From 468f927e8bd0d1eddd7cc0a06cfe15f7d51d833e Mon Sep 17 00:00:00 2001 From: moneroexamples Date: Fri, 28 Apr 2017 13:45:30 +0800 Subject: [PATCH] gitignore modefied https://github.com/moneroexamples/onion-monero-blockchain-explorer/pull/45 --- .gitignore | 1 + CMakeLists.txt | 16 +- README.md | 360 +- ext/CMakeLists.txt | 6 +- ext/date/chrono_io.h | 668 --- ext/date/date.h | 4823 ---------------------- ext/date/ios.h | 49 - ext/date/ios.mm | 405 -- ext/date/julian.h | 3046 -------------- ext/date/tz.cpp | 3120 -------------- ext/date/tz.h | 1345 ------ ext/date/tz_private.h | 265 -- ext/mstch/include/mstch/mstch.hpp | 2 +- ext/mstch/src/visitor/render_node.hpp | 6 + ext/vpetrigocaches/cache.hpp | 138 + ext/vpetrigocaches/cache_policy.hpp | 77 + ext/vpetrigocaches/fifo_cache_policy.hpp | 53 + ext/vpetrigocaches/lfu_cache_policy.hpp | 76 + ext/vpetrigocaches/lru_cache_policy.hpp | 63 + main.cpp | 194 +- screenshot/screenshot_01.jpg | Bin 588341 -> 0 bytes src/CMakeLists.txt | 3 +- src/CmdLineOptions.cpp | 18 +- src/MicroCore.cpp | 508 +-- src/mylmdb.h | 755 ---- src/page.h | 2683 +++++++----- src/rpccalls.cpp | 147 + src/rpccalls.h | 161 +- src/templates/checkrawtx.html | 10 +- src/templates/css/style.css | 2 +- src/templates/footer.html | 1 - src/templates/header.html | 27 +- src/templates/index2.html | 30 +- src/templates/mempool.html | 17 +- src/templates/partials/tx_details.html | 161 +- src/tools.cpp | 151 +- src/tools.h | 15 +- 37 files changed, 3302 insertions(+), 16100 deletions(-) delete mode 100644 ext/date/chrono_io.h delete mode 100644 ext/date/date.h delete mode 100644 ext/date/ios.h delete mode 100644 ext/date/ios.mm delete mode 100644 ext/date/julian.h delete mode 100644 ext/date/tz.cpp delete mode 100644 ext/date/tz.h delete mode 100644 ext/date/tz_private.h create mode 100644 ext/vpetrigocaches/cache.hpp create mode 100644 ext/vpetrigocaches/cache_policy.hpp create mode 100644 ext/vpetrigocaches/fifo_cache_policy.hpp create mode 100644 ext/vpetrigocaches/lfu_cache_policy.hpp create mode 100644 ext/vpetrigocaches/lru_cache_policy.hpp delete mode 100644 screenshot/screenshot_01.jpg delete mode 100644 src/mylmdb.h diff --git a/.gitignore b/.gitignore index 3d2c70d..92acc15 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,6 @@ *.user .idea/ *.log +.orig tests/ cmake-build-debug/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 096936d..75e18f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,8 +55,8 @@ find_package(Boost COMPONENTS if(APPLE) - include_directories(/usr/local/opt/openssl/include) - link_directories(/usr/local/opt/openssl/lib) + include_directories(/usr/local/opt/openssl/include) + link_directories(/usr/local/opt/openssl/lib) endif() @@ -116,16 +116,16 @@ set(LIBRARIES ssl) if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT WIN32) - set(LIBRARIES ${LIBRARIES} unwind) + set(LIBRARIES ${LIBRARIES} unwind) endif() if (WIN32) set(LIBRARIES ${LIBRARIES} - wsock32 - ntdll - ws2_32 - Iphlpapi - ) + wsock32 + ntdll + ws2_32 + Iphlpapi + ) else() set(LIBRARIES ${LIBRARIES} dl) endif() diff --git a/README.md b/README.md index 997fa8d..6cbb855 100644 --- a/README.md +++ b/README.md @@ -7,17 +7,16 @@ Currently available Monero blockchain explorer websites have several limitations - track users activates through google analytics, - are closed sourced, - are not available as hidden services, - - provide only basic search capabilities, - do not support Monero testnet + In this example, these limitations are addressed by development of -an Onion Monero Blockchain Explorer. The example not only shows how to use Monero C++ libraries, - but also demonstrates how to use: +an Onion Monero Blockchain Explorer. The example not only shows how to use +Monero C++ libraries, but also demonstrates how to use: - - [crow](https://github.com/ipkn/crow) - C++ micro web framework + - [crow](https://github.com/ipkn/crow) - C++ micro web framework - [mstch](https://github.com/no1msd/mstch) - C++ {{mustache}} templates - [json](https://github.com/nlohmann/json) - JSON for Modern C++ - - [date](https://github.com/HowardHinnant/date) - C++ date and time library - [fmt](https://github.com/fmtlib/fmt) - Small, safe and fast string formatting library ## Addresses @@ -25,34 +24,26 @@ an Onion Monero Blockchain Explorer. The example not only shows how to use Moner Tor users: - [http://dvwae436pd7nt4bc.onion](http://dvwae436pd7nt4bc.onion) - + Clearnet versions: - - [http://139.162.32.245:8081/](http://139.162.32.245:8081/) - bleeding edge, no https. - - [https://xmrchain.net/](https://xmrchain.net/) - https enabled. - - [https://monerohash.com/explorer/](https://monerohash.com/explorer/) - nice looking one, https enabled. - - [http://blox.supportxmr.com/](http://blox.supportxmr.com/) - no https. - - [https://explorer.xmr.my/](https://explorer.xmr.my/) - https enabled. + + - [http://139.162.32.245:8081/](http://139.162.32.245:8081/) - bleeding edge version, no https. + - [https://explorer.xmr.my/](https://explorer.xmr.my/) - https enabled, up to date, but sometimes down. + - [https://xmrchain.net/](https://xmrchain.net/) - https enabled, most popular and very stable. + - [https://monerohash.com/explorer/](https://monerohash.com/explorer/) - nice looking one, https enabled. + - [http://explore.MoneroWorld.com](http://explore.moneroworld.com) - same as the second one. Clearnet testnet Monero version: - - [http://139.162.32.245:8082/](http://139.162.32.245:8082/) - bleeding edge, no https. + - [http://139.162.32.245:8082/](http://139.162.32.245:8082/) - bleeding edge version, no https. - [https://testnet.xmrchain.com/](https://testnet.xmrchain.com/) - https enabled. - -i2p users (main Monero network) - down for now: - - - [http://monerotools.i2p](http://monerotools.i2p) - -Clearnet testnet priority nodes: - - 23.228.193.90 - /opt/monero/monerod --testnet --add-priority-node 23.228.193.90 - - 62.210.104.109 - /opt/monero/monerod --testnet --add-priority-node 62.210.104.109 +i2p users (main Monero network) - down for now: -Monero tor nodes: + - [http://monerotools.i2p](http://monerotools.i2p) - - 7kome2dwgre4wll6.onion - `/opt/monero/monero-wallet-cli --daemon-host 7kome2dwgre4wll6.onion` - - o6nvntbo3qsn36dm.onion - `/opt/monero/monero-wallet-cli --daemon-host o6nvntbo3qsn36dm.onion` - + ## Onion Monero Blockchain Explorer features The key features of the Onion Monero Blockchain Explorer are: @@ -71,9 +62,10 @@ The key features of the Onion Monero Blockchain Explorer are: - the only explorer showing number of amount output indices, - the only explorer supporting Monero testnet network, - the only explorer providing tx checker and pusher for online pushing of transactions, - - the only explorer allowing to inspect encrypted key images file and output files. - the only explorer able to estimate possible spendings based on address and viewkey. +## Prerequisite + ## Compilation on Ubuntu 16.04 ##### Compile latest Monero @@ -100,13 +92,12 @@ make ``` ##### Compile and run the explorer -Once the Monero is compiled and setup, the explorer can be downloaded and compiled +Once the Monero is compiles, the explorer can be downloaded and compiled as follows: ```bash # go to home folder if still in ~/monero cd ~ - # download the source code git clone https://github.com/moneroexamples/onion-monero-blockchain-explorer.git @@ -135,7 +126,6 @@ To run it: By default it will look for blockchain in its default location i.e., `~/.bitmonero/lmdb`. You can use `--bc-path` option if its in different location. - Example output: ```bash @@ -154,14 +144,30 @@ xmrblocks, start Onion Monero Blockchain Explorer: -h [ --help ] [=arg(=1)] (=0) produce help message -t [ --testnet ] [=arg(=1)] (=0) use testnet blockchain --enable-pusher [=arg(=1)] (=0) enable pushing signed tx + --enable-mixin-details [=arg(=1)] (=0) + enable mixin details for key images, + e.g., timescale, mixin of mixins, in tx + context --enable-key-image-checker [=arg(=1)] (=0) enable key images file checker --enable-output-key-checker [=arg(=1)] (=0) enable outputs key file checker + --enable-mempool-cache arg (=1) enable caching txs in the mempool + --enable-json-api arg (=1) enable JSON REST api + --enable-tx-cache [=arg(=1)] (=0) enable caching of tx details + --show-cache-times [=arg(=1)] (=0) show times of getting data from cache + vs no cache + --enable-block-cache [=arg(=1)] (=0) enable caching of block details --enable-autorefresh-option [=arg(=1)] (=0) enable users to have the index page on autorefresh -p [ --port ] arg (=8081) default port + --testnet-url arg you can specifiy testnet url, if you + run it on mainet. link will show on + front page to testnet explorer + --mainnet-url arg you can specifiy mainnet url, if you + run it on testnet. link will show on + front page to mainnet explorer --no-blocks-on-index arg (=10) number of last blocks to be shown on index page -b [ --bc-path ] arg path to lmdb blockchain @@ -196,27 +202,301 @@ Note: Because we generated our own certificate, modern browsers will complain about it as they cant verify the signatures against any third party. So probably for any practical use need to have properly issued ssl certificates. -## Enable transaction pusher +## JSON API -By default, the tx pusher is disabled. The pushing will not work, but tx checking and inspecting will. +The explorer has JSON api. For the API, it uses conventions defined by [JSend](https://labs.omniti.com/labs/jsend). -To enable pushing the txs, use flag `--enable-pusher`, e.g.: +#### api/transaction/ ```bash -./xmrblocks --enable-pusher +curl -w "\n" -X GET "http://139.162.32.245:8081/api/transaction/6093260dbe79fd6277694d14789dc8718f1bd54457df8bab338c2efa3bb0f03d" ``` - -Note: There has been a number of issues with compatibility of tx's binary data between different Monero versions -and operating systems. Unless you are using latest development version of Monero and the explorer has been compiled -against the lastest version, pushing and checking unsigined and signed tx data - might not work due to incompatibilities in binary data. -## Example screenshot +```json +{ + "data": { + "block_height": 1268252, + "coinbase": 0, + "confirmations": 1, + "fee": 12517785574, + "inputs": [ + { + "amount": 0, + "key_image": "67838fd0ffd79f13e735830d3ec60412aed59e53e1f997feb6f73d088b949611" + } + ], + "outputs": [ + { + "amount": 0, + "public_key": "525779873776e4a42f517fd79b72e7c31c3ba03e730fc32287f6414fb702c1d7" + }, + { + "amount": 0, + "public_key": "e25f00fceb77af841d780b68647618812695b4ca6ebe338faba6e077f758ac30" + } + ], + "rct_type": 1, + "size": 13323000000000000, + "timestamp": 1489753456, + "timestamp_utc": "2017-03-17 12:24:16", + "tx_hash": "6093260dbe79fd6277694d14789dc8718f1bd54457df8bab338c2efa3bb0f03d", + "version": 2 + }, + "status": "success" +} +``` + +#### api/transactions + +Transactions in last 25 blocks + + +```bash +curl -w "\n" -X GET "http://139.162.32.245:8081/api/transactions" +``` + +Partial results shown: + +```json +{ + "data": { + "blocks": [ + { + "age": "33:16:49:53", + "height": 1268252, + "size": 105390000000000000, + "timestamp": 1489753456, + "timestamp_utc": "2017-03-17 12:24:16", + "txs": [ + { + "coinbase": true, + "mixin": 0, + "outputs": 8491554678365, + "rct_type": 0, + "tx_fee": 0, + "tx_hash": "7c4286f64544568265bb5418df84ae69afaa3567749210e46f8340c247f4803f", + "tx_size": 151000000000000, + "tx_version": 2 + }, + { + "coinbase": false, + "mixin": 5, + "outputs": 0, + "rct_type": 2, + "tx_fee": 17882516700, + "tx_hash": "2bfbccb918ee5f050808dd040ce03943b7315b81788e9cdee59cf86b557ba48c", + "tx_size": 19586000000000000, + "tx_version": 2 + } + ] + } + ], + "limit": 25, + "page": 0 + }, + "status": "success" +} +``` + +#### api/transactions?page=&limit= + + +```bash +curl -w "\n" -X GET "http://139.162.32.245:8081/api/transactions?page=2&limit=10" +``` + +Result analogical to the one above. + +#### api/block/ + -![Onion Monero Blockchain Explorer](https://raw.githubusercontent.com/moneroexamples/onion-monero-blockchain-explorer/master/screenshot/screenshot_01.jpg) +```bash +curl -w "\n" -X GET "http://139.162.32.245:8081/api/block/1293257" +``` + +Partial results shown: + +```json +{ + "data": { + "block_height": 1293257, + "block_reward": 0, + "current_height": 1293264, + "hash": "9ef6bb8f9b8bd253fc6390e5c2cdc45c8ee99fad16447437108bf301fe6bd6e1", + "size": 141244, + "timestamp": 1492761974, + "timestamp_utc": "2017-04-21 08:06:14", + "txs": [ + { + "coinbase": true, + "extra": "018ae9560eb85d5ebd22d3beaed55c21d469eab430c5e3cac61b3fe2f5ad156770020800000001a9030800", + "mixin": 0, + "payment_id": "", + "payment_id8": "", + "rct_type": 0, + "tx_fee": 0, + "tx_hash": "3ff71b65bec34c9261e01a856e6a03594cf0472acf6b77db3f17ebd18eaa30bf", + "tx_size": 95, + "tx_version": 2, + "xmr_inputs": 0, + "xmr_outputs": 8025365394426 + } + ] + }, + "status": "success" +} +``` + + +#### api/mempool + + +```bash +curl -w "\n" -X GET "http://139.162.32.245:8081/api/mempool" +``` + +Partial results shown: + +```json +{ + "data": [ + { + "coinbase": false, + "extra": "02210001c32d313b74a859b904079c69dbc04ea6e37eddcf4aeb34e9400cc12831da5401b34082a9ff7476fe29a19fa6a1735a9c59db226b9ddcf715928aa71625b13062", + "mixin": 7, + "payment_id": "01c32d313b74a859b904079c69dbc04ea6e37eddcf4aeb34e9400cc12831da54", + "payment_id8": "", + "rct_type": 1, + "timestamp": 1492763220, + "timestamp_utc": "2017-04-21 08:27:00", + "tx_fee": 4083040000, + "tx_hash": "6751e0029558fdc4ab4528896529e32b2864c6ad43c5d8838c8ebe156ada0514", + "tx_size": 13224, + "tx_version": 2, + "xmr_inputs": 0, + "xmr_outputs": 0 + } + ], + "status": "success" +} +``` + +#### api/search/ + +```bash +curl -w "\n" -X GET "http://139.162.32.245:8081/api/search/1293669" +``` +Partial results shown: + +```json +{ + "data": { + "block_height": 1293669, + "current_height": 1293670, + "hash": "5d55b8fabf85b0b4c959d66ad509eb92ddfe5c2b0e84e1760abcb090195c1913", + "size": 118026, + "timestamp": 1492815321, + "timestamp_utc": "2017-04-21 22:55:21", + "title": "block", + "txs": [ + { + "coinbase": true, + "extra": "01cb7fda09033a5fa06dc601b9295ef3790397cf3c645e958e34cf7ab699d2f5230208000000027f030200", + "mixin": 0, + "payment_id": "", + "payment_id8": "", + "rct_type": 0, + "tx_fee": 0, + "tx_hash": "479ba432f5c88736b438dd4446a11a13046a752d469f7828151f5c5b86be4e9a", + "tx_size": 95, + "tx_version": 2, + "xmr_inputs": 0, + "xmr_outputs": 7992697599717 + } + ] + }, + "status": "success" +} +``` + +#### api/outputs?txhash=&address=
&viewkey=&txprove=<0|1> + +For `txprove=0` we check which outputs belong to given address and corresponding viewkey. +For `txprove=1` we use to prove to the recipient that we sent them founds. +For this, we use recipient's address and our tx private key as a viewkey value, + i.e., `viewkey=` + +Checking outputs: + +```bash +# we use here official Monero project's donation address as an example +curl -w "\n" -X GET "http://139.162.32.245:8081/api/outputs?txhash=17049bc5f2d9fbca1ce8dae443bbbbed2fc02f1ee003ffdd0571996905faa831&address=44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A&viewkey=f359631075708155cc3d92a32b75a7d02a5dcf27756707b47a2b31b21c389501&txprove=0" +``` + +```json +{ + "data": { + "address": "42f18fc61586554095b0799b5c4b6f00cdeb26a93b20540d366932c6001617b75db35109fbba7d5f275fef4b9c49e0cc1c84b219ec6ff652fda54f89f7f63c88", + "outputs": [ + { + "amount": 34980000000000, + "match": true, + "output_idx": 0, + "output_pubkey": "35d7200229e725c2bce0da3a2f20ef0720d242ecf88bfcb71eff2025c2501fdb" + }, + { + "amount": 0, + "match": false, + "output_idx": 1, + "output_pubkey": "44efccab9f9b42e83c12da7988785d6c4eb3ec6e7aa2ae1234e2f0f7cb9ed6dd" + } + ], + "tx_hash": "17049bc5f2d9fbca1ce8dae443bbbbed2fc02f1ee003ffdd0571996905faa831", + "tx_prove": false, + "viewkey": "f359631075708155cc3d92a32b75a7d02a5dcf27756707b47a2b31b21c389501" + }, + "status": "success" +} +``` + +Proving transfer: + +We use recipient's address (i.e. not our address from which we sent xmr to recipient). +For the viewkey, we use `tx_private_key` (although the GET variable is still called `viewkey`) that we obtained by sending this txs. + +```bash +# this is for testnet transaction +curl -w "\n" -X GET "http://139.162.32.245:8082/api/outputs?txhash=94782a8c0aa8d8768afa0c040ef0544b63eb5148ca971a024ac402cad313d3b3&address=9wUf8UcPUtb2huK7RphBw5PFCyKosKxqtGxbcKBDnzTCPrdNfJjLjtuht87zhTgsffCB21qmjxjj18Pw7cBnRctcKHrUB7N&viewkey=e94b5bfc599d2f741d6f07e3ab2a83f915e96fb374dfb2cd3dbe730e34ecb40b&txprove=1" +``` + +```json +{ + "data": { + "address": "71bef5945b70bc0a31dbbe6cd0bd5884fe694bbfd18fff5f68f709438554fb88a51b1291e378e2f46a0155108782c242cc1be78af229242c36d4f4d1c4f72da2", + "outputs": [ + { + "amount": 1000000000000, + "match": true, + "output_idx": 0, + "output_pubkey": "c1bf4dd020b5f0ab70bd672d2f9e800ea7b8ab108b080825c1d6cfc0b7f7ee00" + }, + { + "amount": 0, + "match": false, + "output_idx": 1, + "output_pubkey": "8c61fae6ada2a103565dfdd307c7145b2479ddb1dab1eaadfa6c34db65d189d5" + } + ], + "tx_hash": "94782a8c0aa8d8768afa0c040ef0544b63eb5148ca971a024ac402cad313d3b3", + "tx_prove": true, + "viewkey": "e94b5bfc599d2f741d6f07e3ab2a83f915e96fb374dfb2cd3dbe730e34ecb40b" + }, + "status": "success" +} +``` -## Other Monero examples +## Other monero examples Other examples can be found on [github](https://github.com/moneroexamples?tab=repositories). Please know that some of the examples/repositories are not diff --git a/ext/CMakeLists.txt b/ext/CMakeLists.txt index d2baf80..282bc15 100644 --- a/ext/CMakeLists.txt +++ b/ext/CMakeLists.txt @@ -7,13 +7,11 @@ project(myext) set(SOURCE_HEADERS minicsv.h - format.h - ) + fmt/format.h) set(SOURCE_FILES fmt/format.cc - fmt/ostream.cc - date/tz.cpp) + fmt/ostream.cc) # make static library called libmyxrm # that we are going to link to diff --git a/ext/date/chrono_io.h b/ext/date/chrono_io.h deleted file mode 100644 index d66a4f2..0000000 --- a/ext/date/chrono_io.h +++ /dev/null @@ -1,668 +0,0 @@ -#ifndef CHRONO_IO_H -#define CHRONO_IO_H - -// The MIT License (MIT) -// -// Copyright (c) 2016 Howard Hinnant -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// Our apologies. When the previous paragraph was written, lowercase had not yet -// been invented (that woud involve another several millennia of evolution). -// We did not mean to shout. - -#include -#include -#include -#include -#include -#include -#include - -namespace date -{ - -namespace detail -{ - -#if __cplusplus >= 201402 - -template -class string_literal -{ - CharT p_[N]; - -public: - using const_iterator = const CharT*; - - string_literal(string_literal const&) = default; - string_literal& operator=(string_literal const&) = delete; - - template > - constexpr string_literal(CharT c) noexcept - : p_{c} - { - } - - constexpr string_literal(const CharT(&a)[N]) noexcept - : p_{} - { - for (std::size_t i = 0; i < N; ++i) - p_[i] = a[i]; - } - - template > - constexpr string_literal(const char(&a)[N]) noexcept - : p_{} - { - for (std::size_t i = 0; i < N; ++i) - p_[i] = a[i]; - } - - template {}>> - constexpr string_literal(string_literal const& a) noexcept - : p_{} - { - for (std::size_t i = 0; i < N; ++i) - p_[i] = a[i]; - } - - template > - constexpr string_literal(const string_literal& x, - const string_literal& y) noexcept - : p_{} - { - std::size_t i = 0; - for (; i < N1-1; ++i) - p_[i] = x[i]; - for (std::size_t j = 0; j < N2; ++j, ++i) - p_[i] = y[j]; - } - - constexpr const CharT* data() const noexcept {return p_;} - constexpr std::size_t size() const noexcept {return N-1;} - - constexpr const_iterator begin() const noexcept {return p_;} - constexpr const_iterator end() const noexcept {return p_ + N-1;} - - constexpr CharT const& operator[](std::size_t n) const noexcept - { - return p_[n]; - } - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const string_literal& s) - { - return os << s.p_; - } -}; - -template -constexpr -inline -string_literal, - N1 + N2 - 1> -operator+(const string_literal& x, const string_literal& y) noexcept -{ - using CharT = std::conditional_t; - return string_literal{string_literal{x}, - string_literal{y}}; -} - -template -constexpr -inline -string_literal -msl(const CharT(&a)[N]) noexcept -{ - return string_literal{a}; -} - -template {} || - std::is_same{} || - std::is_same{} || - std::is_same{}>> -constexpr -inline -string_literal -msl(CharT c) noexcept -{ - return string_literal{c}; -} - -constexpr -std::size_t -to_string_len(std::intmax_t i) -{ - std::size_t r = 0; - do - { - i /= 10; - ++r; - } while (i > 0); - return r; -} - -template -constexpr -inline -std::enable_if_t -< - N < 10, - string_literal -> -msl() noexcept -{ - return msl(char(N % 10 + '0')); -} - -template -constexpr -inline -std::enable_if_t -< - 10 <= N, - string_literal -> -msl() noexcept -{ - return msl() + msl(char(N % 10 + '0')); -} - -template -constexpr -inline -std::enable_if_t -< - std::ratio::type::den != 1, - string_literal::type::num) + - to_string_len(std::ratio::type::den) + 4> -> -msl(std::ratio) noexcept -{ - using R = typename std::ratio::type; - return msl(CharT{'['}) + msl() + msl(CharT{'/'}) + - msl() + msl(CharT{']'}); -} - -template -constexpr -inline -std::enable_if_t -< - std::ratio::type::den == 1, - string_literal::type::num) + 3> -> -msl(std::ratio) noexcept -{ - using R = typename std::ratio::type; - return msl(CharT{'['}) + msl() + msl(CharT{']'}); -} - -template -constexpr -inline -auto -msl(std::atto) noexcept -{ - return msl(CharT{'a'}); -} - -template -constexpr -inline -auto -msl(std::femto) noexcept -{ - return msl(CharT{'f'}); -} - -template -constexpr -inline -auto -msl(std::pico) noexcept -{ - return msl(CharT{'p'}); -} - -template -constexpr -inline -auto -msl(std::nano) noexcept -{ - return msl(CharT{'n'}); -} - -template -constexpr -inline -std::enable_if_t -< - std::is_same{}, - string_literal -> -msl(std::micro) noexcept -{ - return string_literal{"\xC2\xB5"}; -} - -template -constexpr -inline -std::enable_if_t -< - !std::is_same{}, - string_literal -> -msl(std::micro) noexcept -{ - return string_literal{CharT{static_cast('\xB5')}}; -} - -template -constexpr -inline -auto -msl(std::milli) noexcept -{ - return msl(CharT{'m'}); -} - -template -constexpr -inline -auto -msl(std::centi) noexcept -{ - return msl(CharT{'c'}); -} - -template -constexpr -inline -auto -msl(std::deci) noexcept -{ - return msl(CharT{'d'}); -} - -template -constexpr -inline -auto -msl(std::deca) noexcept -{ - return string_literal{"da"}; -} - -template -constexpr -inline -auto -msl(std::hecto) noexcept -{ - return msl(CharT{'h'}); -} - -template -constexpr -inline -auto -msl(std::kilo) noexcept -{ - return msl(CharT{'k'}); -} - -template -constexpr -inline -auto -msl(std::mega) noexcept -{ - return msl(CharT{'M'}); -} - -template -constexpr -inline -auto -msl(std::giga) noexcept -{ - return msl(CharT{'G'}); -} - -template -constexpr -inline -auto -msl(std::tera) noexcept -{ - return msl(CharT{'T'}); -} - -template -constexpr -inline -auto -msl(std::peta) noexcept -{ - return msl(CharT{'P'}); -} - -template -constexpr -inline -auto -msl(std::exa) noexcept -{ - return msl(CharT{'E'}); -} - -template -constexpr -auto -get_units(Period p) -{ - return msl(p) + string_literal{"s"}; -} - -template -constexpr -auto -get_units(std::ratio<1>) -{ - return string_literal{"s"}; -} - -template -constexpr -auto -get_units(std::ratio<60>) -{ - return string_literal{"min"}; -} - -template -constexpr -auto -get_units(std::ratio<3600>) -{ - return string_literal{"h"}; -} - -#else // __cplusplus < 201402 - -inline -std::string -to_string(std::uint64_t x) -{ - return std::to_string(x); -} - -template -std::basic_string -to_string(std::uint64_t x) -{ - auto y = std::to_string(x); - return std::basic_string(y.begin(), y.end()); -} - -template -constexpr -inline -typename std::enable_if -< - std::ratio::type::den != 1, - std::basic_string ->::type -msl(std::ratio) noexcept -{ - using R = typename std::ratio::type; - return std::basic_string(1, '[') + to_string(R::num) + CharT{'/'} + - to_string(R::den) + CharT{']'}; -} - -template -constexpr -inline -typename std::enable_if -< - std::ratio::type::den == 1, - std::basic_string ->::type -msl(std::ratio) noexcept -{ - using R = typename std::ratio::type; - return std::basic_string(1, '[') + to_string(R::num) + CharT{']'}; -} - -template -constexpr -inline -std::basic_string -msl(std::atto) noexcept -{ - return {'a'}; -} - -template -constexpr -inline -std::basic_string -msl(std::femto) noexcept -{ - return {'f'}; -} - -template -constexpr -inline -std::basic_string -msl(std::pico) noexcept -{ - return {'p'}; -} - -template -constexpr -inline -std::basic_string -msl(std::nano) noexcept -{ - return {'n'}; -} - -template -constexpr -inline -typename std::enable_if -< - std::is_same::value, - std::string ->::type -msl(std::micro) noexcept -{ - return "\xC2\xB5"; -} - -template -constexpr -inline -typename std::enable_if -< - !std::is_same::value, - std::basic_string ->::type -msl(std::micro) noexcept -{ - return {CharT(static_cast('\xB5'))}; -} - -template -constexpr -inline -std::basic_string -msl(std::milli) noexcept -{ - return {'m'}; -} - -template -constexpr -inline -std::basic_string -msl(std::centi) noexcept -{ - return {'c'}; -} - -template -constexpr -inline -std::basic_string -msl(std::deci) noexcept -{ - return {'d'}; -} - -template -constexpr -inline -std::basic_string -msl(std::deca) noexcept -{ - return {'d', 'a'}; -} - -template -constexpr -inline -std::basic_string -msl(std::hecto) noexcept -{ - return {'h'}; -} - -template -constexpr -inline -std::basic_string -msl(std::kilo) noexcept -{ - return {'k'}; -} - -template -constexpr -inline -std::basic_string -msl(std::mega) noexcept -{ - return {'M'}; -} - -template -constexpr -inline -std::basic_string -msl(std::giga) noexcept -{ - return {'G'}; -} - -template -constexpr -inline -std::basic_string -msl(std::tera) noexcept -{ - return {'T'}; -} - -template -constexpr -inline -std::basic_string -msl(std::peta) noexcept -{ - return {'P'}; -} - -template -constexpr -inline -std::basic_string -msl(std::exa) noexcept -{ - return {'E'}; -} - -template -std::basic_string -get_units(Period p) -{ - return msl(p) + CharT{'s'}; -} - -template -std::basic_string -get_units(std::ratio<1>) -{ - return {'s'}; -} - -template -std::basic_string -get_units(std::ratio<60>) -{ - return {'m', 'i', 'n'}; -} - -template -std::basic_string -get_units(std::ratio<3600>) -{ - return {'h'}; -} - -#endif // __cplusplus >= 201402 - -} // namespace detail - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, - const std::chrono::duration& d) -{ - using namespace std::chrono; - return os << d.count() - << detail::get_units(typename Period::type{}); -} - -} // namespace date - -#endif // CHRONO_IO_H diff --git a/ext/date/date.h b/ext/date/date.h deleted file mode 100644 index 5ff8f01..0000000 --- a/ext/date/date.h +++ /dev/null @@ -1,4823 +0,0 @@ -#ifndef DATE_H -#define DATE_H - -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// Our apologies. When the previous paragraph was written, lowercase had not yet -// been invented (that woud involve another several millennia of evolution). -// We did not mean to shout. - -#include -#include -#if !(__cplusplus >= 201402) -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace date -{ - -//---------------+ -// Configuration | -//---------------+ - -// MSVC's constexpr support is still a WIP, even in VS2015. -// Fall back to a lesser mode to support it. -// TODO: Remove this or retest later once MSVC's constexpr improves. -#if defined(_MSC_VER) && ! defined(__clang__) -// MS cl compiler. -# define CONSTDATA const -# define CONSTCD11 -# define CONSTCD14 -# define NOEXCEPT _NOEXCEPT -#elif __cplusplus >= 201402 -// C++14 -# define CONSTDATA constexpr -# define CONSTCD11 constexpr -# define CONSTCD14 constexpr -# define NOEXCEPT noexcept -#else -// C++11 -# define CONSTDATA constexpr -# define CONSTCD11 constexpr -# define CONSTCD14 -# define NOEXCEPT noexcept -#endif - -//-----------+ -// Interface | -//-----------+ - -// durations - -using days = std::chrono::duration - , std::chrono::hours::period>>; - -using weeks = std::chrono::duration - , days::period>>; - -using years = std::chrono::duration - , days::period>>; - -using months = std::chrono::duration - >>; - -// time_point - -template - using sys_time = std::chrono::time_point; - -using sys_days = sys_time; -using sys_seconds = sys_time; - -struct local_t {}; - -template - using local_time = std::chrono::time_point; - -using local_seconds = local_time; -using local_days = local_time; - -// types - -struct last_spec -{ - explicit last_spec() = default; -}; - -class day; -class month; -class year; - -class weekday; -class weekday_indexed; -class weekday_last; - -class month_day; -class month_day_last; -class month_weekday; -class month_weekday_last; - -class year_month; - -class year_month_day; -class year_month_day_last; -class year_month_weekday; -class year_month_weekday_last; - -// date composition operators - -CONSTCD11 year_month operator/(const year& y, const month& m) NOEXCEPT; -CONSTCD11 year_month operator/(const year& y, int m) NOEXCEPT; - -CONSTCD11 month_day operator/(const day& d, const month& m) NOEXCEPT; -CONSTCD11 month_day operator/(const day& d, int m) NOEXCEPT; -CONSTCD11 month_day operator/(const month& m, const day& d) NOEXCEPT; -CONSTCD11 month_day operator/(const month& m, int d) NOEXCEPT; -CONSTCD11 month_day operator/(int m, const day& d) NOEXCEPT; - -CONSTCD11 month_day_last operator/(const month& m, last_spec) NOEXCEPT; -CONSTCD11 month_day_last operator/(int m, last_spec) NOEXCEPT; -CONSTCD11 month_day_last operator/(last_spec, const month& m) NOEXCEPT; -CONSTCD11 month_day_last operator/(last_spec, int m) NOEXCEPT; - -CONSTCD11 month_weekday operator/(const month& m, const weekday_indexed& wdi) NOEXCEPT; -CONSTCD11 month_weekday operator/(int m, const weekday_indexed& wdi) NOEXCEPT; -CONSTCD11 month_weekday operator/(const weekday_indexed& wdi, const month& m) NOEXCEPT; -CONSTCD11 month_weekday operator/(const weekday_indexed& wdi, int m) NOEXCEPT; - -CONSTCD11 month_weekday_last operator/(const month& m, const weekday_last& wdl) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(int m, const weekday_last& wdl) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(const weekday_last& wdl, const month& m) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(const weekday_last& wdl, int m) NOEXCEPT; - -CONSTCD11 year_month_day operator/(const year_month& ym, const day& d) NOEXCEPT; -CONSTCD11 year_month_day operator/(const year_month& ym, int d) NOEXCEPT; -CONSTCD11 year_month_day operator/(const year& y, const month_day& md) NOEXCEPT; -CONSTCD11 year_month_day operator/(int y, const month_day& md) NOEXCEPT; -CONSTCD11 year_month_day operator/(const month_day& md, const year& y) NOEXCEPT; -CONSTCD11 year_month_day operator/(const month_day& md, int y) NOEXCEPT; - -CONSTCD11 - year_month_day_last operator/(const year_month& ym, last_spec) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(const year& y, const month_day_last& mdl) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(int y, const month_day_last& mdl) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(const month_day_last& mdl, const year& y) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(const month_day_last& mdl, int y) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const year_month& ym, const weekday_indexed& wdi) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const year& y, const month_weekday& mwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(int y, const month_weekday& mwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const month_weekday& mwd, const year& y) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const month_weekday& mwd, int y) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const year_month& ym, const weekday_last& wdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const year& y, const month_weekday_last& mwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(int y, const month_weekday_last& mwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const month_weekday_last& mwdl, const year& y) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const month_weekday_last& mwdl, int y) NOEXCEPT; - -// Detailed interface - -// day - -class day -{ - unsigned char d_; - -public: - day() = default; - explicit CONSTCD11 day(unsigned d) NOEXCEPT; - - CONSTCD14 day& operator++() NOEXCEPT; - CONSTCD14 day operator++(int) NOEXCEPT; - CONSTCD14 day& operator--() NOEXCEPT; - CONSTCD14 day operator--(int) NOEXCEPT; - - CONSTCD14 day& operator+=(const days& d) NOEXCEPT; - CONSTCD14 day& operator-=(const days& d) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator< (const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator> (const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const day& x, const day& y) NOEXCEPT; - -CONSTCD11 day operator+(const day& x, const days& y) NOEXCEPT; -CONSTCD11 day operator+(const days& x, const day& y) NOEXCEPT; -CONSTCD11 day operator-(const day& x, const days& y) NOEXCEPT; -CONSTCD11 days operator-(const day& x, const day& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const day& d); - -// month - -class month -{ - unsigned char m_; - -public: - month() = default; - explicit CONSTCD11 month(unsigned m) NOEXCEPT; - - CONSTCD14 month& operator++() NOEXCEPT; - CONSTCD14 month operator++(int) NOEXCEPT; - CONSTCD14 month& operator--() NOEXCEPT; - CONSTCD14 month operator--(int) NOEXCEPT; - - CONSTCD14 month& operator+=(const months& m) NOEXCEPT; - CONSTCD14 month& operator-=(const months& m) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator< (const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator> (const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month& x, const month& y) NOEXCEPT; - -CONSTCD14 month operator+(const month& x, const months& y) NOEXCEPT; -CONSTCD14 month operator+(const months& x, const month& y) NOEXCEPT; -CONSTCD14 month operator-(const month& x, const months& y) NOEXCEPT; -CONSTCD14 months operator-(const month& x, const month& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month& m); - -// year - -class year -{ - short y_; - -public: - year() = default; - explicit CONSTCD11 year(int y) NOEXCEPT; - - CONSTCD14 year& operator++() NOEXCEPT; - CONSTCD14 year operator++(int) NOEXCEPT; - CONSTCD14 year& operator--() NOEXCEPT; - CONSTCD14 year operator--(int) NOEXCEPT; - - CONSTCD14 year& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 year operator-() const NOEXCEPT; - CONSTCD11 year operator+() const NOEXCEPT; - - CONSTCD11 bool is_leap() const NOEXCEPT; - - CONSTCD11 explicit operator int() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - - static CONSTCD11 year min() NOEXCEPT; - static CONSTCD11 year max() NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator< (const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator> (const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year& x, const year& y) NOEXCEPT; - -CONSTCD11 year operator+(const year& x, const years& y) NOEXCEPT; -CONSTCD11 year operator+(const years& x, const year& y) NOEXCEPT; -CONSTCD11 year operator-(const year& x, const years& y) NOEXCEPT; -CONSTCD11 years operator-(const year& x, const year& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year& y); - -// weekday - -class weekday -{ - unsigned char wd_; -public: - weekday() = default; - explicit CONSTCD11 weekday(unsigned wd) NOEXCEPT; - explicit weekday(int) = delete; - CONSTCD11 weekday(const sys_days& dp) NOEXCEPT; - CONSTCD11 explicit weekday(const local_days& dp) NOEXCEPT; - - CONSTCD14 weekday& operator++() NOEXCEPT; - CONSTCD14 weekday operator++(int) NOEXCEPT; - CONSTCD14 weekday& operator--() NOEXCEPT; - CONSTCD14 weekday operator--(int) NOEXCEPT; - - CONSTCD14 weekday& operator+=(const days& d) NOEXCEPT; - CONSTCD14 weekday& operator-=(const days& d) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - - CONSTCD11 weekday_indexed operator[](unsigned index) const NOEXCEPT; - CONSTCD11 weekday_last operator[](last_spec) const NOEXCEPT; - -private: - static CONSTCD11 unsigned char weekday_from_days(int z) NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday& x, const weekday& y) NOEXCEPT; - -CONSTCD14 weekday operator+(const weekday& x, const days& y) NOEXCEPT; -CONSTCD14 weekday operator+(const days& x, const weekday& y) NOEXCEPT; -CONSTCD14 weekday operator-(const weekday& x, const days& y) NOEXCEPT; -CONSTCD14 days operator-(const weekday& x, const weekday& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday& wd); - -// weekday_indexed - -class weekday_indexed -{ - unsigned char wd_ : 4; - unsigned char index_ : 4; - -public: - CONSTCD11 weekday_indexed(const date::weekday& wd, unsigned index) NOEXCEPT; - - CONSTCD11 date::weekday weekday() const NOEXCEPT; - CONSTCD11 unsigned index() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_indexed& wdi); - -// weekday_last - -class weekday_last -{ - date::weekday wd_; - -public: - explicit CONSTCD11 weekday_last(const date::weekday& wd) NOEXCEPT; - - CONSTCD11 date::weekday weekday() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday_last& x, const weekday_last& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_last& wdl); - -// year_month - -class year_month -{ - date::year y_; - date::month m_; - -public: - year_month() = default; - CONSTCD11 year_month(const date::year& y, const date::month& m) NOEXCEPT; - - CONSTCD11 date::year year() const NOEXCEPT; - CONSTCD11 date::month month() const NOEXCEPT; - - CONSTCD14 year_month& operator+=(const months& dm) NOEXCEPT; - CONSTCD14 year_month& operator-=(const months& dm) NOEXCEPT; - CONSTCD14 year_month& operator+=(const years& dy) NOEXCEPT; - CONSTCD14 year_month& operator-=(const years& dy) NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator< (const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator> (const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year_month& x, const year_month& y) NOEXCEPT; - -CONSTCD14 year_month operator+(const year_month& ym, const months& dm) NOEXCEPT; -CONSTCD14 year_month operator+(const months& dm, const year_month& ym) NOEXCEPT; -CONSTCD14 year_month operator-(const year_month& ym, const months& dm) NOEXCEPT; - -CONSTCD11 months operator-(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 year_month operator+(const year_month& ym, const years& dy) NOEXCEPT; -CONSTCD11 year_month operator+(const years& dy, const year_month& ym) NOEXCEPT; -CONSTCD11 year_month operator-(const year_month& ym, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month& ym); - -// month_day - -class month_day -{ - date::month m_; - date::day d_; - -public: - month_day() = default; - CONSTCD11 month_day(const date::month& m, const date::day& d) NOEXCEPT; - - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::day day() const NOEXCEPT; - - CONSTCD14 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator< (const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator> (const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month_day& x, const month_day& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day& md); - -// month_day_last - -class month_day_last -{ - date::month m_; - -public: - CONSTCD11 explicit month_day_last(const date::month& m) NOEXCEPT; - - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator< (const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator> (const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day_last& mdl); - -// month_weekday - -class month_weekday -{ - date::month m_; - date::weekday_indexed wdi_; -public: - CONSTCD11 month_weekday(const date::month& m, - const date::weekday_indexed& wdi) NOEXCEPT; - - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::weekday_indexed weekday_indexed() const NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_weekday& x, const month_weekday& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday& mwd); - -// month_weekday_last - -class month_weekday_last -{ - date::month m_; - date::weekday_last wdl_; - -public: - CONSTCD11 month_weekday_last(const date::month& m, - const date::weekday_last& wd) NOEXCEPT; - - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::weekday_last weekday_last() const NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 - bool operator==(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT; -CONSTCD11 - bool operator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday_last& mwdl); - -// class year_month_day - -class year_month_day -{ - date::year y_; - date::month m_; - date::day d_; - -public: - year_month_day() = default; - CONSTCD11 year_month_day(const date::year& y, const date::month& m, - const date::day& d) NOEXCEPT; - CONSTCD14 year_month_day(const year_month_day_last& ymdl) NOEXCEPT; - - CONSTCD14 year_month_day(sys_days dp) NOEXCEPT; - CONSTCD14 explicit year_month_day(local_days dp) NOEXCEPT; - - CONSTCD14 year_month_day& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_day& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 date::year year() const NOEXCEPT; - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::day day() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD14 bool ok() const NOEXCEPT; - -private: - static CONSTCD14 year_month_day from_days(days dp) NOEXCEPT; - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator< (const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator> (const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year_month_day& x, const year_month_day& y) NOEXCEPT; - -CONSTCD14 year_month_day operator+(const year_month_day& ymd, const months& dm) NOEXCEPT; -CONSTCD14 year_month_day operator+(const months& dm, const year_month_day& ymd) NOEXCEPT; -CONSTCD14 year_month_day operator-(const year_month_day& ymd, const months& dm) NOEXCEPT; -CONSTCD11 year_month_day operator+(const year_month_day& ymd, const years& dy) NOEXCEPT; -CONSTCD11 year_month_day operator+(const years& dy, const year_month_day& ymd) NOEXCEPT; -CONSTCD11 year_month_day operator-(const year_month_day& ymd, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day& ymd); - -// year_month_day_last - -class year_month_day_last -{ - date::year y_; - date::month_day_last mdl_; - -public: - CONSTCD11 year_month_day_last(const date::year& y, - const date::month_day_last& mdl) NOEXCEPT; - - CONSTCD14 year_month_day_last& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day_last& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day_last& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_day_last& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 date::year year() const NOEXCEPT; - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::month_day_last month_day_last() const NOEXCEPT; - CONSTCD14 date::day day() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 - bool operator==(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator!=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator< (const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator> (const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator<=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; - -CONSTCD14 -year_month_day_last -operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT; - -CONSTCD14 -year_month_day_last -operator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT; - -CONSTCD11 -year_month_day_last -operator+(const year_month_day_last& ymdl, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_day_last -operator+(const years& dy, const year_month_day_last& ymdl) NOEXCEPT; - -CONSTCD14 -year_month_day_last -operator-(const year_month_day_last& ymdl, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_day_last -operator-(const year_month_day_last& ymdl, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day_last& ymdl); - -// year_month_weekday - -class year_month_weekday -{ - date::year y_; - date::month m_; - date::weekday_indexed wdi_; - -public: - year_month_weekday() = default; - CONSTCD11 year_month_weekday(const date::year& y, const date::month& m, - const date::weekday_indexed& wdi) NOEXCEPT; - CONSTCD14 year_month_weekday(const sys_days& dp) NOEXCEPT; - CONSTCD14 explicit year_month_weekday(const local_days& dp) NOEXCEPT; - - CONSTCD14 year_month_weekday& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_weekday& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 date::year year() const NOEXCEPT; - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::weekday weekday() const NOEXCEPT; - CONSTCD11 unsigned index() const NOEXCEPT; - CONSTCD11 date::weekday_indexed weekday_indexed() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD14 bool ok() const NOEXCEPT; - -private: - static CONSTCD14 year_month_weekday from_days(days dp) NOEXCEPT; - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 - bool operator==(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT; -CONSTCD11 - bool operator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT; - -CONSTCD14 -year_month_weekday -operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT; - -CONSTCD14 -year_month_weekday -operator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator+(const year_month_weekday& ymwd, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator+(const years& dy, const year_month_weekday& ymwd) NOEXCEPT; - -CONSTCD14 -year_month_weekday -operator-(const year_month_weekday& ymwd, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator-(const year_month_weekday& ymwd, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday& ymwdi); - -// year_month_weekday_last - -class year_month_weekday_last -{ - date::year y_; - date::month m_; - date::weekday_last wdl_; - -public: - CONSTCD11 year_month_weekday_last(const date::year& y, const date::month& m, - const date::weekday_last& wdl) NOEXCEPT; - - CONSTCD14 year_month_weekday_last& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 date::year year() const NOEXCEPT; - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::weekday weekday() const NOEXCEPT; - CONSTCD11 date::weekday_last weekday_last() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - -private: - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 -bool -operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT; - -CONSTCD11 -bool -operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT; - -CONSTCD14 -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT; - -CONSTCD14 -year_month_weekday_last -operator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator+(const years& dy, const year_month_weekday_last& ymwdl) NOEXCEPT; - -CONSTCD14 -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday_last& ymwdl); - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -inline namespace literals -{ - -CONSTCD11 date::day operator "" _d(unsigned long long d) NOEXCEPT; -CONSTCD11 date::year operator "" _y(unsigned long long y) NOEXCEPT; - -// CONSTDATA date::month jan{1}; -// CONSTDATA date::month feb{2}; -// CONSTDATA date::month mar{3}; -// CONSTDATA date::month apr{4}; -// CONSTDATA date::month may{5}; -// CONSTDATA date::month jun{6}; -// CONSTDATA date::month jul{7}; -// CONSTDATA date::month aug{8}; -// CONSTDATA date::month sep{9}; -// CONSTDATA date::month oct{10}; -// CONSTDATA date::month nov{11}; -// CONSTDATA date::month dec{12}; -// -// CONSTDATA date::weekday sun{0u}; -// CONSTDATA date::weekday mon{1u}; -// CONSTDATA date::weekday tue{2u}; -// CONSTDATA date::weekday wed{3u}; -// CONSTDATA date::weekday thu{4u}; -// CONSTDATA date::weekday fri{5u}; -// CONSTDATA date::weekday sat{6u}; - -} // inline namespace literals -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - -//----------------+ -// Implementation | -//----------------+ - -// utilities -namespace detail { - -template> -class save_stream -{ - std::basic_ostream& os_; - CharT fill_; - std::ios::fmtflags flags_; - std::locale loc_; - -public: - ~save_stream() - { - os_.fill(fill_); - os_.flags(flags_); - os_.imbue(loc_); - } - - save_stream(const save_stream&) = delete; - save_stream& operator=(const save_stream&) = delete; - - explicit save_stream(std::basic_ostream& os) - : os_(os) - , fill_(os.fill()) - , flags_(os.flags()) - , loc_(os.getloc()) - {} -}; - -#ifdef __GNUC__ -// GCC complains about __int128 with -pedantic or -pedantic-errors -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" -#endif - -template -struct choose_trunc_type -{ - static const int digits = std::numeric_limits::digits; - using type = typename std::conditional - < - digits < 32, - std::int32_t, - typename std::conditional - < - digits < 64, - std::int64_t, -#ifdef __SIZEOF_INT128__ - __int128 -#else - std::int64_t -#endif - >::type - >::type; -}; - -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - -template -CONSTCD11 -inline -typename std::enable_if -< - !std::chrono::treat_as_floating_point::value, - T ->::type -trunc(T t) NOEXCEPT -{ - return t; -} - -template -CONSTCD14 -inline -typename std::enable_if -< - std::chrono::treat_as_floating_point::value, - T ->::type -trunc(T t) NOEXCEPT -{ - using namespace std; - using I = typename choose_trunc_type::type; - CONSTDATA auto digits = numeric_limits::digits; - static_assert(digits < numeric_limits::digits, ""); - CONSTDATA auto max = I{1} << (digits-1); - CONSTDATA auto min = -max; - const auto negative = t < T{0}; - if (min <= t && t <= max && t != 0 && t == t) - { - t = static_cast(static_cast(t)); - if (t == 0 && negative) - t = -t; - } - return t; -} - -} // detail - -// trunc towards zero -template -CONSTCD11 -inline -To -trunc(const std::chrono::duration& d) -{ - return To{detail::trunc(std::chrono::duration_cast(d).count())}; -} - -#ifndef HAS_CHRONO_ROUNDING -# if defined(_MSC_FULL_VER) && _MSC_FULL_VER >= 190023918 -# define HAS_CHRONO_ROUNDING 1 -# elif defined(__cpp_lib_chrono) && __cplusplus > 201402 && __cpp_lib_chrono >= 201510 -# define HAS_CHRONO_ROUNDING 1 -# elif defined(_LIBCPP_VERSION) && __cplusplus > 201402 && _LIBCPP_VERSION >= 3800 -# define HAS_CHRONO_ROUNDING 1 -# else -# define HAS_CHRONO_ROUNDING 0 -# endif -#endif // HAS_CHRONO_ROUNDING - -#if HAS_CHRONO_ROUNDING == 0 - -// round down -template -CONSTCD14 -inline -To -floor(const std::chrono::duration& d) -{ - auto t = trunc(d); - if (t > d) - return t - To{1}; - return t; -} - -// round to nearest, to even on tie -template -CONSTCD14 -inline -To -round(const std::chrono::duration& d) -{ - auto t0 = floor(d); - auto t1 = t0 + To{1}; - if (t1 == To{0} && t0 < To{0}) - t1 = -t1; - auto diff0 = d - t0; - auto diff1 = t1 - d; - if (diff0 == diff1) - { - if (t0 - trunc(t0/2)*2 == To{0}) - return t0; - return t1; - } - if (diff0 < diff1) - return t0; - return t1; -} - -// round up -template -CONSTCD14 -inline -To -ceil(const std::chrono::duration& d) -{ - auto t = trunc(d); - if (t < d) - return t + To{1}; - return t; -} - -template ::is_signed - >::type> -CONSTCD11 -std::chrono::duration -abs(std::chrono::duration d) -{ - return d >= d.zero() ? d : -d; -} - -// round down -template -CONSTCD11 -inline -std::chrono::time_point -floor(const std::chrono::time_point& tp) -{ - using std::chrono::time_point; - return time_point{floor(tp.time_since_epoch())}; -} - -// round to nearest, to even on tie -template -CONSTCD11 -inline -std::chrono::time_point -round(const std::chrono::time_point& tp) -{ - using std::chrono::time_point; - return time_point{round(tp.time_since_epoch())}; -} - -// round up -template -CONSTCD11 -inline -std::chrono::time_point -ceil(const std::chrono::time_point& tp) -{ - using std::chrono::time_point; - return time_point{ceil(tp.time_since_epoch())}; -} - -#else // HAS_CHRONO_ROUNDING == 1 - -using std::chrono::floor; -using std::chrono::ceil; -using std::chrono::round; -using std::chrono::abs; - -#endif // HAS_CHRONO_ROUNDING - -// trunc towards zero -template -CONSTCD11 -inline -std::chrono::time_point -trunc(const std::chrono::time_point& tp) -{ - using std::chrono::time_point; - return time_point{trunc(tp.time_since_epoch())}; -} - -// day - -CONSTCD11 inline day::day(unsigned d) NOEXCEPT : d_(static_cast(d)) {} -CONSTCD14 inline day& day::operator++() NOEXCEPT {++d_; return *this;} -CONSTCD14 inline day day::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline day& day::operator--() NOEXCEPT {--d_; return *this;} -CONSTCD14 inline day day::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} -CONSTCD14 inline day& day::operator+=(const days& d) NOEXCEPT {*this = *this + d; return *this;} -CONSTCD14 inline day& day::operator-=(const days& d) NOEXCEPT {*this = *this - d; return *this;} -CONSTCD11 inline day::operator unsigned() const NOEXCEPT {return d_;} -CONSTCD11 inline bool day::ok() const NOEXCEPT {return 1 <= d_ && d_ <= 31;} - -CONSTCD11 -inline -bool -operator==(const day& x, const day& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const day& x, const day& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const day& x, const day& y) NOEXCEPT -{ - return static_cast(x) < static_cast(y); -} - -CONSTCD11 -inline -bool -operator>(const day& x, const day& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const day& x, const day& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const day& x, const day& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD11 -inline -days -operator-(const day& x, const day& y) NOEXCEPT -{ - return days{static_cast(static_cast(x) - - static_cast(y))}; -} - -CONSTCD11 -inline -day -operator+(const day& x, const days& y) NOEXCEPT -{ - return day{static_cast(x) + static_cast(y.count())}; -} - -CONSTCD11 -inline -day -operator+(const days& x, const day& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD11 -inline -day -operator-(const day& x, const days& y) NOEXCEPT -{ - return x + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const day& d) -{ - detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << static_cast(d); - return os; -} - -// month - -CONSTCD11 inline month::month(unsigned m) NOEXCEPT : m_(static_cast(m)) {} -CONSTCD14 inline month& month::operator++() NOEXCEPT {if (++m_ == 13) m_ = 1; return *this;} -CONSTCD14 inline month month::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline month& month::operator--() NOEXCEPT {if (--m_ == 0) m_ = 12; return *this;} -CONSTCD14 inline month month::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} - -CONSTCD14 -inline -month& -month::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -month& -month::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD11 inline month::operator unsigned() const NOEXCEPT {return m_;} -CONSTCD11 inline bool month::ok() const NOEXCEPT {return 1 <= m_ && m_ <= 12;} - -CONSTCD11 -inline -bool -operator==(const month& x, const month& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const month& x, const month& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const month& x, const month& y) NOEXCEPT -{ - return static_cast(x) < static_cast(y); -} - -CONSTCD11 -inline -bool -operator>(const month& x, const month& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const month& x, const month& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const month& x, const month& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD14 -inline -months -operator-(const month& x, const month& y) NOEXCEPT -{ - auto const d = static_cast(x) - static_cast(y); - return months(d <= 11 ? d : d + 12); -} - -CONSTCD14 -inline -month -operator+(const month& x, const months& y) NOEXCEPT -{ - auto const mu = static_cast(static_cast(x)) - 1 + y.count(); - auto const yr = (mu >= 0 ? mu : mu-11) / 12; - return month{static_cast(mu - yr * 12 + 1)}; -} - -CONSTCD14 -inline -month -operator+(const months& x, const month& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD14 -inline -month -operator-(const month& x, const months& y) NOEXCEPT -{ - return x + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month& m) -{ - switch (static_cast(m)) - { - case 1: - os << "Jan"; - break; - case 2: - os << "Feb"; - break; - case 3: - os << "Mar"; - break; - case 4: - os << "Apr"; - break; - case 5: - os << "May"; - break; - case 6: - os << "Jun"; - break; - case 7: - os << "Jul"; - break; - case 8: - os << "Aug"; - break; - case 9: - os << "Sep"; - break; - case 10: - os << "Oct"; - break; - case 11: - os << "Nov"; - break; - case 12: - os << "Dec"; - break; - default: - os << static_cast(m) << " is not a valid month"; - break; - } - return os; -} - -// year - -CONSTCD11 inline year::year(int y) NOEXCEPT : y_(static_cast(y)) {} -CONSTCD14 inline year& year::operator++() NOEXCEPT {++y_; return *this;} -CONSTCD14 inline year year::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline year& year::operator--() NOEXCEPT {--y_; return *this;} -CONSTCD14 inline year year::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} -CONSTCD14 inline year& year::operator+=(const years& y) NOEXCEPT {*this = *this + y; return *this;} -CONSTCD14 inline year& year::operator-=(const years& y) NOEXCEPT {*this = *this - y; return *this;} -CONSTCD11 inline year year::operator-() const NOEXCEPT {return year{-y_};} -CONSTCD11 inline year year::operator+() const NOEXCEPT {return *this;} - -CONSTCD11 -inline -bool -year::is_leap() const NOEXCEPT -{ - return y_ % 4 == 0 && (y_ % 100 != 0 || y_ % 400 == 0); -} - -CONSTCD11 inline year::operator int() const NOEXCEPT {return y_;} -CONSTCD11 inline bool year::ok() const NOEXCEPT {return true;} - -CONSTCD11 -inline -year -year::min() NOEXCEPT -{ - return year{std::numeric_limits::min()}; -} - -CONSTCD11 -inline -year -year::max() NOEXCEPT -{ - return year{std::numeric_limits::max()}; -} - -CONSTCD11 -inline -bool -operator==(const year& x, const year& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const year& x, const year& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year& x, const year& y) NOEXCEPT -{ - return static_cast(x) < static_cast(y); -} - -CONSTCD11 -inline -bool -operator>(const year& x, const year& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year& x, const year& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year& x, const year& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD11 -inline -years -operator-(const year& x, const year& y) NOEXCEPT -{ - return years{static_cast(x) - static_cast(y)}; -} - -CONSTCD11 -inline -year -operator+(const year& x, const years& y) NOEXCEPT -{ - return year{static_cast(x) + y.count()}; -} - -CONSTCD11 -inline -year -operator+(const years& x, const year& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD11 -inline -year -operator-(const year& x, const years& y) NOEXCEPT -{ - return year{static_cast(x) - y.count()}; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year& y) -{ - detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::internal); - os.width(4 + (y < year{0})); - os << static_cast(y); - return os; -} - -// weekday - -CONSTCD11 -inline -unsigned char -weekday::weekday_from_days(int z) NOEXCEPT -{ - return static_cast(static_cast( - z >= -4 ? (z+4) % 7 : (z+5) % 7 + 6)); -} - -CONSTCD11 -inline -weekday::weekday(unsigned wd) NOEXCEPT - : wd_(static_cast(wd)) - {} - -CONSTCD11 -inline -weekday::weekday(const sys_days& dp) NOEXCEPT - : wd_(weekday_from_days(dp.time_since_epoch().count())) - {} - -CONSTCD11 -inline -weekday::weekday(const local_days& dp) NOEXCEPT - : wd_(weekday_from_days(dp.time_since_epoch().count())) - {} - -CONSTCD14 inline weekday& weekday::operator++() NOEXCEPT {if (++wd_ == 7) wd_ = 0; return *this;} -CONSTCD14 inline weekday weekday::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline weekday& weekday::operator--() NOEXCEPT {if (wd_-- == 0) wd_ = 6; return *this;} -CONSTCD14 inline weekday weekday::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} - -CONSTCD14 -inline -weekday& -weekday::operator+=(const days& d) NOEXCEPT -{ - *this = *this + d; - return *this; -} - -CONSTCD14 -inline -weekday& -weekday::operator-=(const days& d) NOEXCEPT -{ - *this = *this - d; - return *this; -} - -CONSTCD11 -inline -weekday::operator unsigned() const NOEXCEPT -{ - return static_cast(wd_); -} - -CONSTCD11 inline bool weekday::ok() const NOEXCEPT {return wd_ <= 6;} - -CONSTCD11 -inline -bool -operator==(const weekday& x, const weekday& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const weekday& x, const weekday& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD14 -inline -days -operator-(const weekday& x, const weekday& y) NOEXCEPT -{ - auto const diff = static_cast(x) - static_cast(y); - return days{diff <= 6 ? diff : diff + 7}; -} - -CONSTCD14 -inline -weekday -operator+(const weekday& x, const days& y) NOEXCEPT -{ - auto const wdu = static_cast(static_cast(x)) + y.count(); - auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7; - return weekday{static_cast(wdu - wk * 7)}; -} - -CONSTCD14 -inline -weekday -operator+(const days& x, const weekday& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD14 -inline -weekday -operator-(const weekday& x, const days& y) NOEXCEPT -{ - return x + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday& wd) -{ - switch (static_cast(wd)) - { - case 0: - os << "Sun"; - break; - case 1: - os << "Mon"; - break; - case 2: - os << "Tue"; - break; - case 3: - os << "Wed"; - break; - case 4: - os << "Thu"; - break; - case 5: - os << "Fri"; - break; - case 6: - os << "Sat"; - break; - default: - os << static_cast(wd) << " is not a valid weekday"; - break; - } - return os; -} - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -inline namespace literals -{ - -CONSTCD11 -inline -date::day -operator "" _d(unsigned long long d) NOEXCEPT -{ - return date::day{static_cast(d)}; -} - -CONSTCD11 -inline -date::year -operator "" _y(unsigned long long y) NOEXCEPT -{ - return date::year(static_cast(y)); -} -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - -CONSTDATA date::last_spec last{}; - -CONSTDATA date::month jan{1}; -CONSTDATA date::month feb{2}; -CONSTDATA date::month mar{3}; -CONSTDATA date::month apr{4}; -CONSTDATA date::month may{5}; -CONSTDATA date::month jun{6}; -CONSTDATA date::month jul{7}; -CONSTDATA date::month aug{8}; -CONSTDATA date::month sep{9}; -CONSTDATA date::month oct{10}; -CONSTDATA date::month nov{11}; -CONSTDATA date::month dec{12}; - -CONSTDATA date::weekday sun{0u}; -CONSTDATA date::weekday mon{1u}; -CONSTDATA date::weekday tue{2u}; -CONSTDATA date::weekday wed{3u}; -CONSTDATA date::weekday thu{4u}; -CONSTDATA date::weekday fri{5u}; -CONSTDATA date::weekday sat{6u}; - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -} // inline namespace literals -#endif - -// weekday_indexed - -CONSTCD11 -inline -weekday -weekday_indexed::weekday() const NOEXCEPT -{ - return date::weekday{static_cast(wd_)}; -} - -CONSTCD11 inline unsigned weekday_indexed::index() const NOEXCEPT {return index_;} - -CONSTCD11 -inline -bool -weekday_indexed::ok() const NOEXCEPT -{ - return weekday().ok() && 1 <= index_ && index_ <= 5; -} - -CONSTCD11 -inline -weekday_indexed::weekday_indexed(const date::weekday& wd, unsigned index) NOEXCEPT - : wd_(static_cast(static_cast(wd))) - , index_(static_cast(index)) - {} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_indexed& wdi) -{ - return os << wdi.weekday() << '[' << wdi.index() << ']'; -} - -CONSTCD11 -inline -weekday_indexed -weekday::operator[](unsigned index) const NOEXCEPT -{ - return {*this, index}; -} - -CONSTCD11 -inline -bool -operator==(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT -{ - return x.weekday() == y.weekday() && x.index() == y.index(); -} - -CONSTCD11 -inline -bool -operator!=(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT -{ - return !(x == y); -} - -// weekday_last - -CONSTCD11 inline date::weekday weekday_last::weekday() const NOEXCEPT {return wd_;} -CONSTCD11 inline bool weekday_last::ok() const NOEXCEPT {return wd_.ok();} -CONSTCD11 inline weekday_last::weekday_last(const date::weekday& wd) NOEXCEPT : wd_(wd) {} - -CONSTCD11 -inline -bool -operator==(const weekday_last& x, const weekday_last& y) NOEXCEPT -{ - return x.weekday() == y.weekday(); -} - -CONSTCD11 -inline -bool -operator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_last& wdl) -{ - return os << wdl.weekday() << "[last]"; -} - -CONSTCD11 -inline -weekday_last -weekday::operator[](last_spec) const NOEXCEPT -{ - return weekday_last{*this}; -} - -// year_month - -CONSTCD11 -inline -year_month::year_month(const date::year& y, const date::month& m) NOEXCEPT - : y_(y) - , m_(m) - {} - -CONSTCD11 inline year year_month::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month::month() const NOEXCEPT {return m_;} -CONSTCD11 inline bool year_month::ok() const NOEXCEPT {return y_.ok() && m_.ok();} - -CONSTCD14 -inline -year_month& -year_month::operator+=(const months& dm) NOEXCEPT -{ - *this = *this + dm; - return *this; -} - -CONSTCD14 -inline -year_month& -year_month::operator-=(const months& dm) NOEXCEPT -{ - *this = *this - dm; - return *this; -} - -CONSTCD14 -inline -year_month& -year_month::operator+=(const years& dy) NOEXCEPT -{ - *this = *this + dy; - return *this; -} - -CONSTCD14 -inline -year_month& -year_month::operator-=(const years& dy) NOEXCEPT -{ - *this = *this - dy; - return *this; -} - -CONSTCD11 -inline -bool -operator==(const year_month& x, const year_month& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month& x, const year_month& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_month& x, const year_month& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (x.month() < y.month())); -} - -CONSTCD11 -inline -bool -operator>(const year_month& x, const year_month& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_month& x, const year_month& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_month& x, const year_month& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD14 -inline -year_month -operator+(const year_month& ym, const months& dm) NOEXCEPT -{ - auto dmi = static_cast(static_cast(ym.month())) - 1 + dm.count(); - auto dy = (dmi >= 0 ? dmi : dmi-11) / 12; - dmi = dmi - dy * 12 + 1; - return (ym.year() + years(dy)) / month(static_cast(dmi)); -} - -CONSTCD14 -inline -year_month -operator+(const months& dm, const year_month& ym) NOEXCEPT -{ - return ym + dm; -} - -CONSTCD14 -inline -year_month -operator-(const year_month& ym, const months& dm) NOEXCEPT -{ - return ym + -dm; -} - -CONSTCD11 -inline -months -operator-(const year_month& x, const year_month& y) NOEXCEPT -{ - return (x.year() - y.year()) + - months(static_cast(x.month()) - static_cast(y.month())); -} - -CONSTCD11 -inline -year_month -operator+(const year_month& ym, const years& dy) NOEXCEPT -{ - return (ym.year() + dy) / ym.month(); -} - -CONSTCD11 -inline -year_month -operator+(const years& dy, const year_month& ym) NOEXCEPT -{ - return ym + dy; -} - -CONSTCD11 -inline -year_month -operator-(const year_month& ym, const years& dy) NOEXCEPT -{ - return ym + -dy; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month& ym) -{ - return os << ym.year() << '/' << ym.month(); -} - -// month_day - -CONSTCD11 -inline -month_day::month_day(const date::month& m, const date::day& d) NOEXCEPT - : m_(m) - , d_(d) - {} - -CONSTCD11 inline date::month month_day::month() const NOEXCEPT {return m_;} -CONSTCD11 inline date::day month_day::day() const NOEXCEPT {return d_;} - -CONSTCD14 -inline -bool -month_day::ok() const NOEXCEPT -{ - CONSTDATA date::day d[] = - { - date::day(31), date::day(29), date::day(31), - date::day(30), date::day(31), date::day(30), - date::day(31), date::day(31), date::day(30), - date::day(31), date::day(30), date::day(31) - }; - return m_.ok() && date::day{1} <= d_ && d_ <= d[static_cast(m_)-1]; -} - -CONSTCD11 -inline -bool -operator==(const month_day& x, const month_day& y) NOEXCEPT -{ - return x.month() == y.month() && x.day() == y.day(); -} - -CONSTCD11 -inline -bool -operator!=(const month_day& x, const month_day& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const month_day& x, const month_day& y) NOEXCEPT -{ - return x.month() < y.month() ? true - : (x.month() > y.month() ? false - : (x.day() < y.day())); -} - -CONSTCD11 -inline -bool -operator>(const month_day& x, const month_day& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const month_day& x, const month_day& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const month_day& x, const month_day& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day& md) -{ - return os << md.month() << '/' << md.day(); -} - -// month_day_last - -CONSTCD11 inline month month_day_last::month() const NOEXCEPT {return m_;} -CONSTCD11 inline bool month_day_last::ok() const NOEXCEPT {return m_.ok();} -CONSTCD11 inline month_day_last::month_day_last(const date::month& m) NOEXCEPT : m_(m) {} - -CONSTCD11 -inline -bool -operator==(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return x.month() == y.month(); -} - -CONSTCD11 -inline -bool -operator!=(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return x.month() < y.month(); -} - -CONSTCD11 -inline -bool -operator>(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day_last& mdl) -{ - return os << mdl.month() << "/last"; -} - -// month_weekday - -CONSTCD11 -inline -month_weekday::month_weekday(const date::month& m, - const date::weekday_indexed& wdi) NOEXCEPT - : m_(m) - , wdi_(wdi) - {} - -CONSTCD11 inline month month_weekday::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday_indexed -month_weekday::weekday_indexed() const NOEXCEPT -{ - return wdi_; -} - -CONSTCD11 -inline -bool -month_weekday::ok() const NOEXCEPT -{ - return m_.ok() && wdi_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const month_weekday& x, const month_weekday& y) NOEXCEPT -{ - return x.month() == y.month() && x.weekday_indexed() == y.weekday_indexed(); -} - -CONSTCD11 -inline -bool -operator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday& mwd) -{ - return os << mwd.month() << '/' << mwd.weekday_indexed(); -} - -// month_weekday_last - -CONSTCD11 -inline -month_weekday_last::month_weekday_last(const date::month& m, - const date::weekday_last& wdl) NOEXCEPT - : m_(m) - , wdl_(wdl) - {} - -CONSTCD11 inline month month_weekday_last::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday_last -month_weekday_last::weekday_last() const NOEXCEPT -{ - return wdl_; -} - -CONSTCD11 -inline -bool -month_weekday_last::ok() const NOEXCEPT -{ - return m_.ok() && wdl_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT -{ - return x.month() == y.month() && x.weekday_last() == y.weekday_last(); -} - -CONSTCD11 -inline -bool -operator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday_last& mwdl) -{ - return os << mwdl.month() << '/' << mwdl.weekday_last(); -} - -// year_month_day_last - -CONSTCD11 -inline -year_month_day_last::year_month_day_last(const date::year& y, - const date::month_day_last& mdl) NOEXCEPT - : y_(y) - , mdl_(mdl) - {} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_day_last::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_day_last::month() const NOEXCEPT {return mdl_.month();} - -CONSTCD11 -inline -month_day_last -year_month_day_last::month_day_last() const NOEXCEPT -{ - return mdl_; -} - -CONSTCD14 -inline -day -year_month_day_last::day() const NOEXCEPT -{ - CONSTDATA date::day d[] = - { - date::day(31), date::day(28), date::day(31), - date::day(30), date::day(31), date::day(30), - date::day(31), date::day(31), date::day(30), - date::day(31), date::day(30), date::day(31) - }; - return month() != feb || !y_.is_leap() ? - d[static_cast(month()) - 1] : date::day{29}; -} - -CONSTCD14 -inline -year_month_day_last::operator sys_days() const NOEXCEPT -{ - return sys_days(year()/month()/day()); -} - -CONSTCD14 -inline -year_month_day_last::operator local_days() const NOEXCEPT -{ - return local_days(year()/month()/day()); -} - -CONSTCD11 -inline -bool -year_month_day_last::ok() const NOEXCEPT -{ - return y_.ok() && mdl_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return x.year() == y.year() && x.month_day_last() == y.month_day_last(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (x.month_day_last() < y.month_day_last())); -} - -CONSTCD11 -inline -bool -operator>(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day_last& ymdl) -{ - return os << ymdl.year() << '/' << ymdl.month_day_last(); -} - -CONSTCD14 -inline -year_month_day_last -operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT -{ - return (ymdl.year() / ymdl.month() + dm) / last; -} - -CONSTCD14 -inline -year_month_day_last -operator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT -{ - return ymdl + dm; -} - -CONSTCD14 -inline -year_month_day_last -operator-(const year_month_day_last& ymdl, const months& dm) NOEXCEPT -{ - return ymdl + (-dm); -} - -CONSTCD11 -inline -year_month_day_last -operator+(const year_month_day_last& ymdl, const years& dy) NOEXCEPT -{ - return {ymdl.year()+dy, ymdl.month_day_last()}; -} - -CONSTCD11 -inline -year_month_day_last -operator+(const years& dy, const year_month_day_last& ymdl) NOEXCEPT -{ - return ymdl + dy; -} - -CONSTCD11 -inline -year_month_day_last -operator-(const year_month_day_last& ymdl, const years& dy) NOEXCEPT -{ - return ymdl + (-dy); -} - -// year_month_day - -CONSTCD11 -inline -year_month_day::year_month_day(const date::year& y, const date::month& m, - const date::day& d) NOEXCEPT - : y_(y) - , m_(m) - , d_(d) - {} - -CONSTCD14 -inline -year_month_day::year_month_day(const year_month_day_last& ymdl) NOEXCEPT - : y_(ymdl.year()) - , m_(ymdl.month()) - , d_(ymdl.day()) - {} - -CONSTCD14 -inline -year_month_day::year_month_day(sys_days dp) NOEXCEPT - : year_month_day(from_days(dp.time_since_epoch())) - {} - -CONSTCD14 -inline -year_month_day::year_month_day(local_days dp) NOEXCEPT - : year_month_day(from_days(dp.time_since_epoch())) - {} - -CONSTCD11 inline year year_month_day::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_day::month() const NOEXCEPT {return m_;} -CONSTCD11 inline day year_month_day::day() const NOEXCEPT {return d_;} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD14 -inline -days -year_month_day::to_days() const NOEXCEPT -{ - static_assert(std::numeric_limits::digits >= 18, - "This algorithm has not been ported to a 16 bit unsigned integer"); - static_assert(std::numeric_limits::digits >= 20, - "This algorithm has not been ported to a 16 bit signed integer"); - auto const y = static_cast(y_) - (m_ <= feb); - auto const m = static_cast(m_); - auto const d = static_cast(d_); - auto const era = (y >= 0 ? y : y-399) / 400; - auto const yoe = static_cast(y - era * 400); // [0, 399] - auto const doy = (153*(m > 2 ? m-3 : m+9) + 2)/5 + d-1; // [0, 365] - auto const doe = yoe * 365 + yoe/4 - yoe/100 + doy; // [0, 146096] - return days{era * 146097 + static_cast(doe) - 719468}; -} - -CONSTCD14 -inline -year_month_day::operator sys_days() const NOEXCEPT -{ - return sys_days{to_days()}; -} - -CONSTCD14 -inline -year_month_day::operator local_days() const NOEXCEPT -{ - return local_days{to_days()}; -} - -CONSTCD14 -inline -bool -year_month_day::ok() const NOEXCEPT -{ - if (!(y_.ok() && m_.ok())) - return false; - return date::day{1} <= d_ && d_ <= (y_ / m_ / last).day(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month() && x.day() == y.day(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (x.month() < y.month() ? true - : (x.month() > y.month() ? false - : (x.day() < y.day())))); -} - -CONSTCD11 -inline -bool -operator>(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day& ymd) -{ - detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os << ymd.year() << '-'; - os.width(2); - os << static_cast(ymd.month()) << '-'; - os << ymd.day(); - return os; -} - -CONSTCD14 -inline -year_month_day -year_month_day::from_days(days dp) NOEXCEPT -{ - static_assert(std::numeric_limits::digits >= 18, - "This algorithm has not been ported to a 16 bit unsigned integer"); - static_assert(std::numeric_limits::digits >= 20, - "This algorithm has not been ported to a 16 bit signed integer"); - auto const z = dp.count() + 719468; - auto const era = (z >= 0 ? z : z - 146096) / 146097; - auto const doe = static_cast(z - era * 146097); // [0, 146096] - auto const yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0, 399] - auto const y = static_cast(yoe) + era * 400; - auto const doy = doe - (365*yoe + yoe/4 - yoe/100); // [0, 365] - auto const mp = (5*doy + 2)/153; // [0, 11] - auto const d = doy - (153*mp+2)/5 + 1; // [1, 31] - auto const m = mp < 10 ? mp+3 : mp-9; // [1, 12] - return year_month_day{date::year{y + (m <= 2)}, date::month(m), date::day(d)}; -} - -CONSTCD14 -inline -year_month_day -operator+(const year_month_day& ymd, const months& dm) NOEXCEPT -{ - return (ymd.year() / ymd.month() + dm) / ymd.day(); -} - -CONSTCD14 -inline -year_month_day -operator+(const months& dm, const year_month_day& ymd) NOEXCEPT -{ - return ymd + dm; -} - -CONSTCD14 -inline -year_month_day -operator-(const year_month_day& ymd, const months& dm) NOEXCEPT -{ - return ymd + (-dm); -} - -CONSTCD11 -inline -year_month_day -operator+(const year_month_day& ymd, const years& dy) NOEXCEPT -{ - return (ymd.year() + dy) / ymd.month() / ymd.day(); -} - -CONSTCD11 -inline -year_month_day -operator+(const years& dy, const year_month_day& ymd) NOEXCEPT -{ - return ymd + dy; -} - -CONSTCD11 -inline -year_month_day -operator-(const year_month_day& ymd, const years& dy) NOEXCEPT -{ - return ymd + (-dy); -} - -// year_month_weekday - -CONSTCD11 -inline -year_month_weekday::year_month_weekday(const date::year& y, const date::month& m, - const date::weekday_indexed& wdi) - NOEXCEPT - : y_(y) - , m_(m) - , wdi_(wdi) - {} - -CONSTCD14 -inline -year_month_weekday::year_month_weekday(const sys_days& dp) NOEXCEPT - : year_month_weekday(from_days(dp.time_since_epoch())) - {} - -CONSTCD14 -inline -year_month_weekday::year_month_weekday(const local_days& dp) NOEXCEPT - : year_month_weekday(from_days(dp.time_since_epoch())) - {} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_weekday::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_weekday::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday -year_month_weekday::weekday() const NOEXCEPT -{ - return wdi_.weekday(); -} - -CONSTCD11 -inline -unsigned -year_month_weekday::index() const NOEXCEPT -{ - return wdi_.index(); -} - -CONSTCD11 -inline -weekday_indexed -year_month_weekday::weekday_indexed() const NOEXCEPT -{ - return wdi_; -} - -CONSTCD14 -inline -year_month_weekday::operator sys_days() const NOEXCEPT -{ - return sys_days{to_days()}; -} - -CONSTCD14 -inline -year_month_weekday::operator local_days() const NOEXCEPT -{ - return local_days{to_days()}; -} - -CONSTCD14 -inline -bool -year_month_weekday::ok() const NOEXCEPT -{ - if (!y_.ok() || !m_.ok() || !wdi_.weekday().ok() || wdi_.index() < 1) - return false; - if (wdi_.index() <= 4) - return true; - auto d2 = wdi_.weekday() - date::weekday(static_cast(y_/m_/1)) + days((wdi_.index()-1)*7 + 1); - return static_cast(d2.count()) <= static_cast((y_/m_/last).day()); -} - -CONSTCD14 -inline -year_month_weekday -year_month_weekday::from_days(days d) NOEXCEPT -{ - sys_days dp{d}; - auto const wd = date::weekday(dp); - auto const ymd = year_month_day(dp); - return {ymd.year(), ymd.month(), wd[(static_cast(ymd.day())-1)/7+1]}; -} - -CONSTCD14 -inline -days -year_month_weekday::to_days() const NOEXCEPT -{ - auto d = sys_days(y_/m_/1); - return (d + (wdi_.weekday() - date::weekday(d) + days{(wdi_.index()-1)*7}) - ).time_since_epoch(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month() && - x.weekday_indexed() == y.weekday_indexed(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday& ymwdi) -{ - return os << ymwdi.year() << '/' << ymwdi.month() - << '/' << ymwdi.weekday_indexed(); -} - -CONSTCD14 -inline -year_month_weekday -operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT -{ - return (ymwd.year() / ymwd.month() + dm) / ymwd.weekday_indexed(); -} - -CONSTCD14 -inline -year_month_weekday -operator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT -{ - return ymwd + dm; -} - -CONSTCD14 -inline -year_month_weekday -operator-(const year_month_weekday& ymwd, const months& dm) NOEXCEPT -{ - return ymwd + (-dm); -} - -CONSTCD11 -inline -year_month_weekday -operator+(const year_month_weekday& ymwd, const years& dy) NOEXCEPT -{ - return {ymwd.year()+dy, ymwd.month(), ymwd.weekday_indexed()}; -} - -CONSTCD11 -inline -year_month_weekday -operator+(const years& dy, const year_month_weekday& ymwd) NOEXCEPT -{ - return ymwd + dy; -} - -CONSTCD11 -inline -year_month_weekday -operator-(const year_month_weekday& ymwd, const years& dy) NOEXCEPT -{ - return ymwd + (-dy); -} - -// year_month_weekday_last - -CONSTCD11 -inline -year_month_weekday_last::year_month_weekday_last(const date::year& y, - const date::month& m, - const date::weekday_last& wdl) NOEXCEPT - : y_(y) - , m_(m) - , wdl_(wdl) - {} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_weekday_last::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_weekday_last::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday -year_month_weekday_last::weekday() const NOEXCEPT -{ - return wdl_.weekday(); -} - -CONSTCD11 -inline -weekday_last -year_month_weekday_last::weekday_last() const NOEXCEPT -{ - return wdl_; -} - -CONSTCD14 -inline -year_month_weekday_last::operator sys_days() const NOEXCEPT -{ - return sys_days{to_days()}; -} - -CONSTCD14 -inline -year_month_weekday_last::operator local_days() const NOEXCEPT -{ - return local_days{to_days()}; -} - -CONSTCD11 -inline -bool -year_month_weekday_last::ok() const NOEXCEPT -{ - return y_.ok() && m_.ok() && wdl_.ok(); -} - -CONSTCD14 -inline -days -year_month_weekday_last::to_days() const NOEXCEPT -{ - auto const d = sys_days(y_/m_/last); - return (d - (date::weekday{d} - wdl_.weekday())).time_since_epoch(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month() && - x.weekday_last() == y.weekday_last(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday_last& ymwdl) -{ - return os << ymwdl.year() << '/' << ymwdl.month() << '/' << ymwdl.weekday_last(); -} - -CONSTCD14 -inline -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT -{ - return (ymwdl.year() / ymwdl.month() + dm) / ymwdl.weekday_last(); -} - -CONSTCD14 -inline -year_month_weekday_last -operator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT -{ - return ymwdl + dm; -} - -CONSTCD14 -inline -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT -{ - return ymwdl + (-dm); -} - -CONSTCD11 -inline -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT -{ - return {ymwdl.year()+dy, ymwdl.month(), ymwdl.weekday_last()}; -} - -CONSTCD11 -inline -year_month_weekday_last -operator+(const years& dy, const year_month_weekday_last& ymwdl) NOEXCEPT -{ - return ymwdl + dy; -} - -CONSTCD11 -inline -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT -{ - return ymwdl + (-dy); -} - -// year_month from operator/() - -CONSTCD11 -inline -year_month -operator/(const year& y, const month& m) NOEXCEPT -{ - return {y, m}; -} - -CONSTCD11 -inline -year_month -operator/(const year& y, int m) NOEXCEPT -{ - return y / month(static_cast(m)); -} - -// month_day from operator/() - -CONSTCD11 -inline -month_day -operator/(const month& m, const day& d) NOEXCEPT -{ - return {m, d}; -} - -CONSTCD11 -inline -month_day -operator/(const day& d, const month& m) NOEXCEPT -{ - return m / d; -} - -CONSTCD11 -inline -month_day -operator/(const month& m, int d) NOEXCEPT -{ - return m / day(static_cast(d)); -} - -CONSTCD11 -inline -month_day -operator/(int m, const day& d) NOEXCEPT -{ - return month(static_cast(m)) / d; -} - -CONSTCD11 inline month_day operator/(const day& d, int m) NOEXCEPT {return m / d;} - -// month_day_last from operator/() - -CONSTCD11 -inline -month_day_last -operator/(const month& m, last_spec) NOEXCEPT -{ - return month_day_last{m}; -} - -CONSTCD11 -inline -month_day_last -operator/(last_spec, const month& m) NOEXCEPT -{ - return m/last; -} - -CONSTCD11 -inline -month_day_last -operator/(int m, last_spec) NOEXCEPT -{ - return month(static_cast(m))/last; -} - -CONSTCD11 -inline -month_day_last -operator/(last_spec, int m) NOEXCEPT -{ - return m/last; -} - -// month_weekday from operator/() - -CONSTCD11 -inline -month_weekday -operator/(const month& m, const weekday_indexed& wdi) NOEXCEPT -{ - return {m, wdi}; -} - -CONSTCD11 -inline -month_weekday -operator/(const weekday_indexed& wdi, const month& m) NOEXCEPT -{ - return m / wdi; -} - -CONSTCD11 -inline -month_weekday -operator/(int m, const weekday_indexed& wdi) NOEXCEPT -{ - return month(static_cast(m)) / wdi; -} - -CONSTCD11 -inline -month_weekday -operator/(const weekday_indexed& wdi, int m) NOEXCEPT -{ - return m / wdi; -} - -// month_weekday_last from operator/() - -CONSTCD11 -inline -month_weekday_last -operator/(const month& m, const weekday_last& wdl) NOEXCEPT -{ - return {m, wdl}; -} - -CONSTCD11 -inline -month_weekday_last -operator/(const weekday_last& wdl, const month& m) NOEXCEPT -{ - return m / wdl; -} - -CONSTCD11 -inline -month_weekday_last -operator/(int m, const weekday_last& wdl) NOEXCEPT -{ - return month(static_cast(m)) / wdl; -} - -CONSTCD11 -inline -month_weekday_last -operator/(const weekday_last& wdl, int m) NOEXCEPT -{ - return m / wdl; -} - -// year_month_day from operator/() - -CONSTCD11 -inline -year_month_day -operator/(const year_month& ym, const day& d) NOEXCEPT -{ - return {ym.year(), ym.month(), d}; -} - -CONSTCD11 -inline -year_month_day -operator/(const year_month& ym, int d) NOEXCEPT -{ - return ym / day(static_cast(d)); -} - -CONSTCD11 -inline -year_month_day -operator/(const year& y, const month_day& md) NOEXCEPT -{ - return y / md.month() / md.day(); -} - -CONSTCD11 -inline -year_month_day -operator/(int y, const month_day& md) NOEXCEPT -{ - return year(y) / md; -} - -CONSTCD11 -inline -year_month_day -operator/(const month_day& md, const year& y) NOEXCEPT -{ - return y / md; -} - -CONSTCD11 -inline -year_month_day -operator/(const month_day& md, int y) NOEXCEPT -{ - return year(y) / md; -} - -// year_month_day_last from operator/() - -CONSTCD11 -inline -year_month_day_last -operator/(const year_month& ym, last_spec) NOEXCEPT -{ - return {ym.year(), month_day_last{ym.month()}}; -} - -CONSTCD11 -inline -year_month_day_last -operator/(const year& y, const month_day_last& mdl) NOEXCEPT -{ - return {y, mdl}; -} - -CONSTCD11 -inline -year_month_day_last -operator/(int y, const month_day_last& mdl) NOEXCEPT -{ - return year(y) / mdl; -} - -CONSTCD11 -inline -year_month_day_last -operator/(const month_day_last& mdl, const year& y) NOEXCEPT -{ - return y / mdl; -} - -CONSTCD11 -inline -year_month_day_last -operator/(const month_day_last& mdl, int y) NOEXCEPT -{ - return year(y) / mdl; -} - -// year_month_weekday from operator/() - -CONSTCD11 -inline -year_month_weekday -operator/(const year_month& ym, const weekday_indexed& wdi) NOEXCEPT -{ - return {ym.year(), ym.month(), wdi}; -} - -CONSTCD11 -inline -year_month_weekday -operator/(const year& y, const month_weekday& mwd) NOEXCEPT -{ - return {y, mwd.month(), mwd.weekday_indexed()}; -} - -CONSTCD11 -inline -year_month_weekday -operator/(int y, const month_weekday& mwd) NOEXCEPT -{ - return year(y) / mwd; -} - -CONSTCD11 -inline -year_month_weekday -operator/(const month_weekday& mwd, const year& y) NOEXCEPT -{ - return y / mwd; -} - -CONSTCD11 -inline -year_month_weekday -operator/(const month_weekday& mwd, int y) NOEXCEPT -{ - return year(y) / mwd; -} - -// year_month_weekday_last from operator/() - -CONSTCD11 -inline -year_month_weekday_last -operator/(const year_month& ym, const weekday_last& wdl) NOEXCEPT -{ - return {ym.year(), ym.month(), wdl}; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(const year& y, const month_weekday_last& mwdl) NOEXCEPT -{ - return {y, mwdl.month(), mwdl.weekday_last()}; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(int y, const month_weekday_last& mwdl) NOEXCEPT -{ - return year(y) / mwdl; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(const month_weekday_last& mwdl, const year& y) NOEXCEPT -{ - return y / mwdl; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(const month_weekday_last& mwdl, int y) NOEXCEPT -{ - return year(y) / mwdl; -} - -// time_of_day - -enum {am = 1, pm}; - -namespace detail -{ - -enum class classify -{ - not_valid, - hour, - minute, - second, - subsecond -}; - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) - -template -struct classify_duration -{ - static CONSTDATA classify value = - Duration{1} >= days{1} ? classify::not_valid : - Duration{1} >= std::chrono::hours{1} ? classify::hour : - Duration{1} >= std::chrono::minutes{1} ? classify::minute : - Duration{1} >= std::chrono::seconds{1} ? classify::second : - classify::subsecond; -}; - -#else - -template -struct classify_duration -{ - static CONSTDATA classify value = - std::ratio_greater_equal< - typename Duration::period, - days::period >::value - ? classify::not_valid : - std::ratio_greater_equal< - typename Duration::period, - std::chrono::hours::period>::value - ? classify::hour : - std::ratio_greater_equal< - typename Duration::period, - std::chrono::minutes::period>::value - ? classify::minute : - std::ratio_greater_equal< - typename Duration::period, - std::chrono::seconds::period>::value - ? classify::second : - classify::subsecond; -}; - -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - -class time_of_day_base -{ -protected: - std::chrono::hours h_; - unsigned char mode_; - - enum {is24hr}; - - CONSTCD11 time_of_day_base(std::chrono::hours h, unsigned m) NOEXCEPT - : h_(h) - , mode_(static_cast(m)) - {} - - CONSTCD14 void make24() NOEXCEPT; - CONSTCD14 void make12() NOEXCEPT; - - CONSTCD14 std::chrono::hours to24hr() const; -}; - -CONSTCD14 -inline -std::chrono::hours -time_of_day_base::to24hr() const -{ - auto h = h_; - if (mode_ == am || mode_ == pm) - { - CONSTDATA auto h12 = std::chrono::hours(12); - if (mode_ == pm) - { - if (h != h12) - h = h + h12; - } - else if (h == h12) - h = std::chrono::hours(0); - } - return h; -} - -CONSTCD14 -inline -void -time_of_day_base::make24() NOEXCEPT -{ - h_ = to24hr(); - mode_ = is24hr; -} - -CONSTCD14 -inline -void -time_of_day_base::make12() NOEXCEPT -{ - if (mode_ == is24hr) - { - CONSTDATA auto h12 = std::chrono::hours(12); - if (h_ >= h12) - { - if (h_ > h12) - h_ = h_ - h12; - mode_ = pm; - } - else - { - if (h_ == std::chrono::hours(0)) - h_ = h12; - mode_ = am; - } - } -} - -template ::value> -class time_of_day_storage; - -template -class time_of_day_storage, detail::classify::hour> - : private detail::time_of_day_base -{ - using base = detail::time_of_day_base; - -public: - using precision = std::chrono::hours; - - CONSTCD11 explicit time_of_day_storage(std::chrono::hours since_midnight) NOEXCEPT - : base(since_midnight, is24hr) - {} - - CONSTCD11 explicit time_of_day_storage(std::chrono::hours h, unsigned md) NOEXCEPT - : base(h, md) - {} - - CONSTCD11 std::chrono::hours hours() const NOEXCEPT {return h_;} - CONSTCD11 unsigned mode() const NOEXCEPT {return mode_;} - - CONSTCD14 explicit operator precision() const NOEXCEPT - { - return to24hr(); - } - - CONSTCD14 precision to_duration() const NOEXCEPT - { - return static_cast(*this); - } - - CONSTCD14 time_of_day_storage& make24() NOEXCEPT {base::make24(); return *this;} - CONSTCD14 time_of_day_storage& make12() NOEXCEPT {base::make12(); return *this;} - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const time_of_day_storage& t) - { - using namespace std; - detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - if (t.mode_ != am && t.mode_ != pm) - os.width(2); - os << t.h_.count(); - switch (t.mode_) - { - case time_of_day_storage::is24hr: - os << "00"; - break; - case am: - os << "am"; - break; - case pm: - os << "pm"; - break; - } - return os; - } -}; - -template -class time_of_day_storage, detail::classify::minute> - : private detail::time_of_day_base -{ - using base = detail::time_of_day_base; - - std::chrono::minutes m_; - -public: - using precision = std::chrono::minutes; - - CONSTCD11 explicit time_of_day_storage(std::chrono::minutes since_midnight) NOEXCEPT - : base(std::chrono::duration_cast(since_midnight), is24hr) - , m_(since_midnight - h_) - {} - - CONSTCD11 explicit time_of_day_storage(std::chrono::hours h, std::chrono::minutes m, - unsigned md) NOEXCEPT - : base(h, md) - , m_(m) - {} - - CONSTCD11 std::chrono::hours hours() const NOEXCEPT {return h_;} - CONSTCD11 std::chrono::minutes minutes() const NOEXCEPT {return m_;} - CONSTCD11 unsigned mode() const NOEXCEPT {return mode_;} - - CONSTCD14 explicit operator precision() const NOEXCEPT - { - return to24hr() + m_; - } - - CONSTCD14 precision to_duration() const NOEXCEPT - { - return static_cast(*this); - } - - CONSTCD14 time_of_day_storage& make24() NOEXCEPT {base::make24(); return *this;} - CONSTCD14 time_of_day_storage& make12() NOEXCEPT {base::make12(); return *this;} - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const time_of_day_storage& t) - { - using namespace std; - detail::save_stream _(os); - if (static_cast(t) < std::chrono::hours{0}) - os << '-'; - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - if (t.mode_ != am && t.mode_ != pm) - os.width(2); - os << std::abs(t.h_.count()) << ':'; - os.width(2); - os << std::abs(t.m_.count()); - switch (t.mode_) - { - case am: - os << "am"; - break; - case pm: - os << "pm"; - break; - } - return os; - } -}; - -template -class time_of_day_storage, detail::classify::second> - : private detail::time_of_day_base -{ - using base = detail::time_of_day_base; - - std::chrono::minutes m_; - std::chrono::seconds s_; - -public: - using precision = std::chrono::seconds; - - CONSTCD11 explicit time_of_day_storage(std::chrono::seconds since_midnight) NOEXCEPT - : base(std::chrono::duration_cast(since_midnight), is24hr) - , m_(std::chrono::duration_cast(since_midnight - h_)) - , s_(since_midnight - h_ - m_) - {} - - CONSTCD11 explicit time_of_day_storage(std::chrono::hours h, std::chrono::minutes m, - std::chrono::seconds s, unsigned md) NOEXCEPT - : base(h, md) - , m_(m) - , s_(s) - {} - - CONSTCD11 std::chrono::hours hours() const NOEXCEPT {return h_;} - CONSTCD11 std::chrono::minutes minutes() const NOEXCEPT {return m_;} - CONSTCD14 std::chrono::seconds& seconds() NOEXCEPT {return s_;} - CONSTCD11 std::chrono::seconds seconds() const NOEXCEPT {return s_;} - CONSTCD11 unsigned mode() const NOEXCEPT {return mode_;} - - CONSTCD14 explicit operator precision() const NOEXCEPT - { - return to24hr() + s_ + m_; - } - - CONSTCD14 precision to_duration() const NOEXCEPT - { - return static_cast(*this); - } - - CONSTCD14 time_of_day_storage& make24() NOEXCEPT {base::make24(); return *this;} - CONSTCD14 time_of_day_storage& make12() NOEXCEPT {base::make12(); return *this;} - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const time_of_day_storage& t) - { - using namespace std; - detail::save_stream _(os); - if (static_cast(t) < std::chrono::hours{0}) - os << '-'; - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - if (t.mode_ != am && t.mode_ != pm) - os.width(2); - os << std::abs(t.h_.count()) << ':'; - os.width(2); - os << std::abs(t.m_.count()) << ':'; - os.width(2); - os << std::abs(t.s_.count()); - switch (t.mode_) - { - case am: - os << "am"; - break; - case pm: - os << "pm"; - break; - } - return os; - } -}; - -template -class time_of_day_storage, detail::classify::subsecond> - : private detail::time_of_day_base -{ -public: - using precision = std::chrono::duration; - -private: - using base = detail::time_of_day_base; - - std::chrono::minutes m_; - std::chrono::seconds s_; - precision sub_s_; - -public: - CONSTCD11 explicit time_of_day_storage(precision since_midnight) NOEXCEPT - : base(std::chrono::duration_cast(since_midnight), is24hr) - , m_(std::chrono::duration_cast(since_midnight - h_)) - , s_(std::chrono::duration_cast(since_midnight - h_ - m_)) - , sub_s_(since_midnight - h_ - m_ - s_) - {} - - CONSTCD11 explicit time_of_day_storage(std::chrono::hours h, std::chrono::minutes m, - std::chrono::seconds s, precision sub_s, - unsigned md) NOEXCEPT - : base(h, md) - , m_(m) - , s_(s) - , sub_s_(sub_s) - {} - - CONSTCD11 std::chrono::hours hours() const NOEXCEPT {return h_;} - CONSTCD11 std::chrono::minutes minutes() const NOEXCEPT {return m_;} - CONSTCD14 std::chrono::seconds& seconds() NOEXCEPT {return s_;} - CONSTCD11 std::chrono::seconds seconds() const NOEXCEPT {return s_;} - CONSTCD11 precision subseconds() const NOEXCEPT {return sub_s_;} - CONSTCD11 unsigned mode() const NOEXCEPT {return mode_;} - - CONSTCD14 explicit operator precision() const NOEXCEPT - { - return to24hr() + s_ + sub_s_ + m_; - } - - CONSTCD14 precision to_duration() const NOEXCEPT - { - return static_cast(*this); - } - - CONSTCD14 time_of_day_storage& make24() NOEXCEPT {base::make24(); return *this;} - CONSTCD14 time_of_day_storage& make12() NOEXCEPT {base::make12(); return *this;} - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const time_of_day_storage& t) - { - using namespace std; - detail::save_stream _(os); - if (static_cast(t) < std::chrono::hours{0}) - os << '-'; - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - if (t.mode_ != am && t.mode_ != pm) - os.width(2); - os << std::abs(t.h_.count()) << ':'; - os.width(2); - os << std::abs(t.m_.count()) << ':'; - os.width(2); - os << std::abs(t.s_.count()) - << use_facet>(os.getloc()).decimal_point(); - os.imbue(locale{}); -#if __cplusplus >= 201402 - CONSTDATA auto cl10 = ceil_log10(Period::den); - using scale = std::ratio_multiply>; - os.width(cl10); - os << std::abs(t.sub_s_.count()) * scale::num / scale::den; -#else // __cplusplus >= 201402 - // inefficient sub-optimal run-time mess, but gets the job done - const unsigned long long cl10 = - static_cast(std::ceil(log10(Period::den))); - const auto p10 = std::pow(10., cl10); - os.width(cl10); - os << static_cast(std::abs(t.sub_s_.count()) - * Period::num * p10 / Period::den); -#endif // __cplusplus >= 201402 - switch (t.mode_) - { - case am: - os << "am"; - break; - case pm: - os << "pm"; - break; - } - return os; - } - -private: -#if __cplusplus >= 201402 - CONSTCD11 static int ceil_log10(unsigned long long i) NOEXCEPT - { - --i; - int n = 0; - if (i >= 10000000000000000) {i /= 10000000000000000; n += 16;} - if (i >= 100000000) {i /= 100000000; n += 8;} - if (i >= 10000) {i /= 10000; n += 4;} - if (i >= 100) {i /= 100; n += 2;} - if (i >= 10) {i /= 10; n += 1;} - if (i >= 1) {i /= 10; n += 1;} - return n; - } - - CONSTCD11 static unsigned long long pow10(unsigned y) NOEXCEPT - { - CONSTDATA unsigned long long p10[] = - { - 1ull, - 10ull, - 100ull, - 1000ull, - 10000ull, - 100000ull, - 1000000ull, - 10000000ull, - 100000000ull, - 1000000000ull, - 10000000000ull, - 100000000000ull, - 1000000000000ull, - 10000000000000ull, - 100000000000000ull, - 1000000000000000ull, - 10000000000000000ull, - 100000000000000000ull, - 1000000000000000000ull, - 10000000000000000000ull - }; - return p10[y]; - } -#endif // __cplusplus >= 201402 -}; - -} // namespace detail - -template -class time_of_day - : public detail::time_of_day_storage -{ - using base = detail::time_of_day_storage; -public: -#if !(defined(_MSC_VER) && !defined(__clang__)) - // C++11 - using base::base; -#else - // MS cl compiler workaround. - template - explicit time_of_day(Args&& ...args) - : base(std::forward(args)...) - {} -#endif -}; - -template ::value>::type> -CONSTCD11 -inline -time_of_day> -make_time(const std::chrono::duration& d) -{ - return time_of_day>(d); -} - -CONSTCD11 -inline -time_of_day -make_time(const std::chrono::hours& h, unsigned md) -{ - return time_of_day(h, md); -} - -CONSTCD11 -inline -time_of_day -make_time(const std::chrono::hours& h, const std::chrono::minutes& m, - unsigned md) -{ - return time_of_day(h, m, md); -} - -CONSTCD11 -inline -time_of_day -make_time(const std::chrono::hours& h, const std::chrono::minutes& m, - const std::chrono::seconds& s, unsigned md) -{ - return time_of_day(h, m, s, md); -} - -template >::value>::type> -CONSTCD11 -inline -time_of_day> -make_time(const std::chrono::hours& h, const std::chrono::minutes& m, - const std::chrono::seconds& s, const std::chrono::duration& sub_s, - unsigned md) -{ - return time_of_day>(h, m, s, sub_s, md); -} - -template -inline -typename std::enable_if -< - !std::chrono::treat_as_floating_point::value && - std::ratio_less::value - , std::basic_ostream& ->::type -operator<<(std::basic_ostream& os, const sys_time& tp) -{ - auto const dp = floor(tp); - return os << year_month_day(dp) << ' ' << make_time(tp-dp); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const sys_days& dp) -{ - return os << year_month_day(dp); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const local_time& ut) -{ - return os << sys_time{ut.time_since_epoch()}; -} - -// format - -namespace detail -{ - -template -std::basic_string -format(const std::locale& loc, std::basic_string fmt, - const local_time& tp, const std::string* abbrev = nullptr, - const std::chrono::seconds* offset_sec = nullptr) -{ - // Handle these specially - // %S append fractional seconds if tp has precision finer than seconds - // %T append fractional seconds if tp has precision finer than seconds - // %z replace with offset from zone on +/-hhmm format - // %Ez, %Oz replace with offset from zone on +/-hh:mm format - // %Z replace with abbreviation from zone - - using namespace std; - using namespace std::chrono; - auto command = false; - auto modified = false; - for (std::size_t i = 0; i < fmt.size(); ++i) - { - switch (fmt[i]) - { - case '%': - command = true; - modified = false; - break; - case 'O': - case 'E': - modified = true; - break; - case 'S': - case 'T': - if (command && !modified && ratio_less>::value) - { - basic_ostringstream os; - os.imbue(loc); - os << make_time(tp - floor(tp)); - auto s = os.str(); - s.erase(0, 8); - fmt.insert(i+1, s); - i += s.size() - 1; - } - command = false; - modified = false; - break; - case 'z': - if (command) - { - if (offset_sec == nullptr) - throw std::runtime_error("Can not format local_time with %z"); - else - { - auto offset = duration_cast(*offset_sec); - basic_ostringstream os; - os.imbue(loc); - if (offset >= minutes{0}) - os << '+'; - os << make_time(offset); - auto s = os.str(); - if (!modified) - s.erase(s.find(':'), 1); - fmt.replace(i - 1 - modified, 2 + modified, s); - i += 3; - } - } - command = false; - modified = false; - break; - case 'Z': - if (command && !modified) - { - if (abbrev == nullptr) - throw std::runtime_error("Can not format local_time with %Z"); - else - { - fmt.replace(i - 1, 2, - std::basic_string(abbrev->begin(), abbrev->end())); - i += abbrev->size() - 1; - } - } - command = false; - modified = false; - break; - default: - command = false; - modified = false; - break; - } - } - auto& f = use_facet>(loc); - basic_ostringstream os; - os.imbue(loc); - auto ld = floor(tp); - auto ymd = year_month_day{ld}; - auto hms = make_time(floor(tp - ld)); - std::tm tm{}; - tm.tm_sec = static_cast(hms.seconds().count()); - tm.tm_min = static_cast(hms.minutes().count()); - tm.tm_hour = static_cast(hms.hours().count()); - tm.tm_mday = static_cast(static_cast(ymd.day())); - tm.tm_mon = static_cast(static_cast(ymd.month()) - 1); - tm.tm_year = static_cast(ymd.year()) - 1900; - tm.tm_wday = static_cast(static_cast(weekday{ld})); - tm.tm_yday = static_cast((ld - local_days(ymd.year()/1/1)).count()); - f.put(os, os, os.fill(), &tm, fmt.data(), fmt.data() + fmt.size()); - return os.str(); -} - -} // namespace detail - -template -inline -std::basic_string -format(const std::locale& loc, std::basic_string fmt, - const local_time& tp) -{ - return detail::format(loc, std::move(fmt), tp); -} - -template -inline -std::basic_string -format(std::basic_string fmt, const local_time& tp) -{ - return detail::format(std::locale{}, std::move(fmt), tp); -} - -template -inline -std::basic_string -format(const std::locale& loc, std::basic_string fmt, - const sys_time& tp) -{ - const std::string abbrev("UTC"); - CONSTDATA std::chrono::seconds offset{0}; - return detail::format(loc, std::move(fmt), - local_time{tp.time_since_epoch()}, &abbrev, &offset); -} - -template -inline -std::basic_string -format(std::basic_string fmt, const sys_time& tp) -{ - const std::string abbrev("UTC"); - CONSTDATA std::chrono::seconds offset{0}; - return detail::format(std::locale{}, std::move(fmt), - local_time{tp.time_since_epoch()}, &abbrev, &offset); -} - -// const CharT* formats - -template -inline -std::basic_string -format(const std::locale& loc, const CharT* fmt, const local_time& tp) -{ - return detail::format(loc, std::basic_string(fmt), tp); -} - -template -inline -std::basic_string -format(const CharT* fmt, const local_time& tp) -{ - return detail::format(std::locale{}, std::basic_string(fmt), tp); -} - -template -inline -std::basic_string -format(const std::locale& loc, const CharT* fmt, const sys_time& tp) -{ - const std::string abbrev("UTC"); - CONSTDATA std::chrono::seconds offset{0}; - return detail::format(loc, std::basic_string(fmt), - local_time{tp.time_since_epoch()}, - &abbrev, &offset); -} - -template -inline -std::basic_string -format(const CharT* fmt, const sys_time& tp) -{ - const std::string abbrev("UTC"); - CONSTDATA std::chrono::seconds offset{0}; - return detail::format(std::locale{}, std::basic_string(fmt), - local_time{tp.time_since_epoch()}, - &abbrev, &offset); -} - -// parse - -namespace detail -{ - -template -void -parse(std::basic_istream& is, - const std::basic_string& format, local_time& tp, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - typename basic_istream::sentry ok{is}; - if (ok) - { - auto& f = use_facet>(is.getloc()); - ios_base::iostate err = ios_base::goodbit; - std::tm tm{}; - Duration subseconds{}; - std::basic_string temp_abbrev; - minutes temp_offset{}; - - auto b = format.data(); - auto i = b; - auto e = b + format.size(); - auto command = false; - auto modified = false; - for (; i < e && 0 == (err & ios_base::failbit); ++i) - { - switch (*i) - { - case '%': - command = true; - modified = false; - break; - case 'F': - if (command && !modified) - { - f.get(is, 0, is, err, &tm, b, i-1); - b = i+1; - if ((err & ios_base::failbit) == 0) - { - const CharT ymd[] = {'%', 'Y', '-', '%', 'm', '-', '%', 'd'}; - f.get(is, 0, is, err, &tm, ymd, ymd+8); - } - } - command = false; - modified = false; - break; - case 'O': - case 'E': - modified = true; - break; - case 'T': - case 'S': - if (command && !modified) - { - f.get(is, 0, is, err, &tm, b, i-1); - if (err & ios_base::failbit) - { - command = modified = false; - break; // break the switch/case - } - b = i+1; - if (*i == 'T') - { - const CharT hm[] = {'%', 'H', ':', '%', 'M', ':'}; - f.get(is, 0, is, err, &tm, hm, hm+6); - if (err & ios_base::failbit) - { - command = modified = false; - break; // break the switch/case - } - } - if (ratio_less>::value) - { - auto decimal_point = Traits::to_int_type( - use_facet>(is.getloc()).decimal_point()); - string buf; - while (true) - { - auto k = is.peek(); - if (Traits::eq_int_type(k, Traits::eof())) - break; - if (Traits::eq_int_type(k, decimal_point)) - { - buf += '.'; - decimal_point = Traits::eof(); - is.get(); - } - else - { - auto c = static_cast(Traits::to_char_type(k)); - if (isdigit(c)) - { - buf += c; - is.get(); - } - else - { - break; - } - } - }; - if (!buf.empty()) - subseconds = round(duration{stod(buf)}); - else - err |= ios_base::failbit; - } - else - { - const CharT hm[] = {'%', 'S'}; - f.get(is, 0, is, err, &tm, hm, hm+2); - } - } - command = false; - modified = false; - break; - case 'z': - if (command) - { - f.get(is, 0, is, err, &tm, b, i-1-modified); - b = i+1; - if ((err & ios_base::failbit) == 0) - { - CharT sign{}; - is >> sign; - if (!is.fail() && (sign == '+' || sign == '-')) - { - char h1, h0, m1, m0; - char colon = ':'; - h1 = static_cast(is.get()); - h0 = static_cast(is.get()); - if (modified) - { - if (h0 == ':') - { - colon = h0; - h0 = h1; - h1 = '0'; - } - else - colon = static_cast(is.get()); - } - m1 = static_cast(is.get()); - m0 = static_cast(is.get()); - if (!is.fail() && std::isdigit(h1) && std::isdigit(h0) - && std::isdigit(m1) && std::isdigit(m0) - && colon == ':') - { - temp_offset = 10*hours{h1 - '0'} + hours{h0 - '0'} + - 10*minutes{m1 - '0'} + minutes{m0 - '0'}; - if (sign == '-') - temp_offset = -temp_offset; - } - else - err |= ios_base::failbit; - } - else - err |= ios_base::failbit; - } - } - command = false; - modified = false; - break; - case 'Z': - if (command && !modified) - { - f.get(is, 0, is, err, &tm, b, i-1); - b = i+1; - if ((err & ios_base::failbit) == 0) - { - is >> temp_abbrev; - if (is.fail()) - err |= ios_base::failbit; - } - } - command = false; - modified = false; - break; - default: - command = false; - modified = false; - break; - } - } - if ((err & ios_base::failbit) == 0) - { - if (b < e) - f.get(is, 0, is, err, &tm, b, e); - if ((err & ios_base::failbit) == 0) - { - using namespace std::chrono; - tp = floor(local_days(year{tm.tm_year + 1900}/ - (tm.tm_mon+1)/ - (tm.tm_mday)) + - subseconds + seconds{tm.tm_sec} + - minutes{tm.tm_min} + hours{tm.tm_hour}); - if (abbrev != nullptr) - *abbrev = std::move(temp_abbrev); - if (offset != nullptr) - *offset = temp_offset; - } - } - is.setstate(err); - } - else - is.setstate(ios_base::failbit); -} - -template -inline -void -parse(std::basic_istream& is, - const std::basic_string& format, local_time& tp, - std::chrono::minutes* offset) -{ - parse(is, format, tp, static_cast*>(nullptr), offset); -} - -template > -struct parse_local_manip -{ - const std::basic_string format_; - local_time& tp_; - std::basic_string* abbrev_; - std::chrono::minutes* offset_; - -public: - parse_local_manip(std::basic_string format, - local_time& tp, std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) - : format_(std::move(format)) - , tp_(tp) - , abbrev_(abbrev) - , offset_(offset) - {} - -}; - -template -std::basic_istream& -operator>>(std::basic_istream& is, - const parse_local_manip& x) -{ - parse(is, x.format_, x.tp_, x.abbrev_, x.offset_); - return is; -} - -template > -struct parse_sys_manip -{ - const std::basic_string format_; - sys_time& tp_; - std::basic_string* abbrev_; - std::chrono::minutes* offset_; - -public: - parse_sys_manip(std::basic_string format, - sys_time& tp, std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) - : format_(std::move(format)) - , tp_(tp) - , abbrev_(abbrev) - , offset_(offset) - {} - -}; - -template -std::basic_istream& -operator>>(std::basic_istream& is, - const parse_sys_manip& x) -{ - std::chrono::minutes offset{}; - auto offptr = x.offset_ ? x.offset_ : &offset; - local_time lt; - parse(is, x.format_, lt, x.abbrev_, offptr); - if (!is.fail()) - x.tp_ = sys_time{floor(lt - *offptr).time_since_epoch()}; - return is; -} - -} // namespace detail - -template -inline -void -parse(std::basic_istream& is, - const std::basic_string& format, sys_time& tp) -{ - std::chrono::minutes offset{}; - local_time lt; - detail::parse(is, format, lt, &offset); - if (!is.fail()) - tp = sys_time{floor(lt - offset).time_since_epoch()}; -} - -template -inline -detail::parse_sys_manip -parse(const std::basic_string& format, sys_time& tp) -{ - return {format, tp}; -} - -template -inline -void -parse(std::basic_istream& is, - const std::basic_string& format, sys_time& tp, - std::basic_string& abbrev) -{ - std::chrono::minutes offset{}; - local_time lt; - detail::parse(is, format, lt, &abbrev, &offset); - if (!is.fail()) - tp = sys_time{floor(lt - offset).time_since_epoch()}; -} - -template -inline -detail::parse_sys_manip -parse(const std::basic_string& format, sys_time& tp, - std::basic_string& abbrev) -{ - return {format, tp, &abbrev}; -} - -template -inline -void -parse(std::basic_istream& is, - const std::basic_string& format, sys_time& tp, - std::chrono::minutes& offset) -{ - local_time lt; - detail::parse(is, format, lt, &offset); - if (!is.fail()) - tp = sys_time{floor(lt - offset).time_since_epoch()}; -} - -template -inline -detail::parse_sys_manip -parse(const std::basic_string& format, sys_time& tp, - std::chrono::minutes& offset) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -void -parse(std::basic_istream& is, - const std::basic_string& format, sys_time& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - local_time lt; - detail::parse(is, format, lt, &abbrev, &offset); - if (!is.fail()) - tp = sys_time{floor(lt - offset).time_since_epoch()}; -} - -template -inline -detail::parse_sys_manip -parse(const std::basic_string& format, sys_time& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -void -parse(std::basic_istream& is, - const std::basic_string& format, sys_time& tp, - std::chrono::minutes& offset, std::basic_string& abbrev) -{ - local_time lt; - detail::parse(is, format, lt, &abbrev, &offset); - if (!is.fail()) - tp = sys_time{floor(lt - offset).time_since_epoch()}; -} - -template -inline -detail::parse_sys_manip -parse(const std::basic_string& format, sys_time& tp, - std::chrono::minutes& offset, std::basic_string& abbrev) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -void -parse(std::basic_istream& is, - const std::basic_string& format, local_time& tp) -{ - detail::parse(is, format, tp); -} - -template -inline -detail::parse_local_manip -parse(const std::basic_string& format, local_time& tp) -{ - return {format, tp}; -} - -template -inline -void -parse(std::basic_istream& is, - const std::basic_string& format, local_time& tp, - std::basic_string& abbrev) -{ - detail::parse(is, format, tp, &abbrev); -} - -template -inline -detail::parse_local_manip -parse(const std::basic_string& format, local_time& tp, - std::basic_string& abbrev) -{ - return {format, tp, &abbrev}; -} - -template -inline -void -parse(std::basic_istream& is, - const std::basic_string& format, local_time& tp, - std::chrono::minutes& offset) -{ - detail::parse(is, format, tp, &offset); -} - -template -inline -detail::parse_local_manip -parse(const std::basic_string& format, local_time& tp, - std::chrono::minutes& offset) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -void -parse(std::basic_istream& is, - const std::basic_string& format, local_time& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - detail::parse(is, format, tp, &abbrev, &offset); -} - -template -inline -detail::parse_local_manip -parse(const std::basic_string& format, local_time& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -void -parse(std::basic_istream& is, - const std::basic_string& format, local_time& tp, - std::chrono::minutes& offset, std::basic_string& abbrev) -{ - detail::parse(is, format, tp, &abbrev, &offset); -} - -template -inline -detail::parse_local_manip -parse(const std::basic_string& format, local_time& tp, - std::chrono::minutes& offset, std::basic_string& abbrev) -{ - return {format, tp, &abbrev, &offset}; -} - -// const CharT* formats - -template -inline -void -parse(std::basic_istream& is, const CharT* format, sys_time& tp) -{ - parse(is, std::basic_string(format), tp); -} - -template -inline -detail::parse_sys_manip -parse(const CharT* format, sys_time& tp) -{ - return {format, tp}; -} - -template -inline -void -parse(std::basic_istream& is, const CharT* format, sys_time& tp, - std::basic_string& abbrev) -{ - parse(is, std::basic_string(format), tp, abbrev); -} - -template -inline -detail::parse_sys_manip -parse(const CharT* format, sys_time& tp, - std::basic_string& abbrev) -{ - return {format, tp, &abbrev}; -} - -template -inline -void -parse(std::basic_istream& is, const CharT* format, sys_time& tp, - std::chrono::minutes& offset) -{ - parse(is, std::basic_string(format), tp, offset); -} - -template -inline -detail::parse_sys_manip -parse(const CharT* format, sys_time& tp, std::chrono::minutes& offset) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -void -parse(std::basic_istream& is, const CharT* format, sys_time& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - parse(is, std::basic_string(format), tp, abbrev, offset); -} - -template -inline -detail::parse_sys_manip -parse(const CharT* format, sys_time& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -void -parse(std::basic_istream& is, const CharT* format, sys_time& tp, - std::chrono::minutes& offset, std::basic_string& abbrev) -{ - parse(is, std::basic_string(format), tp, abbrev, offset); -} - -template -inline -detail::parse_sys_manip -parse(const CharT* format, sys_time& tp, - std::chrono::minutes& offset, std::basic_string& abbrev) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -void -parse(std::basic_istream& is, const CharT* format, - local_time& tp) -{ - parse(is, std::basic_string(format), tp); -} - -template -inline -detail::parse_local_manip -parse(const CharT* format, local_time& tp) -{ - return {format, tp}; -} - -template -inline -void -parse(std::basic_istream& is, const CharT* format, - local_time& tp, std::basic_string& abbrev) -{ - parse(is, std::basic_string(format), tp, abbrev); -} - -template -inline -detail::parse_local_manip -parse(const CharT* format, local_time& tp, - std::basic_string& abbrev) -{ - return {format, tp, &abbrev}; -} - -template -inline -void -parse(std::basic_istream& is, const CharT* format, - local_time& tp, std::chrono::minutes& offset) -{ - parse(is, std::basic_string(format), tp, offset); -} - -template -inline -detail::parse_local_manip -parse(const CharT* format, local_time& tp, std::chrono::minutes& offset) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -void -parse(std::basic_istream& is, const CharT* format, - local_time& tp, std::basic_string& abbrev, - std::chrono::minutes& offset) -{ - parse(is, std::basic_string(format), tp, abbrev, offset); -} - -template -inline -detail::parse_local_manip -parse(const CharT* format, local_time& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) -{ - return {format, tp, &abbrev, &offset}; -} - -template -inline -void -parse(std::basic_istream& is, const CharT* format, - local_time& tp, std::chrono::minutes& offset, - std::basic_string& abbrev) -{ - parse(is, std::basic_string(format), tp, abbrev, offset); -} - -template -inline -detail::parse_local_manip -parse(const CharT* format, local_time& tp, std::chrono::minutes& offset, - std::basic_string& abbrev) -{ - return {format, tp, &abbrev, &offset}; -} - -} // namespace date - -#endif // DATE_H diff --git a/ext/date/ios.h b/ext/date/ios.h deleted file mode 100644 index 3f791bd..0000000 --- a/ext/date/ios.h +++ /dev/null @@ -1,49 +0,0 @@ -// -// ios.h -// DateTimeLib -// -// The MIT License (MIT) -// -// Copyright (c) 2016 Alexander Kormanovsky -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. - -#ifndef ios_hpp -#define ios_hpp - -#if __APPLE__ -# include -# if TARGET_OS_IPHONE -# include - - namespace date - { - namespace iOSUtils - { - - std::string get_tzdata_path(); - - } // namespace iOSUtils - } // namespace date - -# endif // TARGET_OS_IPHONE -#else // !__APPLE__ -# define TARGET_OS_IPHONE 0 -#endif // !__APPLE__ -#endif // ios_hpp diff --git a/ext/date/ios.mm b/ext/date/ios.mm deleted file mode 100644 index ec95302..0000000 --- a/ext/date/ios.mm +++ /dev/null @@ -1,405 +0,0 @@ -// -// The MIT License (MIT) -// -// Copyright (c) 2016 Alexander Kormanovsky -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// - -#include "ios.h" - -#if TARGET_OS_IPHONE - -#include - -#include -#include -#include - -#ifndef TAR_DEBUG -# define TAR_DEBUG 0 -#endif - -#define INTERNAL_DIR "Library/tzdata" -#define TARGZ_EXTENSION "tar.gz" - -#define TAR_BLOCK_SIZE 512 -#define TAR_TYPE_POSITION 156 -#define TAR_NAME_POSITION 0 -#define TAR_NAME_SIZE 100 -#define TAR_SIZE_POSITION 124 -#define TAR_SIZE_SIZE 12 - -namespace date -{ -namespace iOSUtils -{ - -struct TarInfo -{ - char objType; - std::string objName; - int64_t realContentSize; // writable size without padding zeroes - int64_t blocksContentSize; // adjusted size to 512 bytes blocks - bool success; -}; - -char* convertCFStringRefPathToCStringPath(CFStringRef ref); -bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath); -TarInfo getTarObjectInfo(CFReadStreamRef readStream, int64_t location); -std::string getTarObject(CFReadStreamRef readStream, int64_t size); -bool writeFile(CFURLRef tzdataUrl, std::string fileName, std::string data, - int64_t realContentSize); - -std::string -date::iOSUtils::get_tzdata_path() -{ - CFURLRef ref = CFCopyHomeDirectoryURL(); - CFStringRef homePath = CFURLCopyPath(CFCopyHomeDirectoryURL()); - std::string tzdata_path(std::string(convertCFStringRefPathToCStringPath(homePath)) + - INTERNAL_DIR); - - if (access(tzdata_path.c_str(), F_OK) == 0) - { -#if TAR_DEBUG - printf("tzdata exists\n"); -#endif - return tzdata_path; - } - - CFBundleRef mainBundle = CFBundleGetMainBundle(); - CFArrayRef paths = CFBundleCopyResourceURLsOfType(mainBundle, CFSTR(TARGZ_EXTENSION), - NULL); - - if (CFArrayGetCount(paths) != 0) - { - // get archive path, assume there is no other tar.gz in bundle - CFURLRef archiveUrl = static_cast(CFArrayGetValueAtIndex(paths, 0)); - CFStringRef archiveName= CFURLCopyPath(archiveUrl); - archiveUrl = CFBundleCopyResourceURL(mainBundle, archiveName, NULL, NULL); - - extractTzdata(CFCopyHomeDirectoryURL(), archiveUrl, tzdata_path); - } - - return tzdata_path; -} - -char* -convertCFStringRefPathToCStringPath(CFStringRef ref) -{ - CFIndex bufferSize = CFStringGetMaximumSizeOfFileSystemRepresentation(ref); - char *buffer = new char[bufferSize]; - CFStringGetFileSystemRepresentation(ref, buffer, bufferSize); - return buffer; -} - -bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath) -{ - const char *TAR_TMP_PATH = "/tmp.tar"; - - // create Library path - CFStringRef libraryStr = CFStringCreateWithCString(NULL, "Library", - CFStringGetSystemEncoding()); - CFURLRef libraryUrl = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault, - homeUrl, libraryStr, - false); - - // create tzdata path - CFStringRef tzdataPathRef = CFStringCreateWithCString(NULL, INTERNAL_DIR, - CFStringGetSystemEncoding()); - CFURLRef tzdataPathUrl = CFURLCreateCopyAppendingPathComponent(NULL, homeUrl, - tzdataPathRef, false); - - // create src archive path - CFStringRef archivePath = CFURLCopyPath(archiveUrl); - gzFile tarFile = gzopen(convertCFStringRefPathToCStringPath(archivePath), "rb"); - - // create tar unpacking path - CFStringRef tarName = CFStringCreateWithCString(NULL, TAR_TMP_PATH, - CFStringGetSystemEncoding()); - CFURLRef tarUrl = CFURLCreateCopyAppendingPathComponent(NULL, libraryUrl, tarName, - false); - const char *tarPath = convertCFStringRefPathToCStringPath(CFURLCopyPath(tarUrl)); - - // create tzdata directory - mkdir(destPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - - // create stream - CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(NULL, tarUrl); - bool success = true; - - if (!CFWriteStreamOpen(writeStream)) - { - CFStreamError err = CFWriteStreamGetError(writeStream); - - if (err.domain == kCFStreamErrorDomainPOSIX) - { - printf("kCFStreamErrorDomainPOSIX %i\n", err.error); - } - else if(err.domain == kCFStreamErrorDomainMacOSStatus) - { - printf("kCFStreamErrorDomainMacOSStatus %i\n", err.error); - } - - success = false; - } - - if (!success) - { - remove(tarPath); - return false; - } - - // ======= extract tar ======== - - unsigned int bufferLength = 1024 * 256; // 256Kb - void *buffer = malloc(bufferLength); - - while (true) - { - int readBytes = gzread(tarFile, buffer, bufferLength); - - if (readBytes > 0) - { - CFIndex writtenBytes = CFWriteStreamWrite(writeStream, (unsigned char*)buffer, - readBytes); - - if (writtenBytes < 0) - { - CFStreamError err = CFWriteStreamGetError(writeStream); - printf("write stream error %i\n", err.error); - success = false; - break; - } - } - else if (readBytes == 0) - { - break; - } - else if (readBytes == -1) - { - printf("decompression failed\n"); - success = false; - break; - } - else - { - printf("unexpected zlib state\n"); - success = false; - break; - } - } - - CFWriteStreamClose(writeStream); - CFRelease(writeStream); - free(buffer); - gzclose(tarFile); - - if (!success) - { - remove(tarPath); - return false; - } - - // ======== extract files ========= - - uint64_t location = 0; // Position in the file - - // get file size - struct stat stat_buf; - int res = stat(tarPath, &stat_buf); - if (res != 0) - { - printf("error file size\n"); - remove(tarPath); - return false; - } - int64_t tarSize = stat_buf.st_size; - - // create read stream - CFReadStreamRef readStream = CFReadStreamCreateWithFile(kCFAllocatorDefault, tarUrl); - - if (!CFReadStreamOpen(readStream)) - { - CFStreamError err = CFReadStreamGetError(readStream); - - if (err.domain == kCFStreamErrorDomainPOSIX) - { - printf("kCFStreamErrorDomainPOSIX %i", err.error); - } - else if(err.domain == kCFStreamErrorDomainMacOSStatus) - { - printf("kCFStreamErrorDomainMacOSStatus %i", err.error); - } - - success = false; - } - - if (!success) - { - CFRelease(readStream); - remove(tarPath); - return false; - } - - int count = 0; - long size = 0; - - // process files - while (location < tarSize) - { - TarInfo info = getTarObjectInfo(readStream, location); - - if (!info.success || info.realContentSize == 0) - { - break; // something wrong or all files are read - } - - switch (info.objType) - { - case '0': // file - case '\0': // - { - std::string obj = getTarObject(readStream, info.blocksContentSize); -#if TAR_DEBUG - size += info.realContentSize; - printf("#%i %s file size %lld written total %ld from %lld\n", ++count, - info.objName.c_str(), info.realContentSize, size, tarSize); -#endif - writeFile(tzdataPathUrl, info.objName, obj, info.realContentSize); - location += info.blocksContentSize; - - break; - } - } - } - - CFReadStreamClose(readStream); - CFRelease(readStream); - - remove(tarPath); - - return true; -} - -TarInfo -getTarObjectInfo(CFReadStreamRef readStream, int64_t location) -{ - int64_t length = TAR_BLOCK_SIZE; - uint8_t buffer[length]; - - char type; - char name[TAR_NAME_SIZE + 1]; - char sizeBuf[TAR_SIZE_SIZE + 1]; - CFIndex bytesRead; - - bool avail = CFReadStreamHasBytesAvailable(readStream); - - bytesRead = CFReadStreamRead(readStream, buffer, length); - - if (bytesRead < 0) - { - CFStreamError err = CFReadStreamGetError(readStream); - printf("error reading tar object info %i", err.error); - return {false}; - } - - memcpy(&type, &buffer[TAR_TYPE_POSITION], 1); - - memset(&name, '\0', TAR_NAME_SIZE + 1); - memcpy(&name, &buffer[TAR_NAME_POSITION], TAR_NAME_SIZE); - - memset(&sizeBuf, '\0', TAR_SIZE_SIZE + 1); - memcpy(&sizeBuf, &buffer[TAR_SIZE_POSITION], TAR_SIZE_SIZE); - int64_t realSize = strtol(sizeBuf, NULL, 8); - int64_t blocksSize = realSize + (TAR_BLOCK_SIZE - (realSize % TAR_BLOCK_SIZE)); - - return {type, std::string(name), realSize, blocksSize, true}; -} - -std::string -getTarObject(CFReadStreamRef readStream, int64_t size) -{ - uint8_t buffer[size]; - - CFIndex bytesRead = CFReadStreamRead(readStream, buffer, size); - - if (bytesRead < 0) - { - CFStreamError err = CFReadStreamGetError(readStream); - printf("error reading tar object info %i", err.error); - } - - return std::string((char *)buffer); -} - -bool -writeFile(CFURLRef tzdataUrl, std::string fileName, std::string data, - int64_t realContentSize) -{ - // create stream - CFStringRef fileNameRef = CFStringCreateWithCString(NULL, fileName.c_str(), - CFStringGetSystemEncoding()); - CFURLRef url = CFURLCreateCopyAppendingPathComponent(NULL, tzdataUrl, fileNameRef, - false); - CFWriteStreamRef writeStream = CFWriteStreamCreateWithFile(NULL, url); - - // open stream - if (!CFWriteStreamOpen(writeStream)) - { - CFStreamError err = CFWriteStreamGetError(writeStream); - - if (err.domain == kCFStreamErrorDomainPOSIX) - { - printf("kCFStreamErrorDomainPOSIX %i\n", err.error); - } - else if(err.domain == kCFStreamErrorDomainMacOSStatus) - { - printf("kCFStreamErrorDomainMacOSStatus %i\n", err.error); - } - - CFRelease(writeStream); - return false; - } - - // trim empty space - uint8_t trimmedData[realContentSize + 1]; - memset(&trimmedData, '\0', realContentSize); - memcpy(&trimmedData, data.c_str(), realContentSize); - - // write - CFIndex writtenBytes = CFWriteStreamWrite(writeStream, trimmedData, realContentSize); - - if (writtenBytes < 0) - { - CFStreamError err = CFWriteStreamGetError(writeStream); - printf("write stream error %i\n", err.error); - } - - CFWriteStreamClose(writeStream); - CFRelease(writeStream); - writeStream = NULL; - - return true; -} - -} // namespace iOSUtils -} // namespace date - -#endif // TARGET_OS_IPHONE diff --git a/ext/date/julian.h b/ext/date/julian.h deleted file mode 100644 index 696be7c..0000000 --- a/ext/date/julian.h +++ /dev/null @@ -1,3046 +0,0 @@ -#ifndef JULIAN_H -#define JULIAN_H - -// The MIT License (MIT) -// -// Copyright (c) 2016 Howard Hinnant -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// Our apologies. When the previous paragraph was written, lowercase had not yet -// been invented (that woud involve another several millennia of evolution). -// We did not mean to shout. - -#include "date.h" - -namespace julian -{ - -// durations - -using days = date::days; - -using weeks = date::weeks; - -using years = std::chrono::duration - , days::period>>; - -using months = std::chrono::duration - >>; - -// time_point - -using sys_days = date::sys_days; -using local_days = date::local_days; - -// types - -struct last_spec -{ - explicit last_spec() = default; -}; - -class day; -class month; -class year; - -class weekday; -class weekday_indexed; -class weekday_last; - -class month_day; -class month_day_last; -class month_weekday; -class month_weekday_last; - -class year_month; - -class year_month_day; -class year_month_day_last; -class year_month_weekday; -class year_month_weekday_last; - -// date composition operators - -CONSTCD11 year_month operator/(const year& y, const month& m) NOEXCEPT; -CONSTCD11 year_month operator/(const year& y, int m) NOEXCEPT; - -CONSTCD11 month_day operator/(const day& d, const month& m) NOEXCEPT; -CONSTCD11 month_day operator/(const day& d, int m) NOEXCEPT; -CONSTCD11 month_day operator/(const month& m, const day& d) NOEXCEPT; -CONSTCD11 month_day operator/(const month& m, int d) NOEXCEPT; -CONSTCD11 month_day operator/(int m, const day& d) NOEXCEPT; - -CONSTCD11 month_day_last operator/(const month& m, last_spec) NOEXCEPT; -CONSTCD11 month_day_last operator/(int m, last_spec) NOEXCEPT; -CONSTCD11 month_day_last operator/(last_spec, const month& m) NOEXCEPT; -CONSTCD11 month_day_last operator/(last_spec, int m) NOEXCEPT; - -CONSTCD11 month_weekday operator/(const month& m, const weekday_indexed& wdi) NOEXCEPT; -CONSTCD11 month_weekday operator/(int m, const weekday_indexed& wdi) NOEXCEPT; -CONSTCD11 month_weekday operator/(const weekday_indexed& wdi, const month& m) NOEXCEPT; -CONSTCD11 month_weekday operator/(const weekday_indexed& wdi, int m) NOEXCEPT; - -CONSTCD11 month_weekday_last operator/(const month& m, const weekday_last& wdl) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(int m, const weekday_last& wdl) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(const weekday_last& wdl, const month& m) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(const weekday_last& wdl, int m) NOEXCEPT; - -CONSTCD11 year_month_day operator/(const year_month& ym, const day& d) NOEXCEPT; -CONSTCD11 year_month_day operator/(const year_month& ym, int d) NOEXCEPT; -CONSTCD11 year_month_day operator/(const year& y, const month_day& md) NOEXCEPT; -CONSTCD11 year_month_day operator/(int y, const month_day& md) NOEXCEPT; -CONSTCD11 year_month_day operator/(const month_day& md, const year& y) NOEXCEPT; -CONSTCD11 year_month_day operator/(const month_day& md, int y) NOEXCEPT; - -CONSTCD11 - year_month_day_last operator/(const year_month& ym, last_spec) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(const year& y, const month_day_last& mdl) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(int y, const month_day_last& mdl) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(const month_day_last& mdl, const year& y) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(const month_day_last& mdl, int y) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const year_month& ym, const weekday_indexed& wdi) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const year& y, const month_weekday& mwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(int y, const month_weekday& mwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const month_weekday& mwd, const year& y) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const month_weekday& mwd, int y) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const year_month& ym, const weekday_last& wdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const year& y, const month_weekday_last& mwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(int y, const month_weekday_last& mwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const month_weekday_last& mwdl, const year& y) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const month_weekday_last& mwdl, int y) NOEXCEPT; - -// Detailed interface - -// day - -class day -{ - unsigned char d_; - -public: - explicit CONSTCD11 day(unsigned d) NOEXCEPT; - - CONSTCD14 day& operator++() NOEXCEPT; - CONSTCD14 day operator++(int) NOEXCEPT; - CONSTCD14 day& operator--() NOEXCEPT; - CONSTCD14 day operator--(int) NOEXCEPT; - - CONSTCD14 day& operator+=(const days& d) NOEXCEPT; - CONSTCD14 day& operator-=(const days& d) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator< (const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator> (const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const day& x, const day& y) NOEXCEPT; - -CONSTCD11 day operator+(const day& x, const days& y) NOEXCEPT; -CONSTCD11 day operator+(const days& x, const day& y) NOEXCEPT; -CONSTCD11 day operator-(const day& x, const days& y) NOEXCEPT; -CONSTCD11 days operator-(const day& x, const day& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const day& d); - -// month - -class month -{ - unsigned char m_; - -public: - explicit CONSTCD11 month(unsigned m) NOEXCEPT; - - CONSTCD14 month& operator++() NOEXCEPT; - CONSTCD14 month operator++(int) NOEXCEPT; - CONSTCD14 month& operator--() NOEXCEPT; - CONSTCD14 month operator--(int) NOEXCEPT; - - CONSTCD14 month& operator+=(const months& m) NOEXCEPT; - CONSTCD14 month& operator-=(const months& m) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator< (const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator> (const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month& x, const month& y) NOEXCEPT; - -CONSTCD14 month operator+(const month& x, const months& y) NOEXCEPT; -CONSTCD14 month operator+(const months& x, const month& y) NOEXCEPT; -CONSTCD14 month operator-(const month& x, const months& y) NOEXCEPT; -CONSTCD14 months operator-(const month& x, const month& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month& m); - -// year - -class year -{ - short y_; - -public: - explicit CONSTCD11 year(int y) NOEXCEPT; - - CONSTCD14 year& operator++() NOEXCEPT; - CONSTCD14 year operator++(int) NOEXCEPT; - CONSTCD14 year& operator--() NOEXCEPT; - CONSTCD14 year operator--(int) NOEXCEPT; - - CONSTCD14 year& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 bool is_leap() const NOEXCEPT; - - CONSTCD11 explicit operator int() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - - static CONSTCD11 year min() NOEXCEPT; - static CONSTCD11 year max() NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator< (const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator> (const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year& x, const year& y) NOEXCEPT; - -CONSTCD11 year operator+(const year& x, const years& y) NOEXCEPT; -CONSTCD11 year operator+(const years& x, const year& y) NOEXCEPT; -CONSTCD11 year operator-(const year& x, const years& y) NOEXCEPT; -CONSTCD11 years operator-(const year& x, const year& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year& y); - -// weekday - -class weekday -{ - unsigned char wd_; -public: - explicit CONSTCD11 weekday(unsigned wd) NOEXCEPT; - explicit weekday(int) = delete; - CONSTCD11 weekday(const sys_days& dp) NOEXCEPT; - CONSTCD11 explicit weekday(const local_days& dp) NOEXCEPT; - - CONSTCD14 weekday& operator++() NOEXCEPT; - CONSTCD14 weekday operator++(int) NOEXCEPT; - CONSTCD14 weekday& operator--() NOEXCEPT; - CONSTCD14 weekday operator--(int) NOEXCEPT; - - CONSTCD14 weekday& operator+=(const days& d) NOEXCEPT; - CONSTCD14 weekday& operator-=(const days& d) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - - CONSTCD11 weekday_indexed operator[](unsigned index) const NOEXCEPT; - CONSTCD11 weekday_last operator[](last_spec) const NOEXCEPT; - -private: - static CONSTCD11 unsigned char weekday_from_days(int z) NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday& x, const weekday& y) NOEXCEPT; - -CONSTCD14 weekday operator+(const weekday& x, const days& y) NOEXCEPT; -CONSTCD14 weekday operator+(const days& x, const weekday& y) NOEXCEPT; -CONSTCD14 weekday operator-(const weekday& x, const days& y) NOEXCEPT; -CONSTCD14 days operator-(const weekday& x, const weekday& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday& wd); - -// weekday_indexed - -class weekday_indexed -{ - unsigned char wd_ : 4; - unsigned char index_ : 4; - -public: - CONSTCD11 weekday_indexed(const julian::weekday& wd, unsigned index) NOEXCEPT; - - CONSTCD11 julian::weekday weekday() const NOEXCEPT; - CONSTCD11 unsigned index() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_indexed& wdi); - -// weekday_last - -class weekday_last -{ - julian::weekday wd_; - -public: - explicit CONSTCD11 weekday_last(const julian::weekday& wd) NOEXCEPT; - - CONSTCD11 julian::weekday weekday() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday_last& x, const weekday_last& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_last& wdl); - -// year_month - -class year_month -{ - julian::year y_; - julian::month m_; - -public: - CONSTCD11 year_month(const julian::year& y, const julian::month& m) NOEXCEPT; - - CONSTCD11 julian::year year() const NOEXCEPT; - CONSTCD11 julian::month month() const NOEXCEPT; - - CONSTCD14 year_month& operator+=(const months& dm) NOEXCEPT; - CONSTCD14 year_month& operator-=(const months& dm) NOEXCEPT; - CONSTCD14 year_month& operator+=(const years& dy) NOEXCEPT; - CONSTCD14 year_month& operator-=(const years& dy) NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator< (const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator> (const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year_month& x, const year_month& y) NOEXCEPT; - -CONSTCD14 year_month operator+(const year_month& ym, const months& dm) NOEXCEPT; -CONSTCD14 year_month operator+(const months& dm, const year_month& ym) NOEXCEPT; -CONSTCD14 year_month operator-(const year_month& ym, const months& dm) NOEXCEPT; - -CONSTCD11 months operator-(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 year_month operator+(const year_month& ym, const years& dy) NOEXCEPT; -CONSTCD11 year_month operator+(const years& dy, const year_month& ym) NOEXCEPT; -CONSTCD11 year_month operator-(const year_month& ym, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month& ym); - -// month_day - -class month_day -{ - julian::month m_; - julian::day d_; - -public: - CONSTCD11 month_day(const julian::month& m, const julian::day& d) NOEXCEPT; - - CONSTCD11 julian::month month() const NOEXCEPT; - CONSTCD11 julian::day day() const NOEXCEPT; - - CONSTCD14 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator< (const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator> (const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month_day& x, const month_day& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day& md); - -// month_day_last - -class month_day_last -{ - julian::month m_; - -public: - CONSTCD11 explicit month_day_last(const julian::month& m) NOEXCEPT; - - CONSTCD11 julian::month month() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator< (const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator> (const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day_last& mdl); - -// month_weekday - -class month_weekday -{ - julian::month m_; - julian::weekday_indexed wdi_; -public: - CONSTCD11 month_weekday(const julian::month& m, - const julian::weekday_indexed& wdi) NOEXCEPT; - - CONSTCD11 julian::month month() const NOEXCEPT; - CONSTCD11 julian::weekday_indexed weekday_indexed() const NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_weekday& x, const month_weekday& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday& mwd); - -// month_weekday_last - -class month_weekday_last -{ - julian::month m_; - julian::weekday_last wdl_; - -public: - CONSTCD11 month_weekday_last(const julian::month& m, - const julian::weekday_last& wd) NOEXCEPT; - - CONSTCD11 julian::month month() const NOEXCEPT; - CONSTCD11 julian::weekday_last weekday_last() const NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 - bool operator==(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT; -CONSTCD11 - bool operator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday_last& mwdl); - -// class year_month_day - -class year_month_day -{ - julian::year y_; - julian::month m_; - julian::day d_; - -public: - CONSTCD11 year_month_day(const julian::year& y, const julian::month& m, - const julian::day& d) NOEXCEPT; - CONSTCD14 year_month_day(const year_month_day_last& ymdl) NOEXCEPT; - - CONSTCD14 year_month_day(sys_days dp) NOEXCEPT; - CONSTCD14 explicit year_month_day(local_days dp) NOEXCEPT; - - CONSTCD14 year_month_day& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_day& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 julian::year year() const NOEXCEPT; - CONSTCD11 julian::month month() const NOEXCEPT; - CONSTCD11 julian::day day() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD14 bool ok() const NOEXCEPT; - -private: - static CONSTCD14 year_month_day from_days(days dp) NOEXCEPT; - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator< (const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator> (const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year_month_day& x, const year_month_day& y) NOEXCEPT; - -CONSTCD14 year_month_day operator+(const year_month_day& ymd, const months& dm) NOEXCEPT; -CONSTCD14 year_month_day operator+(const months& dm, const year_month_day& ymd) NOEXCEPT; -CONSTCD14 year_month_day operator-(const year_month_day& ymd, const months& dm) NOEXCEPT; -CONSTCD11 year_month_day operator+(const year_month_day& ymd, const years& dy) NOEXCEPT; -CONSTCD11 year_month_day operator+(const years& dy, const year_month_day& ymd) NOEXCEPT; -CONSTCD11 year_month_day operator-(const year_month_day& ymd, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day& ymd); - -// year_month_day_last - -class year_month_day_last -{ - julian::year y_; - julian::month_day_last mdl_; - -public: - CONSTCD11 year_month_day_last(const julian::year& y, - const julian::month_day_last& mdl) NOEXCEPT; - - CONSTCD14 year_month_day_last& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day_last& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day_last& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_day_last& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 julian::year year() const NOEXCEPT; - CONSTCD11 julian::month month() const NOEXCEPT; - CONSTCD11 julian::month_day_last month_day_last() const NOEXCEPT; - CONSTCD14 julian::day day() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 - bool operator==(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator!=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator< (const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator> (const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator<=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; - -CONSTCD14 -year_month_day_last -operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT; - -CONSTCD14 -year_month_day_last -operator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT; - -CONSTCD11 -year_month_day_last -operator+(const year_month_day_last& ymdl, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_day_last -operator+(const years& dy, const year_month_day_last& ymdl) NOEXCEPT; - -CONSTCD14 -year_month_day_last -operator-(const year_month_day_last& ymdl, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_day_last -operator-(const year_month_day_last& ymdl, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day_last& ymdl); - -// year_month_weekday - -class year_month_weekday -{ - julian::year y_; - julian::month m_; - julian::weekday_indexed wdi_; - -public: - CONSTCD11 year_month_weekday(const julian::year& y, const julian::month& m, - const julian::weekday_indexed& wdi) NOEXCEPT; - CONSTCD14 year_month_weekday(const sys_days& dp) NOEXCEPT; - CONSTCD14 explicit year_month_weekday(const local_days& dp) NOEXCEPT; - - CONSTCD14 year_month_weekday& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_weekday& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 julian::year year() const NOEXCEPT; - CONSTCD11 julian::month month() const NOEXCEPT; - CONSTCD11 julian::weekday weekday() const NOEXCEPT; - CONSTCD11 unsigned index() const NOEXCEPT; - CONSTCD11 julian::weekday_indexed weekday_indexed() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD14 bool ok() const NOEXCEPT; - -private: - static CONSTCD14 year_month_weekday from_days(days dp) NOEXCEPT; - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 - bool operator==(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT; -CONSTCD11 - bool operator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT; - -CONSTCD14 -year_month_weekday -operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT; - -CONSTCD14 -year_month_weekday -operator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator+(const year_month_weekday& ymwd, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator+(const years& dy, const year_month_weekday& ymwd) NOEXCEPT; - -CONSTCD14 -year_month_weekday -operator-(const year_month_weekday& ymwd, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator-(const year_month_weekday& ymwd, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday& ymwdi); - -// year_month_weekday_last - -class year_month_weekday_last -{ - julian::year y_; - julian::month m_; - julian::weekday_last wdl_; - -public: - CONSTCD11 year_month_weekday_last(const julian::year& y, const julian::month& m, - const julian::weekday_last& wdl) NOEXCEPT; - - CONSTCD14 year_month_weekday_last& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 julian::year year() const NOEXCEPT; - CONSTCD11 julian::month month() const NOEXCEPT; - CONSTCD11 julian::weekday weekday() const NOEXCEPT; - CONSTCD11 julian::weekday_last weekday_last() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - -private: - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 -bool -operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT; - -CONSTCD11 -bool -operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT; - -CONSTCD14 -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT; - -CONSTCD14 -year_month_weekday_last -operator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator+(const years& dy, const year_month_weekday_last& ymwdl) NOEXCEPT; - -CONSTCD14 -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday_last& ymwdl); - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -inline namespace literals -{ - -CONSTCD11 julian::day operator "" _d(unsigned long long d) NOEXCEPT; -CONSTCD11 julian::year operator "" _y(unsigned long long y) NOEXCEPT; - -// CONSTDATA julian::month jan{1}; -// CONSTDATA julian::month feb{2}; -// CONSTDATA julian::month mar{3}; -// CONSTDATA julian::month apr{4}; -// CONSTDATA julian::month may{5}; -// CONSTDATA julian::month jun{6}; -// CONSTDATA julian::month jul{7}; -// CONSTDATA julian::month aug{8}; -// CONSTDATA julian::month sep{9}; -// CONSTDATA julian::month oct{10}; -// CONSTDATA julian::month nov{11}; -// CONSTDATA julian::month dec{12}; - -} // inline namespace literals -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - -//----------------+ -// Implementation | -//----------------+ - -// day - -CONSTCD11 inline day::day(unsigned d) NOEXCEPT : d_(static_cast(d)) {} -CONSTCD14 inline day& day::operator++() NOEXCEPT {++d_; return *this;} -CONSTCD14 inline day day::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline day& day::operator--() NOEXCEPT {--d_; return *this;} -CONSTCD14 inline day day::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} -CONSTCD14 inline day& day::operator+=(const days& d) NOEXCEPT {*this = *this + d; return *this;} -CONSTCD14 inline day& day::operator-=(const days& d) NOEXCEPT {*this = *this - d; return *this;} -CONSTCD11 inline day::operator unsigned() const NOEXCEPT {return d_;} -CONSTCD11 inline bool day::ok() const NOEXCEPT {return 1 <= d_ && d_ <= 31;} - -CONSTCD11 -inline -bool -operator==(const day& x, const day& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const day& x, const day& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const day& x, const day& y) NOEXCEPT -{ - return static_cast(x) < static_cast(y); -} - -CONSTCD11 -inline -bool -operator>(const day& x, const day& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const day& x, const day& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const day& x, const day& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD11 -inline -days -operator-(const day& x, const day& y) NOEXCEPT -{ - return days{static_cast(static_cast(x) - - static_cast(y))}; -} - -CONSTCD11 -inline -day -operator+(const day& x, const days& y) NOEXCEPT -{ - return day{static_cast(x) + static_cast(y.count())}; -} - -CONSTCD11 -inline -day -operator+(const days& x, const day& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD11 -inline -day -operator-(const day& x, const days& y) NOEXCEPT -{ - return x + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const day& d) -{ - date::detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << static_cast(d); - return os; -} - -// month - -CONSTCD11 inline month::month(unsigned m) NOEXCEPT : m_(static_cast(m)) {} -CONSTCD14 inline month& month::operator++() NOEXCEPT {if (++m_ == 13) m_ = 1; return *this;} -CONSTCD14 inline month month::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline month& month::operator--() NOEXCEPT {if (--m_ == 0) m_ = 12; return *this;} -CONSTCD14 inline month month::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} - -CONSTCD14 -inline -month& -month::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -month& -month::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD11 inline month::operator unsigned() const NOEXCEPT {return m_;} -CONSTCD11 inline bool month::ok() const NOEXCEPT {return 1 <= m_ && m_ <= 12;} - -CONSTCD11 -inline -bool -operator==(const month& x, const month& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const month& x, const month& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const month& x, const month& y) NOEXCEPT -{ - return static_cast(x) < static_cast(y); -} - -CONSTCD11 -inline -bool -operator>(const month& x, const month& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const month& x, const month& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const month& x, const month& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD14 -inline -months -operator-(const month& x, const month& y) NOEXCEPT -{ - auto const d = static_cast(x) - static_cast(y); - return months(d <= 11 ? d : d + 12); -} - -CONSTCD14 -inline -month -operator+(const month& x, const months& y) NOEXCEPT -{ - auto const mu = static_cast(static_cast(x)) - 1 + y.count(); - auto const yr = (mu >= 0 ? mu : mu-11) / 12; - return month{static_cast(mu - yr * 12 + 1)}; -} - -CONSTCD14 -inline -month -operator+(const months& x, const month& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD14 -inline -month -operator-(const month& x, const months& y) NOEXCEPT -{ - return x + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month& m) -{ - switch (static_cast(m)) - { - case 1: - os << "Jan"; - break; - case 2: - os << "Feb"; - break; - case 3: - os << "Mar"; - break; - case 4: - os << "Apr"; - break; - case 5: - os << "May"; - break; - case 6: - os << "Jun"; - break; - case 7: - os << "Jul"; - break; - case 8: - os << "Aug"; - break; - case 9: - os << "Sep"; - break; - case 10: - os << "Oct"; - break; - case 11: - os << "Nov"; - break; - case 12: - os << "Dec"; - break; - default: - os << static_cast(m) << " is not a valid month"; - break; - } - return os; -} - -// year - -CONSTCD11 inline year::year(int y) NOEXCEPT : y_(static_cast(y)) {} -CONSTCD14 inline year& year::operator++() NOEXCEPT {++y_; return *this;} -CONSTCD14 inline year year::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline year& year::operator--() NOEXCEPT {--y_; return *this;} -CONSTCD14 inline year year::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} -CONSTCD14 inline year& year::operator+=(const years& y) NOEXCEPT {*this = *this + y; return *this;} -CONSTCD14 inline year& year::operator-=(const years& y) NOEXCEPT {*this = *this - y; return *this;} - -CONSTCD11 -inline -bool -year::is_leap() const NOEXCEPT -{ - return y_ % 4 == 0; -} - -CONSTCD11 inline year::operator int() const NOEXCEPT {return y_;} -CONSTCD11 inline bool year::ok() const NOEXCEPT {return true;} - -CONSTCD11 -inline -year -year::min() NOEXCEPT -{ - return year{std::numeric_limits::min()}; -} - -CONSTCD11 -inline -year -year::max() NOEXCEPT -{ - return year{std::numeric_limits::max()}; -} - -CONSTCD11 -inline -bool -operator==(const year& x, const year& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const year& x, const year& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year& x, const year& y) NOEXCEPT -{ - return static_cast(x) < static_cast(y); -} - -CONSTCD11 -inline -bool -operator>(const year& x, const year& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year& x, const year& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year& x, const year& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD11 -inline -years -operator-(const year& x, const year& y) NOEXCEPT -{ - return years{static_cast(x) - static_cast(y)}; -} - -CONSTCD11 -inline -year -operator+(const year& x, const years& y) NOEXCEPT -{ - return year{static_cast(x) + y.count()}; -} - -CONSTCD11 -inline -year -operator+(const years& x, const year& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD11 -inline -year -operator-(const year& x, const years& y) NOEXCEPT -{ - return year{static_cast(x) - y.count()}; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year& y) -{ - date::detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::internal); - os.width(4 + (y < year{0})); - os << static_cast(y); - return os; -} - -// weekday - -CONSTCD11 -inline -unsigned char -weekday::weekday_from_days(int z) NOEXCEPT -{ - return static_cast(static_cast( - z >= -4 ? (z+4) % 7 : (z+5) % 7 + 6)); -} - -CONSTCD11 -inline -weekday::weekday(unsigned wd) NOEXCEPT - : wd_(static_cast(wd)) - {} - -CONSTCD11 -inline -weekday::weekday(const sys_days& dp) NOEXCEPT - : wd_(weekday_from_days(dp.time_since_epoch().count())) - {} - -CONSTCD11 -inline -weekday::weekday(const local_days& dp) NOEXCEPT - : wd_(weekday_from_days(dp.time_since_epoch().count())) - {} - -CONSTCD14 inline weekday& weekday::operator++() NOEXCEPT {if (++wd_ == 7) wd_ = 0; return *this;} -CONSTCD14 inline weekday weekday::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline weekday& weekday::operator--() NOEXCEPT {if (wd_-- == 0) wd_ = 6; return *this;} -CONSTCD14 inline weekday weekday::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} - -CONSTCD14 -inline -weekday& -weekday::operator+=(const days& d) NOEXCEPT -{ - *this = *this + d; - return *this; -} - -CONSTCD14 -inline -weekday& -weekday::operator-=(const days& d) NOEXCEPT -{ - *this = *this - d; - return *this; -} - -CONSTCD11 -inline -weekday::operator unsigned() const NOEXCEPT -{ - return static_cast(wd_); -} - -CONSTCD11 inline bool weekday::ok() const NOEXCEPT {return wd_ <= 6;} - -CONSTCD11 -inline -bool -operator==(const weekday& x, const weekday& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const weekday& x, const weekday& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD14 -inline -days -operator-(const weekday& x, const weekday& y) NOEXCEPT -{ - auto const diff = static_cast(x) - static_cast(y); - return days{diff <= 6 ? diff : diff + 7}; -} - -CONSTCD14 -inline -weekday -operator+(const weekday& x, const days& y) NOEXCEPT -{ - auto const wdu = static_cast(static_cast(x)) + y.count(); - auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7; - return weekday{static_cast(wdu - wk * 7)}; -} - -CONSTCD14 -inline -weekday -operator+(const days& x, const weekday& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD14 -inline -weekday -operator-(const weekday& x, const days& y) NOEXCEPT -{ - return x + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday& wd) -{ - switch (static_cast(wd)) - { - case 0: - os << "Sun"; - break; - case 1: - os << "Mon"; - break; - case 2: - os << "Tue"; - break; - case 3: - os << "Wed"; - break; - case 4: - os << "Thu"; - break; - case 5: - os << "Fri"; - break; - case 6: - os << "Sat"; - break; - default: - os << static_cast(wd) << " is not a valid weekday"; - break; - } - return os; -} - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -inline namespace literals -{ - -CONSTCD11 -inline -julian::day -operator "" _d(unsigned long long d) NOEXCEPT -{ - return julian::day{static_cast(d)}; -} - -CONSTCD11 -inline -julian::year -operator "" _y(unsigned long long y) NOEXCEPT -{ - return julian::year(static_cast(y)); -} -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - -CONSTDATA julian::last_spec last{}; - -CONSTDATA julian::month jan{1}; -CONSTDATA julian::month feb{2}; -CONSTDATA julian::month mar{3}; -CONSTDATA julian::month apr{4}; -CONSTDATA julian::month may{5}; -CONSTDATA julian::month jun{6}; -CONSTDATA julian::month jul{7}; -CONSTDATA julian::month aug{8}; -CONSTDATA julian::month sep{9}; -CONSTDATA julian::month oct{10}; -CONSTDATA julian::month nov{11}; -CONSTDATA julian::month dec{12}; - -CONSTDATA julian::weekday sun{0u}; -CONSTDATA julian::weekday mon{1u}; -CONSTDATA julian::weekday tue{2u}; -CONSTDATA julian::weekday wed{3u}; -CONSTDATA julian::weekday thu{4u}; -CONSTDATA julian::weekday fri{5u}; -CONSTDATA julian::weekday sat{6u}; - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -} // inline namespace literals -#endif - -// weekday_indexed - -CONSTCD11 -inline -weekday -weekday_indexed::weekday() const NOEXCEPT -{ - return julian::weekday{static_cast(wd_)}; -} - -CONSTCD11 inline unsigned weekday_indexed::index() const NOEXCEPT {return index_;} - -CONSTCD11 -inline -bool -weekday_indexed::ok() const NOEXCEPT -{ - return weekday().ok() && 1 <= index_ && index_ <= 5; -} - -CONSTCD11 -inline -weekday_indexed::weekday_indexed(const julian::weekday& wd, unsigned index) NOEXCEPT - : wd_(static_cast(static_cast(wd))) - , index_(static_cast(index)) - {} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_indexed& wdi) -{ - return os << wdi.weekday() << '[' << wdi.index() << ']'; -} - -CONSTCD11 -inline -weekday_indexed -weekday::operator[](unsigned index) const NOEXCEPT -{ - return {*this, index}; -} - -CONSTCD11 -inline -bool -operator==(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT -{ - return x.weekday() == y.weekday() && x.index() == y.index(); -} - -CONSTCD11 -inline -bool -operator!=(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT -{ - return !(x == y); -} - -// weekday_last - -CONSTCD11 inline julian::weekday weekday_last::weekday() const NOEXCEPT {return wd_;} -CONSTCD11 inline bool weekday_last::ok() const NOEXCEPT {return wd_.ok();} -CONSTCD11 inline weekday_last::weekday_last(const julian::weekday& wd) NOEXCEPT : wd_(wd) {} - -CONSTCD11 -inline -bool -operator==(const weekday_last& x, const weekday_last& y) NOEXCEPT -{ - return x.weekday() == y.weekday(); -} - -CONSTCD11 -inline -bool -operator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_last& wdl) -{ - return os << wdl.weekday() << "[last]"; -} - -CONSTCD11 -inline -weekday_last -weekday::operator[](last_spec) const NOEXCEPT -{ - return weekday_last{*this}; -} - -// year_month - -CONSTCD11 -inline -year_month::year_month(const julian::year& y, const julian::month& m) NOEXCEPT - : y_(y) - , m_(m) - {} - -CONSTCD11 inline year year_month::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month::month() const NOEXCEPT {return m_;} -CONSTCD11 inline bool year_month::ok() const NOEXCEPT {return y_.ok() && m_.ok();} - -CONSTCD14 -inline -year_month& -year_month::operator+=(const months& dm) NOEXCEPT -{ - *this = *this + dm; - return *this; -} - -CONSTCD14 -inline -year_month& -year_month::operator-=(const months& dm) NOEXCEPT -{ - *this = *this - dm; - return *this; -} - -CONSTCD14 -inline -year_month& -year_month::operator+=(const years& dy) NOEXCEPT -{ - *this = *this + dy; - return *this; -} - -CONSTCD14 -inline -year_month& -year_month::operator-=(const years& dy) NOEXCEPT -{ - *this = *this - dy; - return *this; -} - -CONSTCD11 -inline -bool -operator==(const year_month& x, const year_month& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month& x, const year_month& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_month& x, const year_month& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (x.month() < y.month())); -} - -CONSTCD11 -inline -bool -operator>(const year_month& x, const year_month& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_month& x, const year_month& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_month& x, const year_month& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD14 -inline -year_month -operator+(const year_month& ym, const months& dm) NOEXCEPT -{ - auto dmi = static_cast(static_cast(ym.month())) - 1 + dm.count(); - auto dy = (dmi >= 0 ? dmi : dmi-11) / 12; - dmi = dmi - dy * 12 + 1; - return (ym.year() + years(dy)) / month(static_cast(dmi)); -} - -CONSTCD14 -inline -year_month -operator+(const months& dm, const year_month& ym) NOEXCEPT -{ - return ym + dm; -} - -CONSTCD14 -inline -year_month -operator-(const year_month& ym, const months& dm) NOEXCEPT -{ - return ym + -dm; -} - -CONSTCD11 -inline -months -operator-(const year_month& x, const year_month& y) NOEXCEPT -{ - return (x.year() - y.year()) + - months(static_cast(x.month()) - static_cast(y.month())); -} - -CONSTCD11 -inline -year_month -operator+(const year_month& ym, const years& dy) NOEXCEPT -{ - return (ym.year() + dy) / ym.month(); -} - -CONSTCD11 -inline -year_month -operator+(const years& dy, const year_month& ym) NOEXCEPT -{ - return ym + dy; -} - -CONSTCD11 -inline -year_month -operator-(const year_month& ym, const years& dy) NOEXCEPT -{ - return ym + -dy; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month& ym) -{ - return os << ym.year() << '/' << ym.month(); -} - -// month_day - -CONSTCD11 -inline -month_day::month_day(const julian::month& m, const julian::day& d) NOEXCEPT - : m_(m) - , d_(d) - {} - -CONSTCD11 inline julian::month month_day::month() const NOEXCEPT {return m_;} -CONSTCD11 inline julian::day month_day::day() const NOEXCEPT {return d_;} - -CONSTCD14 -inline -bool -month_day::ok() const NOEXCEPT -{ - CONSTDATA julian::day d[] = - {31_d, 29_d, 31_d, 30_d, 31_d, 30_d, 31_d, 31_d, 30_d, 31_d, 30_d, 31_d}; - return m_.ok() && 1_d <= d_ && d_ <= d[static_cast(m_)-1]; -} - -CONSTCD11 -inline -bool -operator==(const month_day& x, const month_day& y) NOEXCEPT -{ - return x.month() == y.month() && x.day() == y.day(); -} - -CONSTCD11 -inline -bool -operator!=(const month_day& x, const month_day& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const month_day& x, const month_day& y) NOEXCEPT -{ - return x.month() < y.month() ? true - : (x.month() > y.month() ? false - : (x.day() < y.day())); -} - -CONSTCD11 -inline -bool -operator>(const month_day& x, const month_day& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const month_day& x, const month_day& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const month_day& x, const month_day& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day& md) -{ - return os << md.month() << '/' << md.day(); -} - -// month_day_last - -CONSTCD11 inline month month_day_last::month() const NOEXCEPT {return m_;} -CONSTCD11 inline bool month_day_last::ok() const NOEXCEPT {return m_.ok();} -CONSTCD11 inline month_day_last::month_day_last(const julian::month& m) NOEXCEPT : m_(m) {} - -CONSTCD11 -inline -bool -operator==(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return x.month() == y.month(); -} - -CONSTCD11 -inline -bool -operator!=(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return x.month() < y.month(); -} - -CONSTCD11 -inline -bool -operator>(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day_last& mdl) -{ - return os << mdl.month() << "/last"; -} - -// month_weekday - -CONSTCD11 -inline -month_weekday::month_weekday(const julian::month& m, - const julian::weekday_indexed& wdi) NOEXCEPT - : m_(m) - , wdi_(wdi) - {} - -CONSTCD11 inline month month_weekday::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday_indexed -month_weekday::weekday_indexed() const NOEXCEPT -{ - return wdi_; -} - -CONSTCD11 -inline -bool -month_weekday::ok() const NOEXCEPT -{ - return m_.ok() && wdi_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const month_weekday& x, const month_weekday& y) NOEXCEPT -{ - return x.month() == y.month() && x.weekday_indexed() == y.weekday_indexed(); -} - -CONSTCD11 -inline -bool -operator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday& mwd) -{ - return os << mwd.month() << '/' << mwd.weekday_indexed(); -} - -// month_weekday_last - -CONSTCD11 -inline -month_weekday_last::month_weekday_last(const julian::month& m, - const julian::weekday_last& wdl) NOEXCEPT - : m_(m) - , wdl_(wdl) - {} - -CONSTCD11 inline month month_weekday_last::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday_last -month_weekday_last::weekday_last() const NOEXCEPT -{ - return wdl_; -} - -CONSTCD11 -inline -bool -month_weekday_last::ok() const NOEXCEPT -{ - return m_.ok() && wdl_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT -{ - return x.month() == y.month() && x.weekday_last() == y.weekday_last(); -} - -CONSTCD11 -inline -bool -operator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday_last& mwdl) -{ - return os << mwdl.month() << '/' << mwdl.weekday_last(); -} - -// year_month_day_last - -CONSTCD11 -inline -year_month_day_last::year_month_day_last(const julian::year& y, - const julian::month_day_last& mdl) NOEXCEPT - : y_(y) - , mdl_(mdl) - {} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_day_last::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_day_last::month() const NOEXCEPT {return mdl_.month();} - -CONSTCD11 -inline -month_day_last -year_month_day_last::month_day_last() const NOEXCEPT -{ - return mdl_; -} - -CONSTCD14 -inline -day -year_month_day_last::day() const NOEXCEPT -{ - CONSTDATA julian::day d[] = - {31_d, 28_d, 31_d, 30_d, 31_d, 30_d, 31_d, 31_d, 30_d, 31_d, 30_d, 31_d}; - return month() != feb || !y_.is_leap() ? d[static_cast(month())-1] : 29_d; -} - -CONSTCD14 -inline -year_month_day_last::operator sys_days() const NOEXCEPT -{ - return sys_days(year()/month()/day()); -} - -CONSTCD14 -inline -year_month_day_last::operator local_days() const NOEXCEPT -{ - return local_days(year()/month()/day()); -} - -CONSTCD11 -inline -bool -year_month_day_last::ok() const NOEXCEPT -{ - return y_.ok() && mdl_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return x.year() == y.year() && x.month_day_last() == y.month_day_last(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (x.month_day_last() < y.month_day_last())); -} - -CONSTCD11 -inline -bool -operator>(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day_last& ymdl) -{ - return os << ymdl.year() << '/' << ymdl.month_day_last(); -} - -CONSTCD14 -inline -year_month_day_last -operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT -{ - return (ymdl.year() / ymdl.month() + dm) / last; -} - -CONSTCD14 -inline -year_month_day_last -operator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT -{ - return ymdl + dm; -} - -CONSTCD14 -inline -year_month_day_last -operator-(const year_month_day_last& ymdl, const months& dm) NOEXCEPT -{ - return ymdl + (-dm); -} - -CONSTCD11 -inline -year_month_day_last -operator+(const year_month_day_last& ymdl, const years& dy) NOEXCEPT -{ - return {ymdl.year()+dy, ymdl.month_day_last()}; -} - -CONSTCD11 -inline -year_month_day_last -operator+(const years& dy, const year_month_day_last& ymdl) NOEXCEPT -{ - return ymdl + dy; -} - -CONSTCD11 -inline -year_month_day_last -operator-(const year_month_day_last& ymdl, const years& dy) NOEXCEPT -{ - return ymdl + (-dy); -} - -// year_month_day - -CONSTCD11 -inline -year_month_day::year_month_day(const julian::year& y, const julian::month& m, - const julian::day& d) NOEXCEPT - : y_(y) - , m_(m) - , d_(d) - {} - -CONSTCD14 -inline -year_month_day::year_month_day(const year_month_day_last& ymdl) NOEXCEPT - : y_(ymdl.year()) - , m_(ymdl.month()) - , d_(ymdl.day()) - {} - -CONSTCD14 -inline -year_month_day::year_month_day(sys_days dp) NOEXCEPT - : year_month_day(from_days(dp.time_since_epoch())) - {} - -CONSTCD14 -inline -year_month_day::year_month_day(local_days dp) NOEXCEPT - : year_month_day(from_days(dp.time_since_epoch())) - {} - -CONSTCD11 inline year year_month_day::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_day::month() const NOEXCEPT {return m_;} -CONSTCD11 inline day year_month_day::day() const NOEXCEPT {return d_;} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD14 -inline -days -year_month_day::to_days() const NOEXCEPT -{ - static_assert(std::numeric_limits::digits >= 18, - "This algorithm has not been ported to a 16 bit unsigned integer"); - static_assert(std::numeric_limits::digits >= 20, - "This algorithm has not been ported to a 16 bit signed integer"); - auto const y = static_cast(y_) - (m_ <= feb); - auto const m = static_cast(m_); - auto const d = static_cast(d_); - auto const era = (y >= 0 ? y : y-3) / 4; - auto const yoe = static_cast(y - era * 4); // [0, 3] - auto const doy = (153*(m > 2 ? m-3 : m+9) + 2)/5 + d-1; // [0, 365] - auto const doe = yoe * 365 + doy; // [0, 1460] - return days{era * 1461 + static_cast(doe) - 719470}; -} - -CONSTCD14 -inline -year_month_day::operator sys_days() const NOEXCEPT -{ - return sys_days{to_days()}; -} - -CONSTCD14 -inline -year_month_day::operator local_days() const NOEXCEPT -{ - return local_days{to_days()}; -} - -CONSTCD14 -inline -bool -year_month_day::ok() const NOEXCEPT -{ - if (!(y_.ok() && m_.ok())) - return false; - return 1_d <= d_ && d_ <= (y_/m_/last).day(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month() && x.day() == y.day(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (x.month() < y.month() ? true - : (x.month() > y.month() ? false - : (x.day() < y.day())))); -} - -CONSTCD11 -inline -bool -operator>(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day& ymd) -{ - date::detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os << ymd.year() << '-'; - os.width(2); - os << static_cast(ymd.month()) << '-'; - os << ymd.day(); - return os; -} - -CONSTCD14 -inline -year_month_day -year_month_day::from_days(days dp) NOEXCEPT -{ - static_assert(std::numeric_limits::digits >= 18, - "This algorithm has not been ported to a 16 bit unsigned integer"); - static_assert(std::numeric_limits::digits >= 20, - "This algorithm has not been ported to a 16 bit signed integer"); - auto const z = dp.count() + 719470; - auto const era = (z >= 0 ? z : z - 1460) / 1461; - auto const doe = static_cast(z - era * 1461); // [0, 1460] - auto const yoe = (doe - doe/1460) / 365; // [0, 3] - auto const y = static_cast(yoe) + era * 4; - auto const doy = doe - 365*yoe; // [0, 365] - auto const mp = (5*doy + 2)/153; // [0, 11] - auto const d = doy - (153*mp+2)/5 + 1; // [1, 31] - auto const m = mp < 10 ? mp+3 : mp-9; // [1, 12] - return year_month_day{julian::year{y + (m <= 2)}, julian::month(m), julian::day(d)}; -} - -CONSTCD14 -inline -year_month_day -operator+(const year_month_day& ymd, const months& dm) NOEXCEPT -{ - return (ymd.year() / ymd.month() + dm) / ymd.day(); -} - -CONSTCD14 -inline -year_month_day -operator+(const months& dm, const year_month_day& ymd) NOEXCEPT -{ - return ymd + dm; -} - -CONSTCD14 -inline -year_month_day -operator-(const year_month_day& ymd, const months& dm) NOEXCEPT -{ - return ymd + (-dm); -} - -CONSTCD11 -inline -year_month_day -operator+(const year_month_day& ymd, const years& dy) NOEXCEPT -{ - return (ymd.year() + dy) / ymd.month() / ymd.day(); -} - -CONSTCD11 -inline -year_month_day -operator+(const years& dy, const year_month_day& ymd) NOEXCEPT -{ - return ymd + dy; -} - -CONSTCD11 -inline -year_month_day -operator-(const year_month_day& ymd, const years& dy) NOEXCEPT -{ - return ymd + (-dy); -} - -// year_month_weekday - -CONSTCD11 -inline -year_month_weekday::year_month_weekday(const julian::year& y, const julian::month& m, - const julian::weekday_indexed& wdi) - NOEXCEPT - : y_(y) - , m_(m) - , wdi_(wdi) - {} - -CONSTCD14 -inline -year_month_weekday::year_month_weekday(const sys_days& dp) NOEXCEPT - : year_month_weekday(from_days(dp.time_since_epoch())) - {} - -CONSTCD14 -inline -year_month_weekday::year_month_weekday(const local_days& dp) NOEXCEPT - : year_month_weekday(from_days(dp.time_since_epoch())) - {} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_weekday::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_weekday::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday -year_month_weekday::weekday() const NOEXCEPT -{ - return wdi_.weekday(); -} - -CONSTCD11 -inline -unsigned -year_month_weekday::index() const NOEXCEPT -{ - return wdi_.index(); -} - -CONSTCD11 -inline -weekday_indexed -year_month_weekday::weekday_indexed() const NOEXCEPT -{ - return wdi_; -} - -CONSTCD14 -inline -year_month_weekday::operator sys_days() const NOEXCEPT -{ - return sys_days{to_days()}; -} - -CONSTCD14 -inline -year_month_weekday::operator local_days() const NOEXCEPT -{ - return local_days{to_days()}; -} - -CONSTCD14 -inline -bool -year_month_weekday::ok() const NOEXCEPT -{ - if (!y_.ok() || !m_.ok() || !wdi_.weekday().ok() || wdi_.index() < 1) - return false; - if (wdi_.index() <= 4) - return true; - auto d2 = wdi_.weekday() - julian::weekday(y_/m_/1) + days((wdi_.index()-1)*7 + 1); - return static_cast(d2.count()) <= static_cast((y_/m_/last).day()); -} - -CONSTCD14 -inline -year_month_weekday -year_month_weekday::from_days(days d) NOEXCEPT -{ - sys_days dp{d}; - auto const wd = julian::weekday(dp); - auto const ymd = year_month_day(dp); - return {ymd.year(), ymd.month(), wd[(static_cast(ymd.day())-1)/7+1]}; -} - -CONSTCD14 -inline -days -year_month_weekday::to_days() const NOEXCEPT -{ - auto d = sys_days(y_/m_/1); - return (d + (wdi_.weekday() - julian::weekday(d) + days{(wdi_.index()-1)*7}) - ).time_since_epoch(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month() && - x.weekday_indexed() == y.weekday_indexed(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday& ymwdi) -{ - return os << ymwdi.year() << '/' << ymwdi.month() - << '/' << ymwdi.weekday_indexed(); -} - -CONSTCD14 -inline -year_month_weekday -operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT -{ - return (ymwd.year() / ymwd.month() + dm) / ymwd.weekday_indexed(); -} - -CONSTCD14 -inline -year_month_weekday -operator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT -{ - return ymwd + dm; -} - -CONSTCD14 -inline -year_month_weekday -operator-(const year_month_weekday& ymwd, const months& dm) NOEXCEPT -{ - return ymwd + (-dm); -} - -CONSTCD11 -inline -year_month_weekday -operator+(const year_month_weekday& ymwd, const years& dy) NOEXCEPT -{ - return {ymwd.year()+dy, ymwd.month(), ymwd.weekday_indexed()}; -} - -CONSTCD11 -inline -year_month_weekday -operator+(const years& dy, const year_month_weekday& ymwd) NOEXCEPT -{ - return ymwd + dy; -} - -CONSTCD11 -inline -year_month_weekday -operator-(const year_month_weekday& ymwd, const years& dy) NOEXCEPT -{ - return ymwd + (-dy); -} - -// year_month_weekday_last - -CONSTCD11 -inline -year_month_weekday_last::year_month_weekday_last(const julian::year& y, - const julian::month& m, - const julian::weekday_last& wdl) NOEXCEPT - : y_(y) - , m_(m) - , wdl_(wdl) - {} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_weekday_last::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_weekday_last::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday -year_month_weekday_last::weekday() const NOEXCEPT -{ - return wdl_.weekday(); -} - -CONSTCD11 -inline -weekday_last -year_month_weekday_last::weekday_last() const NOEXCEPT -{ - return wdl_; -} - -CONSTCD14 -inline -year_month_weekday_last::operator sys_days() const NOEXCEPT -{ - return sys_days{to_days()}; -} - -CONSTCD14 -inline -year_month_weekday_last::operator local_days() const NOEXCEPT -{ - return local_days{to_days()}; -} - -CONSTCD11 -inline -bool -year_month_weekday_last::ok() const NOEXCEPT -{ - return y_.ok() && m_.ok() && wdl_.ok(); -} - -CONSTCD14 -inline -days -year_month_weekday_last::to_days() const NOEXCEPT -{ - auto const d = sys_days(y_/m_/last); - return (d - (julian::weekday{d} - wdl_.weekday())).time_since_epoch(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month() && - x.weekday_last() == y.weekday_last(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday_last& ymwdl) -{ - return os << ymwdl.year() << '/' << ymwdl.month() << '/' << ymwdl.weekday_last(); -} - -CONSTCD14 -inline -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT -{ - return (ymwdl.year() / ymwdl.month() + dm) / ymwdl.weekday_last(); -} - -CONSTCD14 -inline -year_month_weekday_last -operator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT -{ - return ymwdl + dm; -} - -CONSTCD14 -inline -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT -{ - return ymwdl + (-dm); -} - -CONSTCD11 -inline -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT -{ - return {ymwdl.year()+dy, ymwdl.month(), ymwdl.weekday_last()}; -} - -CONSTCD11 -inline -year_month_weekday_last -operator+(const years& dy, const year_month_weekday_last& ymwdl) NOEXCEPT -{ - return ymwdl + dy; -} - -CONSTCD11 -inline -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT -{ - return ymwdl + (-dy); -} - -// year_month from operator/() - -CONSTCD11 -inline -year_month -operator/(const year& y, const month& m) NOEXCEPT -{ - return {y, m}; -} - -CONSTCD11 -inline -year_month -operator/(const year& y, int m) NOEXCEPT -{ - return y / month(static_cast(m)); -} - -// month_day from operator/() - -CONSTCD11 -inline -month_day -operator/(const month& m, const day& d) NOEXCEPT -{ - return {m, d}; -} - -CONSTCD11 -inline -month_day -operator/(const day& d, const month& m) NOEXCEPT -{ - return m / d; -} - -CONSTCD11 -inline -month_day -operator/(const month& m, int d) NOEXCEPT -{ - return m / day(static_cast(d)); -} - -CONSTCD11 -inline -month_day -operator/(int m, const day& d) NOEXCEPT -{ - return month(static_cast(m)) / d; -} - -CONSTCD11 inline month_day operator/(const day& d, int m) NOEXCEPT {return m / d;} - -// month_day_last from operator/() - -CONSTCD11 -inline -month_day_last -operator/(const month& m, last_spec) NOEXCEPT -{ - return month_day_last{m}; -} - -CONSTCD11 -inline -month_day_last -operator/(last_spec, const month& m) NOEXCEPT -{ - return m/last; -} - -CONSTCD11 -inline -month_day_last -operator/(int m, last_spec) NOEXCEPT -{ - return month(static_cast(m))/last; -} - -CONSTCD11 -inline -month_day_last -operator/(last_spec, int m) NOEXCEPT -{ - return m/last; -} - -// month_weekday from operator/() - -CONSTCD11 -inline -month_weekday -operator/(const month& m, const weekday_indexed& wdi) NOEXCEPT -{ - return {m, wdi}; -} - -CONSTCD11 -inline -month_weekday -operator/(const weekday_indexed& wdi, const month& m) NOEXCEPT -{ - return m / wdi; -} - -CONSTCD11 -inline -month_weekday -operator/(int m, const weekday_indexed& wdi) NOEXCEPT -{ - return month(static_cast(m)) / wdi; -} - -CONSTCD11 -inline -month_weekday -operator/(const weekday_indexed& wdi, int m) NOEXCEPT -{ - return m / wdi; -} - -// month_weekday_last from operator/() - -CONSTCD11 -inline -month_weekday_last -operator/(const month& m, const weekday_last& wdl) NOEXCEPT -{ - return {m, wdl}; -} - -CONSTCD11 -inline -month_weekday_last -operator/(const weekday_last& wdl, const month& m) NOEXCEPT -{ - return m / wdl; -} - -CONSTCD11 -inline -month_weekday_last -operator/(int m, const weekday_last& wdl) NOEXCEPT -{ - return month(static_cast(m)) / wdl; -} - -CONSTCD11 -inline -month_weekday_last -operator/(const weekday_last& wdl, int m) NOEXCEPT -{ - return m / wdl; -} - -// year_month_day from operator/() - -CONSTCD11 -inline -year_month_day -operator/(const year_month& ym, const day& d) NOEXCEPT -{ - return {ym.year(), ym.month(), d}; -} - -CONSTCD11 -inline -year_month_day -operator/(const year_month& ym, int d) NOEXCEPT -{ - return ym / day(static_cast(d)); -} - -CONSTCD11 -inline -year_month_day -operator/(const year& y, const month_day& md) NOEXCEPT -{ - return y / md.month() / md.day(); -} - -CONSTCD11 -inline -year_month_day -operator/(int y, const month_day& md) NOEXCEPT -{ - return year(y) / md; -} - -CONSTCD11 -inline -year_month_day -operator/(const month_day& md, const year& y) NOEXCEPT -{ - return y / md; -} - -CONSTCD11 -inline -year_month_day -operator/(const month_day& md, int y) NOEXCEPT -{ - return year(y) / md; -} - -// year_month_day_last from operator/() - -CONSTCD11 -inline -year_month_day_last -operator/(const year_month& ym, last_spec) NOEXCEPT -{ - return {ym.year(), month_day_last{ym.month()}}; -} - -CONSTCD11 -inline -year_month_day_last -operator/(const year& y, const month_day_last& mdl) NOEXCEPT -{ - return {y, mdl}; -} - -CONSTCD11 -inline -year_month_day_last -operator/(int y, const month_day_last& mdl) NOEXCEPT -{ - return year(y) / mdl; -} - -CONSTCD11 -inline -year_month_day_last -operator/(const month_day_last& mdl, const year& y) NOEXCEPT -{ - return y / mdl; -} - -CONSTCD11 -inline -year_month_day_last -operator/(const month_day_last& mdl, int y) NOEXCEPT -{ - return year(y) / mdl; -} - -// year_month_weekday from operator/() - -CONSTCD11 -inline -year_month_weekday -operator/(const year_month& ym, const weekday_indexed& wdi) NOEXCEPT -{ - return {ym.year(), ym.month(), wdi}; -} - -CONSTCD11 -inline -year_month_weekday -operator/(const year& y, const month_weekday& mwd) NOEXCEPT -{ - return {y, mwd.month(), mwd.weekday_indexed()}; -} - -CONSTCD11 -inline -year_month_weekday -operator/(int y, const month_weekday& mwd) NOEXCEPT -{ - return year(y) / mwd; -} - -CONSTCD11 -inline -year_month_weekday -operator/(const month_weekday& mwd, const year& y) NOEXCEPT -{ - return y / mwd; -} - -CONSTCD11 -inline -year_month_weekday -operator/(const month_weekday& mwd, int y) NOEXCEPT -{ - return year(y) / mwd; -} - -// year_month_weekday_last from operator/() - -CONSTCD11 -inline -year_month_weekday_last -operator/(const year_month& ym, const weekday_last& wdl) NOEXCEPT -{ - return {ym.year(), ym.month(), wdl}; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(const year& y, const month_weekday_last& mwdl) NOEXCEPT -{ - return {y, mwdl.month(), mwdl.weekday_last()}; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(int y, const month_weekday_last& mwdl) NOEXCEPT -{ - return year(y) / mwdl; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(const month_weekday_last& mwdl, const year& y) NOEXCEPT -{ - return y / mwdl; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(const month_weekday_last& mwdl, int y) NOEXCEPT -{ - return year(y) / mwdl; -} - -} // namespace julian - -#endif // JULIAN_H diff --git a/ext/date/tz.cpp b/ext/date/tz.cpp deleted file mode 100644 index e3c4da7..0000000 --- a/ext/date/tz.cpp +++ /dev/null @@ -1,3120 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// Copyright (c) 2015 Ville Voutilainen -// Copyright (c) 2016 Alexander Kormanovsky -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// Our apologies. When the previous paragraph was written, lowercase had not yet -// been invented (that woud involve another several millennia of evolution). -// We did not mean to shout. - -#ifdef _WIN32 -// Windows.h will be included directly and indirectly (e.g. by curl). -// We need to define these macros to prevent Windows.h bringing in -// more than we need and do it eearly so Windows.h doesn't get included -// without these macros having been defined. -// min/max macrosinterfere with the C++ versions. -#ifndef NOMINMAX -#define NOMINMAX -#endif -// We don't need all that Windows has to offer. -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif // _WIN32 - -// None of this happens with the MS SDK (at least VS14 which I tested), but: -// Compiling with mingw, we get "error: 'KF_FLAG_DEFAULT' was not declared in this scope." -// and error: 'SHGetKnownFolderPath' was not declared in this scope.". -// It seems when using mingw NTDDI_VERSION is undefined and that -// causes KNOWN_FOLDER_FLAG and the KF_ flags to not get defined. -// So we must define NTDDI_VERSION to get those flags on mingw. -// The docs say though here: -// https://msdn.microsoft.com/en-nz/library/windows/desktop/aa383745(v=vs.85).aspx -// that "If you define NTDDI_VERSION, you must also define _WIN32_WINNT." -// So we declare we require Vista or greater. -#ifdef __MINGW32__ - -#ifndef NTDDI_VERSION -#define NTDDI_VERSION 0x06000000 -#define _WIN32_WINNT _WIN32_WINNT_VISTA -#elif NTDDI_VERSION < 0x06000000 -#warning "If this fails to compile NTDDI_VERSION may be to low. See comments above." -#endif -// But once we define the values above we then get this linker error: -// "tz.cpp:(.rdata$.refptr.FOLDERID_Downloads[.refptr.FOLDERID_Downloads]+0x0): " -// "undefined reference to `FOLDERID_Downloads'" -// which #include cures see: -// https://support.microsoft.com/en-us/kb/130869 -#include -// But with included, the error moves on to: -// error: 'FOLDERID_Downloads' was not declared in this scope -// Which #include cures. -#include - -#endif // __MINGW32__ - -#include -#endif // _WIN32 - -#include "tz_private.h" -#include "ios.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -#include -#include -#endif // _WIN32 - -// unistd.h is used on some platforms as part of the the means to get -// the current time zone. On Win32 Windows.h provides a means to do it. -// gcc/mingw supports unistd.h on Win32 but MSVC does not. - -#ifdef _WIN32 -# include // _unlink etc. -# include // CoTaskFree, ShGetKnownFolderPath etc. -# if HAS_REMOTE_API -# include // _mkdir -# include // ShFileOperation etc. -# endif // HAS_REMOTE_API -#else // !WIN32 -# include -# include -# if !USE_SHELL_API -# include -# include -# include -# include -# include -# include -# endif //!USE_SHELL_API -#endif // !WIN32 - - -#if HAS_REMOTE_API -// Note curl includes windows.h so we must include curl AFTER definitions of things -// that effect windows.h such as NOMINMAX. -#include -#endif - -#ifdef _WIN32 -static CONSTDATA char folder_delimiter = '\\'; - -namespace -{ - struct task_mem_deleter - { - void operator()(wchar_t buf[]) - { - if (buf != nullptr) - CoTaskMemFree(buf); - } - }; - using co_task_mem_ptr = std::unique_ptr; -} - -// We might need to know certain locations even if not using the remote API, -// so keep these routines out of that block for now. -static -std::string -get_known_folder(const GUID& folderid) -{ - std::string folder; - PWSTR pfolder = nullptr; - HRESULT hr = SHGetKnownFolderPath(folderid, KF_FLAG_DEFAULT, NULL, &pfolder); - if (SUCCEEDED(hr)) - { - co_task_mem_ptr folder_ptr(pfolder); - folder = std::string(folder_ptr.get(), folder_ptr.get() + wcslen(folder_ptr.get())); - } - return folder; -} - -// Usually something like "c:\Program Files". -static -std::string -get_program_folder() -{ - return get_known_folder(FOLDERID_ProgramFiles); -} - -// Usually something like "c:\Users\username\Downloads". -static -std::string -get_download_folder() -{ - return get_known_folder(FOLDERID_Downloads); -} - -#else // !_WIN32 - -static CONSTDATA char folder_delimiter = '/'; - -static -std::string -expand_path(std::string path) -{ -#if TARGET_OS_IPHONE - return date::iOSUtils::get_tzdata_path(); -#else - ::wordexp_t w{}; - ::wordexp(path.c_str(), &w, 0); - assert(w.we_wordc == 1); - path = w.we_wordv[0]; - ::wordfree(&w); - return path; -#endif -} - -#endif // !_WIN32 - -namespace date -{ -// +---------------------+ -// | Begin Configuration | -// +---------------------+ - -using namespace detail; - -static std::string get_install() -{ -#ifdef _WIN32 - std::string install = get_download_folder(); - install += folder_delimiter; - install += "tzdata"; -#else - std::string install = expand_path("~/Downloads/tzdata"); -#endif - return install; -} - -#ifndef INSTALL - -static const std::string install = get_install(); - -#else // INSTALL - -#define STRINGIZEIMP(x) #x -#define STRINGIZE(x) STRINGIZEIMP(x) - -static const std::string install = STRINGIZE(INSTALL) + - std::string(1, folder_delimiter) + "tzdata"; - -#endif // INSTALL - -static -std::string -get_download_gz_file(const std::string& version) -{ - auto file = install + version + ".tar.gz"; - return file; -} - -static const std::vector files = -{ - "africa", "antarctica", "asia", "australasia", "backward", "etcetera", "europe", - "pacificnew", "northamerica", "southamerica", "systemv", "leapseconds" -}; - -// These can be used to reduce the range of the database to save memory -CONSTDATA auto min_year = date::year::min(); -CONSTDATA auto max_year = date::year::max(); - -CONSTDATA auto min_day = date::jan/1; -CONSTDATA auto max_day = date::dec/31; - -// +-------------------+ -// | End Configuration | -// +-------------------+ - -namespace detail -{ -struct undocumented {explicit undocumented() = default;}; -} - -#ifndef _MSC_VER -static_assert(min_year <= max_year, "Configuration error"); -#endif - -#ifdef TIMEZONE_MAPPING - -namespace // Put types in an anonymous name space. -{ - -// A simple type to manage RAII for key handles and to -// implement the trivial registry interface we need. -// Not intended to be general-purpose. -class reg_key -{ -private: - // Note there is no value documented to be an invalid handle value. - // Not NULL nor INVALID_HANDLE_VALUE. We must rely on is_open. - HKEY m_key = nullptr; - bool m_is_open = false; -public: - ~reg_key() - { - close(); - } - - reg_key() = default; - reg_key(const reg_key&) = delete; - reg_key& operator=(const reg_key&) = delete; - - HKEY handle() - { - return m_key; - } - - bool is_open() const - { - return m_is_open; - } - - LONG open(const wchar_t* key_name) - { - LONG result; - result = RegOpenKeyExW(HKEY_LOCAL_MACHINE, key_name, 0, KEY_READ, &m_key); - if (result == ERROR_SUCCESS) - m_is_open = true; - return result; - } - - LONG close() - { - if (m_is_open) - { - auto result = RegCloseKey(m_key); - assert(result == ERROR_SUCCESS); - if (result == ERROR_SUCCESS) - { - m_is_open = false; - m_key = nullptr; - } - return result; - } - return ERROR_SUCCESS; - } - - // WARNING: this function is not a general-purpose function. - // It has a hard-coded value size limit that should be sufficient for our use cases. - bool get_string(const wchar_t* key_name, std::string& value, std::wstring_convert>& converter) - { - value.clear(); - wchar_t value_buffer[256]; - // in/out parameter. Documentation say that size is a count of bytes not chars. - DWORD size = sizeof(value_buffer) - sizeof(value_buffer[0]); - DWORD tzi_type = REG_SZ; - if (RegQueryValueExW(handle(), key_name, nullptr, &tzi_type, - reinterpret_cast(value_buffer), &size) == ERROR_SUCCESS) - { - // Function does not guarantee to null terminate. - value_buffer[size/sizeof(value_buffer[0])] = L'\0'; - value = converter.to_bytes(value_buffer); - return true; - } - return false; - } - - bool get_binary(const wchar_t* key_name, void* value, int value_size) - { - DWORD size = value_size; - DWORD type = REG_BINARY; - if (RegQueryValueExW(handle(), key_name, nullptr, &type, - reinterpret_cast(value), &size) == ERROR_SUCCESS - && (int) size == value_size) - return true; - return false; - } -}; - -} // anonymous namespace - -static -std::string -get_download_mapping_file(const std::string& version) -{ - auto file = install + version + "windowsZones.xml"; - return file; -} - -// Parse this XML file: -// http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml -// The parsing method is designed to be simple and quick. It is not overly -// forgiving of change but it should diagnose basic format issues. -// See timezone_mapping structure for more info. -static -std::vector -load_timezone_mappings_from_xml_file(const std::string& input_path) -{ - std::size_t line_num = 0; - std::vector mappings; - std::string line; - - std::ifstream is(input_path); - if (!is.is_open()) - { - // We don't emit file exceptions because that's an implementation detail. - std::string msg = "Error opening time zone mapping file \""; - msg += input_path; - msg += "\"."; - throw std::runtime_error(msg); - } - - auto error = [&input_path, &line_num](const char* info) - { - std::string msg = "Error loading time zone mapping file \""; - msg += input_path; - msg += "\" at line "; - msg += std::to_string(line_num); - msg += ": "; - msg += info; - throw std::runtime_error(msg); - }; - // [optional space]a="b" - auto read_attribute = [&line_num, &line, &error] - (const char* name, std::string& value, std::size_t startPos) - ->std::size_t - { - value.clear(); - // Skip leading space before attribute name. - std::size_t spos = line.find_first_not_of(' ', startPos); - if (spos == std::string::npos) - spos = startPos; - // Assume everything up to next = is the attribute name - // and that an = will always delimit that. - std::size_t epos = line.find('=', spos); - if (epos == std::string::npos) - error("Expected \'=\' right after attribute name."); - std::size_t name_len = epos - spos; - // Expect the name we find matches the name we expect. - if (line.compare(spos, name_len, name) != 0) - { - std::string msg; - msg = "Expected attribute name \'"; - msg += name; - msg += "\' around position "; - msg += std::to_string(spos); - msg += " but found something else."; - error(msg.c_str()); - } - ++epos; // Skip the '=' that is after the attribute name. - spos = epos; - if (spos < line.length() && line[spos] == '\"') - ++spos; // Skip the quote that is before the attribute value. - else - { - std::string msg = "Expected '\"' to begin value of attribute \'"; - msg += name; - msg += "\'."; - error(msg.c_str()); - } - epos = line.find('\"', spos); - if (epos == std::string::npos) - { - std::string msg = "Expected '\"' to end value of attribute \'"; - msg += name; - msg += "\'."; - error(msg.c_str()); - } - // Extract everything in between the quotes. Note no escaping is done. - std::size_t value_len = epos - spos; - value.assign(line, spos, value_len); - ++epos; // Skip the quote that is after the attribute value; - return epos; - }; - - // Quick but not overly forgiving XML mapping file processing. - bool mapTimezonesOpenTagFound = false; - bool mapTimezonesCloseTagFound = false; - bool mapZoneOpenTagFound = false; - bool mapTZoneCloseTagFound = false; - std::size_t mapZonePos = std::string::npos; - std::size_t mapTimezonesPos = std::string::npos; - CONSTDATA char mapTimeZonesOpeningTag[] = { ""); - mapTimezonesCloseTagFound = (mapTimezonesPos != std::string::npos); - if (!mapTimezonesCloseTagFound) - { - std::size_t commentPos = line.find(" " << x.target_; -} - -// leap - -leap::leap(const std::string& s, detail::undocumented) -{ - using namespace date; - std::istringstream in(s); - in.exceptions(std::ios::failbit | std::ios::badbit); - std::string word; - int y; - MonthDayTime date; - in >> word >> y >> date; - date_ = date.to_time_point(year(y)); -} - -std::ostream& -operator<<(std::ostream& os, const leap& x) -{ - using namespace date; - return os << x.date_ << " +"; -} - -static -bool -file_exists(const std::string& filename) -{ -#ifdef _WIN32 - return ::_access(filename.c_str(), 0) == 0; -#else - return ::access(filename.c_str(), F_OK) == 0; -#endif -} - -#if HAS_REMOTE_API - -// CURL tools - -static -int -curl_global() -{ - if (::curl_global_init(CURL_GLOBAL_DEFAULT) != 0) - throw std::runtime_error("CURL global initialization failed"); - return 0; -} - -static const auto curl_delete = [](CURL* p) {::curl_easy_cleanup(p);}; - -static -std::unique_ptr -curl_init() -{ - static const auto curl_is_now_initiailized = curl_global(); - (void)curl_is_now_initiailized; - return std::unique_ptr{::curl_easy_init(), curl_delete}; -} - -static -bool -download_to_string(const std::string& url, std::string& str) -{ - str.clear(); - auto curl = curl_init(); - if (!curl) - return false; - std::string version; - curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str()); - curl_write_callback write_cb = [](char* contents, std::size_t size, std::size_t nmemb, - void* userp) -> std::size_t - { - auto& str = *static_cast(userp); - auto realsize = size * nmemb; - str.append(contents, realsize); - return realsize; - }; - curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, write_cb); - curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &str); - auto res = curl_easy_perform(curl.get()); - return (res == CURLE_OK); -} - -namespace -{ - enum class download_file_options { binary, text }; -} - -static -bool -download_to_file(const std::string& url, const std::string& local_filename, - download_file_options opts) -{ - auto curl = curl_init(); - if (!curl) - return false; - curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str()); - curl_write_callback write_cb = [](char* contents, std::size_t size, std::size_t nmemb, - void* userp) -> std::size_t - { - auto& of = *static_cast(userp); - auto realsize = size * nmemb; - of.write(contents, realsize); - return realsize; - }; - curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, write_cb); - decltype(curl_easy_perform(curl.get())) res; - { - std::ofstream of(local_filename, - opts == download_file_options::binary ? - std::ofstream::out | std::ofstream::binary : - std::ofstream::out); - of.exceptions(std::ios::badbit); - curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &of); - res = curl_easy_perform(curl.get()); - } - return res == CURLE_OK; -} - -std::string -remote_version() -{ - std::string version; - std::string str; - if (download_to_string("http://www.iana.org/time-zones", str)) - { - CONSTDATA char db[] = "/time-zones/repository/releases/tzdata"; - CONSTDATA auto db_size = sizeof(db) - 1; - auto p = str.find(db, 0, db_size); - const int ver_str_len = 5; - if (p != std::string::npos && p + (db_size + ver_str_len) <= str.size()) - version = str.substr(p + db_size, ver_str_len); - } - return version; -} - -bool -remote_download(const std::string& version) -{ - assert(!version.empty()); - auto url = "http://www.iana.org/time-zones/repository/releases/tzdata" + version + - ".tar.gz"; - bool result = download_to_file(url, get_download_gz_file(version), - download_file_options::binary); -#ifdef TIMEZONE_MAPPING - if (result) - { - auto mapping_file = get_download_mapping_file(version); - result = download_to_file("http://unicode.org/repos/cldr/trunk/common/" - "supplemental/windowsZones.xml", - mapping_file, download_file_options::text); - } -#endif - return result; -} - -// TODO! Using system() create a process and a console window. -// This is useful to see what errors may occur but is slow and distracting. -// Consider implementing this functionality more directly, such as -// using _mkdir and CreateProcess etc. -// But use the current means now as matches Unix implementations and while -// in proof of concept / testing phase. -// TODO! Use eventually. -static -bool -remove_folder_and_subfolders(const std::string& folder) -{ -#ifdef _WIN32 -# if USE_SHELL_API - // Delete the folder contents by deleting the folder. - std::string cmd = "rd /s /q \""; - cmd += folder; - cmd += '\"'; - return std::system(cmd.c_str()) == EXIT_SUCCESS; -# else // !USE_SHELL_API - // Create a buffer containing the path to delete. It must be terminated - // by two nuls. Who designs these API's... - std::vector from; - from.assign(folder.begin(), folder.end()); - from.push_back('\0'); - from.push_back('\0'); - SHFILEOPSTRUCT fo{}; // Zero initialize. - fo.wFunc = FO_DELETE; - fo.pFrom = from.data(); - fo.fFlags = FOF_NO_UI; - int ret = SHFileOperation(&fo); - if (ret == 0 && !fo.fAnyOperationsAborted) - return true; - return false; -# endif // !USE_SHELL_API -#else // !WIN32 -# if USE_SHELL_API - return std::system(("rm -R " + folder).c_str()) == EXIT_SUCCESS; -# else // !USE_SHELL_API - struct dir_deleter { - dir_deleter() {} - void operator()(DIR* d) const - { - if (d != nullptr) - { - int result = closedir(d); - assert(result == 0); - } - } - }; - using closedir_ptr = std::unique_ptr; - - std::string filename; - struct stat statbuf; - std::size_t folder_len = folder.length(); - struct dirent* p = nullptr; - - closedir_ptr d(opendir(folder.c_str())); - bool r = d.get() != nullptr; - while (r && (p=readdir(d.get())) != nullptr) - { - if (strcmp(p->d_name, ".") == 0 || strcmp(p->d_name, "..") == 0) - continue; - - // + 2 for path delimiter and nul terminator. - std::size_t buf_len = folder_len + strlen(p->d_name) + 2; - filename.resize(buf_len); - std::size_t path_len = static_cast( - snprintf(&filename[0], buf_len, "%s/%s", folder.c_str(), p->d_name)); - assert(path_len == buf_len - 1); - filename.resize(path_len); - - if (stat(filename.c_str(), &statbuf) == 0) - r = S_ISDIR(statbuf.st_mode) - ? remove_folder_and_subfolders(filename) - : unlink(filename.c_str()) == 0; - } - d.reset(); - - if (r) - r = rmdir(folder.c_str()) == 0; - - return r; -# endif // !USE_SHELL_API -#endif // !WIN32 -} - -static -bool -make_directory(const std::string& folder) -{ -#ifdef _WIN32 -# if USE_SHELL_API - // Re-create the folder. - std::string cmd = "mkdir \""; - cmd += folder; - cmd += '\"'; - return std::system(cmd.c_str()) == EXIT_SUCCESS; -# else // !USE_SHELL_API - return _mkdir(folder.c_str()) == 0; -# endif // !USE_SHELL_API -#else // !WIN32 -# if USE_SHELL_API - return std::system(("mkdir " + folder).c_str()) == EXIT_SUCCESS; -# else // !USE_SHELL_API - return mkdir(folder.c_str(), 0777) == 0; -# endif // !USE_SHELL_API -#endif -} - -static -bool -delete_file(const std::string& file) -{ -#ifdef _WIN32 -# if USE_SHELL_API - std::string cmd = "del \""; - cmd += file; - cmd += '\"'; - return std::system(cmd.c_str()) == 0; -# else // !USE_SHELL_API - return _unlink(file.c_str()) == 0; -# endif // !USE_SHELL_API -#else // !WIN32 -# if USE_SHELL_API - return std::system(("rm " + file).c_str()) == EXIT_SUCCESS; -# else // !USE_SHELL_API - return unlink(file.c_str()) == 0; -# endif // !USE_SHELL_API -#endif // !WIN32 -} - -#ifdef TIMEZONE_MAPPING - -static -bool -move_file(const std::string& from, const std::string& to) -{ -#ifdef _WIN32 -# if USE_SHELL_API - std::string cmd = "move \""; - cmd += from; - cmd += "\" \""; - cmd += to; - cmd += '\"'; - return std::system(cmd.c_str()) == EXIT_SUCCESS; -# else // !USE_SHELL_API - return !!::MoveFile(from.c_str(), to.c_str()); -# endif // !USE_SHELL_API -#else // !WIN32 -# if USE_SHELL_API - return std::system(("mv " + from + " " + to).c_str()) == EXIT_SUCCESS; -# else - return rename(from, to) == 0); -# endif -#endif // !WIN32 -} - -#endif // TIMEZONE_MAPPING - -#ifdef _WIN32 - -// Note folder can and usually does contain spaces. -static -std::string -get_unzip_program() -{ - std::string path; - - // 7-Zip appears to note its location in the registry. - // If that doesn't work, fall through and take a guess, but it will likely be wrong. - HKEY hKey = nullptr; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\7-Zip", 0, KEY_READ, &hKey) == ERROR_SUCCESS) - { - char value_buffer[MAX_PATH + 1]; // fyi 260 at time of writing. - // in/out parameter. Documentation say that size is a count of bytes not chars. - DWORD size = sizeof(value_buffer) - sizeof(value_buffer[0]); - DWORD tzi_type = REG_SZ; - // Testing shows Path key value is "C:\Program Files\7-Zip\" i.e. always with trailing \. - bool got_value = (RegQueryValueExA(hKey, "Path", nullptr, &tzi_type, - reinterpret_cast(value_buffer), &size) == ERROR_SUCCESS); - RegCloseKey(hKey); // Close now incase of throw later. - if (got_value) - { - // Function does not guarantee to null terminate. - value_buffer[size / sizeof(value_buffer[0])] = '\0'; - path = value_buffer; - if (!path.empty()) - { - path += "7z.exe"; - return path; - } - } - } - path += get_program_folder(); - path += folder_delimiter; - path += "7-Zip\\7z.exe"; - return path; -} - -#if !USE_SHELL_API -static -int -run_program(const std::string& command) -{ - STARTUPINFO si{}; - si.cb = sizeof(si); - PROCESS_INFORMATION pi{}; - - // Allegedly CreateProcess overwrites the command line. Ugh. - std::string mutable_command(command); - if (CreateProcess(nullptr, &mutable_command[0], - nullptr, nullptr, FALSE, CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi)) - { - WaitForSingleObject(pi.hProcess, INFINITE); - DWORD exit_code; - bool got_exit_code = !!GetExitCodeProcess(pi.hProcess, &exit_code); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - // Not 100% sure about this still active thing is correct, - // but I'm going with it because I *think* WaitForSingleObject might - // return in some cases without INFINITE-ly waiting. - // But why/wouldn't GetExitCodeProcess return false in that case? - if (got_exit_code && exit_code != STILL_ACTIVE) - return static_cast(exit_code); - } - return EXIT_FAILURE; -} -#endif // !USE_SHELL_API - -static -std::string -get_download_tar_file(const std::string& version) -{ - auto file = install; - file += folder_delimiter; - file += "tzdata"; - file += version; - file += ".tar"; - return file; -} - -static -bool -extract_gz_file(const std::string& version, const std::string& gz_file, - const std::string& dest_folder) -{ - auto unzip_prog = get_unzip_program(); - bool unzip_result = false; - // Use the unzip program to extract the tar file from the archive. - - // Aim to create a string like: - // "C:\Program Files\7-Zip\7z.exe" x "C:\Users\SomeUser\Downloads\tzdata2016d.tar.gz" - // -o"C:\Users\SomeUser\Downloads\tzdata" - std::string cmd; - cmd = '\"'; - cmd += unzip_prog; - cmd += "\" x \""; - cmd += gz_file; - cmd += "\" -o\""; - cmd += dest_folder; - cmd += '\"'; - -#if USE_SHELL_API - // When using shelling out with std::system() extra quotes are required around the - // whole command. It's weird but neccessary it seems, see: - // http://stackoverflow.com/q/27975969/576911 - - cmd = "\"" + cmd + "\""; - if (std::system(cmd.c_str()) == EXIT_SUCCESS) - unzip_result = true; -#else // !USE_SHELL_API - if (run_program(cmd) == EXIT_SUCCESS) - unzip_result = true; -#endif // !USE_SHELL_API - if (unzip_result) - delete_file(gz_file); - - // Use the unzip program extract the data from the tar file that was - // just extracted from the archive. - auto tar_file = get_download_tar_file(version); - cmd = '\"'; - cmd += unzip_prog; - cmd += "\" x \""; - cmd += tar_file; - cmd += "\" -o\""; - cmd += install; - cmd += '\"'; -#if USE_SHELL_API - cmd = "\"" + cmd + "\""; - if (std::system(cmd.c_str()) == EXIT_SUCCESS) - unzip_result = true; -#else // !USE_SHELL_API - if (run_program(cmd) == EXIT_SUCCESS) - unzip_result = true; -#endif // !USE_SHELL_API - - if (unzip_result) - delete_file(tar_file); - - return unzip_result; -} - -#else // !_WIN32 - -#if !USE_SHELL_API -static -int -run_program(const char* prog, const char*const args[]) -{ - pid_t pid = fork(); - if (pid == -1) // Child failed to start. - return EXIT_FAILURE; - - if (pid != 0) - { - // We are in the parent. Child started. Wait for it. - pid_t ret; - int status; - while ((ret = waitpid(pid, &status, 0)) == -1) - { - if (errno != EINTR) - break; - } - if (ret != -1) - { - if (WIFEXITED(status)) - return WEXITSTATUS(status); - } - printf("Child issues!\n"); - - return EXIT_FAILURE; // Not sure what status of child is. - } - else // We are in the child process. Start the program the parent wants to run. - { - - if (execv(prog, const_cast(args)) == -1) // Does not return. - { - perror("unreachable 0\n"); - _Exit(127); - } - printf("unreachable 2\n"); - } - printf("unreachable 2\n"); - // Unreachable. - assert(false); - exit(EXIT_FAILURE); - return EXIT_FAILURE; -} -#endif // !USE_SHELL_API - -static -bool -extract_gz_file(const std::string&, const std::string& gz_file, const std::string&) -{ -#if USE_SHELL_API - bool unzipped = std::system(("tar -xzf " + gz_file + " -C " + install).c_str()) == EXIT_SUCCESS; -#else // !USE_SHELL_API - const char prog[] = {"/usr/bin/tar"}; - const char*const args[] = - { - prog, "-xzf", gz_file.c_str(), "-C", install.c_str(), nullptr - }; - bool unzipped = (run_program(prog, args) == EXIT_SUCCESS); -#endif // !USE_SHELL_API - if (unzipped) - { - delete_file(gz_file); - return true; - } - return false; -} - -#endif // !_WIN32 - -bool -remote_install(const std::string& version) -{ - auto success = false; - assert(!version.empty()); - - auto gz_file = get_download_gz_file(version); - if (file_exists(gz_file)) - { - if (file_exists(install)) - remove_folder_and_subfolders(install); - if (make_directory(install)) - { - if (extract_gz_file(version, gz_file, install)) - success = true; -#ifdef TIMEZONE_MAPPING - auto mapping_file_source = get_download_mapping_file(version); - auto mapping_file_dest = install; - mapping_file_dest += folder_delimiter; - mapping_file_dest += "windowsZones.xml"; - if (!move_file(mapping_file_source, mapping_file_dest)) - success = false; -#endif - } - } - return success; -} -#endif // HAS_REMOTE_API - -static -std::string -get_version(const std::string& path) -{ - std::ifstream infile(path + "NEWS"); - std::string version; - while (infile) - { - infile >> version; - if (version == "Release") - { - infile >> version; - return version; - } - } - throw std::runtime_error("Unable to get Timezone database version from " + path); -} - -static -TZ_DB -init_tzdb() -{ - using namespace date; - const std::string path = install + folder_delimiter; - std::string line; - bool continue_zone = false; - TZ_DB db; - -#if AUTO_DOWNLOAD - if (!file_exists(install)) - { - auto rv = remote_version(); - if (!rv.empty() && remote_download(rv)) - { - if (!remote_install(rv)) - { - std::string msg = "Timezone database version \""; - msg += rv; - msg += "\" did not install correctly to \""; - msg += install; - msg += "\""; - throw std::runtime_error(msg); - } - } - if (!file_exists(install)) - { - std::string msg = "Timezone database not found at \""; - msg += install; - msg += "\""; - throw std::runtime_error(msg); - } - db.version = get_version(path); - } - else - { - db.version = get_version(path); - auto rv = remote_version(); - if (!rv.empty() && db.version != rv) - { - if (remote_download(rv)) - { - remote_install(rv); - db.version = get_version(path); - } - } - } -#else // !AUTO_DOWNLOAD - if (!file_exists(install)) - { - std::string msg = "Timezone database not found at \""; - msg += install; - msg += "\""; - throw std::runtime_error(msg); - } - db.version = get_version(path); -#endif // !AUTO_DOWNLOAD - - for (const auto& filename : files) - { - std::ifstream infile(path + filename); - while (infile) - { - std::getline(infile, line); - if (!line.empty() && line[0] != '#') - { - std::istringstream in(line); - std::string word; - in >> word; - if (word == "Rule") - { - db.rules.push_back(Rule(line)); - continue_zone = false; - } - else if (word == "Link") - { - db.links.push_back(link(line)); - continue_zone = false; - } - else if (word == "Leap") - { - db.leaps.push_back(leap(line, detail::undocumented{})); - continue_zone = false; - } - else if (word == "Zone") - { - db.zones.push_back(time_zone(line, detail::undocumented{})); - continue_zone = true; - } - else if (line[0] == '\t' && continue_zone) - { - db.zones.back().add(line); - } - else - { - std::cerr << line << '\n'; - } - } - } - } - std::sort(db.rules.begin(), db.rules.end()); - Rule::split_overlaps(db.rules); - std::sort(db.zones.begin(), db.zones.end()); -#if !LAZY_INIT - for (auto& z : db.zones) - z.adjust_infos(db.rules); -#endif - db.zones.shrink_to_fit(); - std::sort(db.links.begin(), db.links.end()); - db.links.shrink_to_fit(); - std::sort(db.leaps.begin(), db.leaps.end()); - db.leaps.shrink_to_fit(); - -#ifdef TIMEZONE_MAPPING - std::string mapping_file = path + "windowsZones.xml"; - db.mappings = load_timezone_mappings_from_xml_file(mapping_file); - sort_zone_mappings(db.mappings); - get_windows_timezone_info(db.native_zones); -#endif // TIMEZONE_MAPPING - - return db; -} - -static -TZ_DB& -access_tzdb() -{ - static TZ_DB tz_db; - return tz_db; -} - -const TZ_DB& -reload_tzdb() -{ -#if AUTO_DOWNLOAD - auto const& v = access_tzdb().version; - if (!v.empty() && v == remote_version()) - return access_tzdb(); -#endif - return access_tzdb() = init_tzdb(); -} - -const TZ_DB& -get_tzdb() -{ - static const TZ_DB& ref = access_tzdb() = init_tzdb(); - return ref; -} - -const time_zone* -locate_zone(const std::string& tz_name) -{ - const auto& db = get_tzdb(); - auto zi = std::lower_bound(db.zones.begin(), db.zones.end(), tz_name, - [](const time_zone& z, const std::string& nm) - { - return z.name() < nm; - }); - if (zi == db.zones.end() || zi->name() != tz_name) - { - auto li = std::lower_bound(db.links.begin(), db.links.end(), tz_name, - [](const link& z, const std::string& nm) - { - return z.name() < nm; - }); - if (li != db.links.end() && li->name() == tz_name) - { - zi = std::lower_bound(db.zones.begin(), db.zones.end(), li->target(), - [](const time_zone& z, const std::string& nm) - { - return z.name() < nm; - }); - if (zi != db.zones.end() && zi->name() == li->target()) - return &*zi; - } - throw std::runtime_error(tz_name + " not found in timezone database"); - } - return &*zi; -} - -std::ostream& -operator<<(std::ostream& os, const TZ_DB& db) -{ - os << "Version: " << db.version << '\n'; - std::string title("--------------------------------------------" - "--------------------------------------------\n" - "Name ""Start Y ""End Y " - "Beginning ""Offset " - "Designator\n" - "--------------------------------------------" - "--------------------------------------------\n"); - int count = 0; - for (const auto& x : db.rules) - { - if (count++ % 50 == 0) - os << title; - os << x << '\n'; - } - os << '\n'; - title = std::string("---------------------------------------------------------" - "--------------------------------------------------------\n" - "Name ""Offset " - "Rule ""Abrev ""Until\n" - "---------------------------------------------------------" - "--------------------------------------------------------\n"); - count = 0; - for (const auto& x : db.zones) - { - if (count++ % 10 == 0) - os << title; - os << x << '\n'; - } - os << '\n'; - title = std::string("---------------------------------------------------------" - "--------------------------------------------------------\n" - "Alias ""To\n" - "---------------------------------------------------------" - "--------------------------------------------------------\n"); - count = 0; - for (const auto& x : db.links) - { - if (count++ % 45 == 0) - os << title; - os << x << '\n'; - } - os << '\n'; - title = std::string("---------------------------------------------------------" - "--------------------------------------------------------\n" - "Leap second on\n" - "---------------------------------------------------------" - "--------------------------------------------------------\n"); - os << title; - for (const auto& x : db.leaps) - os << x << '\n'; - return os; -} - -// ----------------------- - -#ifdef _WIN32 - -const time_zone* -current_zone() -{ -#ifdef TIMEZONE_MAPPING - TIME_ZONE_INFORMATION tzi{}; - DWORD tz_result = ::GetTimeZoneInformation(&tzi); - if (tz_result == TIME_ZONE_ID_INVALID) - { - auto error_code = ::GetLastError(); // Store this quick before it gets overwritten. - throw std::runtime_error("GetTimeZoneInformation failed: " - + get_win32_message(error_code)); - } - std::wstring_convert> converter; - std::string standard_name(converter.to_bytes(tzi.StandardName)); - auto tz = find_native_timezone_by_standard_name(standard_name); - if (!tz) - { - std::string msg; - msg = "current_zone() failed: "; - msg += standard_name; - msg += " was not found in the Windows Time Zone registry"; - throw std::runtime_error( msg ); - } - std::string standard_tzid; - if (!native_to_standard_timezone_name(tz->timezone_id, standard_tzid)) - { - std::string msg; - msg = "current_zone() failed: A mapping from the Windows Time Zone id \""; - msg += tz->timezone_id; - msg += "\" was not found in the time zone mapping database."; - throw std::runtime_error(msg); - } - return date::locate_zone(standard_tzid); -#else // !TIMEZONE_MAPPING - // Currently Win32 requires iana <--> windows tz name mappings - // for this function to work. - // TODO! we should really support TIMEZONE_MAPPINGS=0 on Windows, - // And in this mode we should read the current iana timezone from a file. - // This would allow the TZ library do be used by apps that don't care - // about Windows standard names just iana names. - // This would allow the xml dependency to be dropped and none of - // the name mapping functions would be needed. - throw std::runtime_error("current_zone not implemented."); -#endif // !TIMEZONE_MAPPING -} - -#else // !WIN32 - -const time_zone* -current_zone() -{ - // On some OS's a file called /etc/localtime may - // exist and it may be either a real file - // containing time zone details or a symlink to such a file. - // On MacOS and BSD Unix if this file is a symlink it - // might resolve to a path like this: - // "/usr/share/zoneinfo/America/Los_Angeles" - // If it does, we try to determine the current - // timezone from the remainder of the path by removing the prefix - // and hoping the rest resolves to valid timezone. - // It may not always work though. If it doesn't then an - // exception will be thrown by local_timezone. - // The path may also take a relative form: - // "../usr/share/zoneinfo/America/Los_Angeles". - struct stat sb; - CONSTDATA auto timezone = "/etc/localtime"; - if (lstat(timezone, &sb) == 0 && S_ISLNK(sb.st_mode) && sb.st_size > 0) - { - std::string result(sb.st_size, '\0'); - auto sz = readlink(timezone, &result.front(), result.size()); - if (sz == -1) - throw std::runtime_error("readlink failure"); - result.resize(sz); - const char zonepath[] = "/usr/share/zoneinfo/"; - const std::size_t zonepath_len = sizeof(zonepath)/sizeof(zonepath[0])-1; - const std::size_t pos = result.find(zonepath); - if (pos != result.npos) - result.erase(0, zonepath_len+pos); - return locate_zone(result); - } - { - // On some versions of some linux distro's (e.g. Ubuntu), - // the current timezone might be in the first line of - // the /etc/timezone file. - std::ifstream timezone_file("/etc/timezone"); - if (timezone_file.is_open()) - { - std::string result; - std::getline(timezone_file, result); - if (!result.empty()) - return locate_zone(result); - } - // Fall through to try other means. - } - { - // On some versions of some linux distro's (e.g. Red Hat), - // the current timezone might be in the first line of - // the /etc/sysconfig/clock file as: - // ZONE="US/Eastern" - std::ifstream timezone_file("/etc/sysconfig/clock"); - std::string result; - while (timezone_file) - { - std::getline(timezone_file, result); - auto p = result.find("ZONE=\""); - if (p != std::string::npos) - { - result.erase(p, p+6); - result.erase(result.rfind('"')); - return locate_zone(result); - } - } - // Fall through to try other means. - } - throw std::runtime_error("Could not get current timezone"); -} - -#endif // !WIN32 - -#if defined(TZ_TEST) && defined(TIMEZONE_MAPPING) - -const time_zone* -locate_native_zone(const std::string& native_tz_name) -{ - std::string standard_tz_name; - if (!native_to_standard_timezone_name(native_tz_name, standard_tz_name)) - { - std::string msg; - msg = "locate_native_zone() failed: A mapping from the native/Windows Time Zone id \""; - msg += native_tz_name; - msg += "\" was not found in the time zone mapping database."; - throw std::runtime_error(msg); - } - return locate_zone(standard_tz_name); -} - -#endif // TZ_TEST && TIMEZONE_MAPPING - -} // namespace date diff --git a/ext/date/tz.h b/ext/date/tz.h deleted file mode 100644 index 49cb805..0000000 --- a/ext/date/tz.h +++ /dev/null @@ -1,1345 +0,0 @@ -#ifndef TZ_H -#define TZ_H - -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// Our apologies. When the previous paragraph was written, lowercase had not yet -// been invented (that woud involve another several millennia of evolution). -// We did not mean to shout. - -// Get more recent database at http://www.iana.org/time-zones - -// The notion of "current timezone" is something the operating system is expected to "just -// know". How it knows this is system specific. It's often a value set by the user at OS -// intallation time and recorded by the OS somewhere. On Linux and Mac systems the current -// timezone name is obtained by looking at the name or contents of a particular file on -// disk. On Windows the current timzeone name comes from the registry. In either method, -// there is no guarantee that the "native" current timezone name obtained will match any -// of the "Standard" names in this library's "database". On Linux, the names usually do -// seem to match so mapping functions to map from native to "Standard" are typically not -// required. On Windows, the names are never "Standard" so mapping is always required. -// Technically any OS may use the mapping process but currently only Windows does use it. - -#ifdef _WIN32 -# ifndef TIMEZONE_MAPPING -# define TIMEZONE_MAPPING 1 -# endif -#else -# ifdef TIMEZONE_MAPPING -# error "Timezone mapping is not required or not implemented for this platform." -# endif -#endif - -#ifndef LAZY_INIT -# define LAZY_INIT 1 -#endif - -#ifndef HAS_REMOTE_API -# ifdef _WIN32 -# define HAS_REMOTE_API 0 -# else -# define HAS_REMOTE_API 1 -# endif -#endif - -#ifndef AUTO_DOWNLOAD -# define AUTO_DOWNLOAD HAS_REMOTE_API -#endif - -static_assert(HAS_REMOTE_API == 0 ? AUTO_DOWNLOAD == 0 : true, - "AUTO_DOWNLOAD can not be turned on without HAS_REMOTE_API"); - -#ifndef USE_SHELL_API -# define USE_SHELL_API 1 -#endif - -#include "date.h" - -#if defined(_MSC_VER) && (_MSC_VER < 1900) -#include "tz_private.h" -#endif - -#include -#include -#include -#include -#include -#if LAZY_INIT -# include -# include -#endif -#include -#include -#include -#include -#include -#include -#include - -namespace date -{ - -enum class choose {earliest, latest}; - -namespace detail -{ - struct undocumented; -} - -class nonexistent_local_time - : public std::runtime_error -{ -public: - template - nonexistent_local_time(local_time tp, local_seconds first, - const std::string& first_abbrev, local_seconds last, - const std::string& last_abbrev, sys_seconds time_sys); - -private: - template - static - std::string - make_msg(local_time tp, - local_seconds first, const std::string& first_abbrev, - local_seconds last, const std::string& last_abbrev, - sys_seconds time_sys); -}; - -template -inline -nonexistent_local_time::nonexistent_local_time(local_time tp, - local_seconds first, - const std::string& first_abbrev, - local_seconds last, - const std::string& last_abbrev, - sys_seconds time_sys) - : std::runtime_error(make_msg(tp, first, first_abbrev, last, last_abbrev, time_sys)) - {} - -template -std::string -nonexistent_local_time::make_msg(local_time tp, local_seconds first, - const std::string& first_abbrev, local_seconds last, - const std::string& last_abbrev, sys_seconds time_sys) -{ - using namespace date; - std::ostringstream os; - os << tp << " is in a gap between\n" - << first << ' ' << first_abbrev << " and\n" - << last << ' ' << last_abbrev - << " which are both equivalent to\n" - << time_sys << " UTC"; - return os.str(); -} - -class ambiguous_local_time - : public std::runtime_error -{ -public: - template - ambiguous_local_time(local_time tp, std::chrono::seconds first_offset, - const std::string& first_abbrev, - std::chrono::seconds second_offset, - const std::string& second_abbrev); - -private: - template - static - std::string - make_msg(local_time tp, - std::chrono::seconds first_offset, const std::string& first_abbrev, - std::chrono::seconds second_offset, const std::string& second_abbrev); -}; - -template -inline -ambiguous_local_time::ambiguous_local_time( - local_time tp, - std::chrono::seconds first_offset, - const std::string& first_abbrev, - std::chrono::seconds second_offset, - const std::string& second_abbrev) - : std::runtime_error(make_msg(tp, first_offset, first_abbrev, second_offset, - second_abbrev)) - {} - -template -std::string -ambiguous_local_time::make_msg(local_time tp, - std::chrono::seconds first_offset, - const std::string& first_abbrev, - std::chrono::seconds second_offset, - const std::string& second_abbrev) -{ - using namespace date; - std::ostringstream os; - os << tp << " is ambiguous. It could be\n" - << tp << ' ' << first_abbrev << " == " - << tp - first_offset << " UTC or\n" - << tp << ' ' << second_abbrev << " == " - << tp - second_offset << " UTC"; - return os.str(); -} - -namespace detail { class Rule; } - -struct sys_info -{ - sys_seconds begin; - sys_seconds end; - std::chrono::seconds offset; - std::chrono::minutes save; - std::string abbrev; -}; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const sys_info& r) -{ - os << r.begin << '\n'; - os << r.end << '\n'; - os << make_time(r.offset) << "\n"; - os << make_time(r.save) << "\n"; - os << r.abbrev << '\n'; - return os; -} - -struct local_info -{ - enum {unique, nonexistent, ambiguous} result; - sys_info first; - sys_info second; -}; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const local_info& r) -{ - if (r.result == local_info::nonexistent) - os << "nonexistent between\n"; - else if (r.result == local_info::ambiguous) - os << "ambiguous between\n"; - os << r.first; - if (r.result != local_info::unique) - { - os << "and\n"; - os << r.second; - } - return os; -} - -class time_zone; - -template -class zoned_time -{ - const time_zone* zone_; - sys_time tp_; - -public: - zoned_time(const sys_time& st); - explicit zoned_time(const time_zone* z); - explicit zoned_time(const std::string& name); - - template , - sys_time>::value - >::type> - zoned_time(const zoned_time& zt) NOEXCEPT; - - zoned_time(const time_zone* z, const local_time& tp); - zoned_time(const std::string& name, const local_time& tp); - zoned_time(const time_zone* z, const local_time& tp, choose c); - zoned_time(const std::string& name, const local_time& tp, choose c); - - zoned_time(const time_zone* z, const zoned_time& zt); - zoned_time(const std::string& name, const zoned_time& zt); - zoned_time(const time_zone* z, const zoned_time& zt, choose); - zoned_time(const std::string& name, const zoned_time& zt, choose); - - zoned_time(const time_zone* z, const sys_time& st); - zoned_time(const std::string& name, const sys_time& st); - - zoned_time& operator=(const sys_time& st); - zoned_time& operator=(const local_time& ut); - - operator sys_time() const; - explicit operator local_time() const; - - const time_zone* get_time_zone() const; - local_time get_local_time() const; - sys_time get_sys_time() const; - sys_info get_info() const; - - template - friend - bool - operator==(const zoned_time& x, const zoned_time& y); - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const zoned_time& t); - -private: - template friend class zoned_time; - - static_assert(std::is_convertible::value, - "zoned_time must have a precision of seconds or finer"); -}; - -using zoned_seconds = zoned_time; - -template -inline -bool -operator==(const zoned_time& x, const zoned_time& y) -{ - return x.zone_ == y.zone_ && x.tp_ == y.tp_; -} - -template -inline -bool -operator!=(const zoned_time& x, const zoned_time& y) -{ - return !(x == y); -} - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -namespace detail { struct zonelet; } -#endif - -class time_zone -{ -private: - - std::string name_; - std::vector zonelets_; -#if LAZY_INIT - std::unique_ptr adjusted_; -#endif - -public: -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) - time_zone(time_zone&&) = default; - time_zone& operator=(time_zone&&) = default; -#else // defined(_MSC_VER) && (_MSC_VER < 1900) - time_zone(time_zone&& src); - time_zone& operator=(time_zone&& src); -#endif // defined(_MSC_VER) && (_MSC_VER < 1900) - - explicit time_zone(const std::string& s, detail::undocumented); - - const std::string& name() const NOEXCEPT; - - template sys_info get_info(sys_time st) const; - template local_info get_info(local_time tp) const; - - template - sys_time::type> - to_sys(local_time tp) const; - - template - sys_time::type> - to_sys(local_time tp, choose z) const; - - template - local_time::type> - to_local(sys_time tp) const; - - friend bool operator==(const time_zone& x, const time_zone& y) NOEXCEPT; - friend bool operator< (const time_zone& x, const time_zone& y) NOEXCEPT; - friend std::ostream& operator<<(std::ostream& os, const time_zone& z); - - void add(const std::string& s); - void adjust_infos(const std::vector& rules); - -private: - sys_info get_info_impl(sys_seconds tp) const; - local_info get_info_impl(local_seconds tp) const; - sys_info get_info_impl(sys_seconds tp, int timezone) const; - - void parse_info(std::istream& in); - - template - sys_time::type> - to_sys_impl(local_time tp, choose z, std::false_type) const; - template - sys_time::type> - to_sys_impl(local_time tp, choose, std::true_type) const; -}; - -#if defined(_MSC_VER) && (_MSC_VER < 1900) - -inline -time_zone::time_zone(time_zone&& src) - : name_(std::move(src.name_)) - , zonelets_(std::move(src.zonelets_)) -#if LAZY_INIT - , adjusted_(std::move(src.adjusted_)) -#endif - {} - -inline -time_zone& -time_zone::operator=(time_zone&& src) -{ - name_ = std::move(src.name_); - zonelets_ = std::move(src.zonelets_); -#if LAZY_INIT - adjusted_ = std::move(src.adjusted_); -#endif - return *this; -} - -#endif // defined(_MSC_VER) && (_MSC_VER < 1900) - -inline -const std::string& -time_zone::name() const NOEXCEPT -{ - return name_; -} - -template -inline -sys_info -time_zone::get_info(sys_time st) const -{ - using namespace std::chrono; - return get_info_impl(floor(st)); -} - -template -inline -local_info -time_zone::get_info(local_time tp) const -{ - using namespace std::chrono; - return get_info_impl(floor(tp)); -} - -template -inline -sys_time::type> -time_zone::to_sys(local_time tp) const -{ - return to_sys_impl(tp, choose{}, std::true_type{}); -} - -template -inline -sys_time::type> -time_zone::to_sys(local_time tp, choose z) const -{ - return to_sys_impl(tp, z, std::false_type{}); -} - -template -inline -local_time::type> -time_zone::to_local(sys_time tp) const -{ - using LT = local_time::type>; - auto i = get_info(tp); - return LT{(tp + i.offset).time_since_epoch()}; -} - -inline bool operator==(const time_zone& x, const time_zone& y) NOEXCEPT {return x.name_ == y.name_;} -inline bool operator< (const time_zone& x, const time_zone& y) NOEXCEPT {return x.name_ < y.name_;} - -inline bool operator!=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(x == y);} -inline bool operator> (const time_zone& x, const time_zone& y) NOEXCEPT {return y < x;} -inline bool operator<=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(y < x);} -inline bool operator>=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(x < y);} - -template -sys_time::type> -time_zone::to_sys_impl(local_time tp, choose z, std::false_type) const -{ - using namespace date; - using namespace std::chrono; - auto i = get_info(tp); - if (i.result == local_info::nonexistent) - { - return i.first.end; - } - else if (i.result == local_info::ambiguous) - { - if (z == choose::latest) - return sys_time{tp.time_since_epoch()} - i.second.offset; - } - return sys_time{tp.time_since_epoch()} - i.first.offset; -} - -template -sys_time::type> -time_zone::to_sys_impl(local_time tp, choose, std::true_type) const -{ - using namespace date; - using namespace std::chrono; - auto i = get_info(tp); - if (i.result == local_info::nonexistent) - { - auto prev_end = local_seconds{i.first.end.time_since_epoch()} + - i.first.offset; - auto next_begin = local_seconds{i.second.begin.time_since_epoch()} + - i.second.offset; - throw nonexistent_local_time(tp, prev_end, i.first.abbrev, - next_begin, i.second.abbrev, i.first.end); - } - else if (i.result == local_info::ambiguous) - { - throw ambiguous_local_time(tp, i.first.offset, i.first.abbrev, - i.second.offset, i.second.abbrev); - } - return sys_time{tp.time_since_epoch()} - i.first.offset; -} - -class link -{ -private: - std::string name_; - std::string target_; -public: - explicit link(const std::string& s); - - const std::string& name() const {return name_;} - const std::string& target() const {return target_;} - - friend bool operator==(const link& x, const link& y) {return x.name_ == y.name_;} - friend bool operator< (const link& x, const link& y) {return x.name_ < y.name_;} - - friend std::ostream& operator<<(std::ostream& os, const link& x); -}; - -inline bool operator!=(const link& x, const link& y) {return !(x == y);} -inline bool operator> (const link& x, const link& y) {return y < x;} -inline bool operator<=(const link& x, const link& y) {return !(y < x);} -inline bool operator>=(const link& x, const link& y) {return !(x < y);} - -class leap -{ -private: - sys_seconds date_; - -public: - explicit leap(const std::string& s, detail::undocumented); - - sys_seconds date() const {return date_;} - - friend bool operator==(const leap& x, const leap& y) {return x.date_ == y.date_;} - friend bool operator< (const leap& x, const leap& y) {return x.date_ < y.date_;} - - template - friend - bool - operator==(const leap& x, const sys_time& y) - { - return x.date_ == y; - } - - template - friend - bool - operator< (const leap& x, const sys_time& y) - { - return x.date_ < y; - } - - template - friend - bool - operator< (const sys_time& x, const leap& y) - { - return x < y.date_; - } - - friend std::ostream& operator<<(std::ostream& os, const leap& x); -}; - -inline bool operator!=(const leap& x, const leap& y) {return !(x == y);} -inline bool operator> (const leap& x, const leap& y) {return y < x;} -inline bool operator<=(const leap& x, const leap& y) {return !(y < x);} -inline bool operator>=(const leap& x, const leap& y) {return !(x < y);} - -template -inline -bool -operator==(const sys_time& x, const leap& y) -{ - return y == x; -} - -template -inline -bool -operator!=(const leap& x, const sys_time& y) -{ - return !(x == y); -} - -template -inline -bool -operator!=(const sys_time& x, const leap& y) -{ - return !(x == y); -} - -template -inline -bool -operator> (const leap& x, const sys_time& y) -{ - return y < x; -} - -template -inline -bool -operator> (const sys_time& x, const leap& y) -{ - return y < x; -} - -template -inline -bool -operator<=(const leap& x, const sys_time& y) -{ - return !(y < x); -} - -template -inline -bool -operator<=(const sys_time& x, const leap& y) -{ - return !(y < x); -} - -template -inline -bool -operator>=(const leap& x, const sys_time& y) -{ - return !(x < y); -} - -template -inline -bool -operator>=(const sys_time& x, const leap& y) -{ - return !(x < y); -} - -#ifdef TIMEZONE_MAPPING - -namespace detail -{ - -// The time zone mapping is modelled after this data file: -// http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml -// and the field names match the element names from the mapZone element -// of windowsZones.xml. -// The website displays this file here: -// http://www.unicode.org/cldr/charts/latest/supplemental/zone_tzid.html -// The html view is sorted before being displayed but is otherwise the same -// There is a mapping between the os centric view (in this case windows) -// the html displays uses and the generic view the xml file. -// That mapping is this: -// display column "windows" -> xml field "other". -// display column "region" -> xml field "territory". -// display column "tzid" -> xml field "type". -// This structure uses the generic terminology because it could be -// used to to support other os/native name conversions, not just windows, -// and using the same generic names helps retain the connection to the -// origin of the data that we are using. -struct timezone_mapping -{ - timezone_mapping(const char* other, const char* territory, const char* type) - : other(other), territory(territory), type(type) - { - } - timezone_mapping() = default; - std::string other; - std::string territory; - std::string type; -}; - -struct timezone_info -{ - timezone_info() = default; - std::string timezone_id; - std::string standard_name; -}; - -} // detail - -#endif // TIMEZONE_MAPPING - -struct TZ_DB -{ - std::string version; - std::vector zones; - std::vector links; - std::vector leaps; - std::vector rules; -#ifdef TIMEZONE_MAPPING - // TODO! These need some protection. - std::vector mappings; - std::vector native_zones; -#endif - - TZ_DB() = default; -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) - TZ_DB(TZ_DB&&) = default; - TZ_DB& operator=(TZ_DB&&) = default; -#else // defined(_MSC_VER) || (_MSC_VER >= 1900) - TZ_DB(TZ_DB&& src) - : - version(std::move(src.version)), - zones(std::move(src.zones)), - links(std::move(src.links)), - leaps(std::move(src.leaps)), - rules(std::move(src.rules)) -#ifdef TIMEZONE_MAPPING - , - mappings(std::move(src.mappings)), - native_zones(std::move(src.native_zones)) -#endif - {} - - TZ_DB& operator=(TZ_DB&& src) - { - version = std::move(src.version); - zones = std::move(src.zones); - links = std::move(src.links); - leaps = std::move(src.leaps); - rules = std::move(src.rules); -#ifdef TIMEZONE_MAPPING - mappings = std::move(src.mappings); - native_zones = std::move(src.native_zones); -#endif - return *this; - } -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) -}; - -std::ostream& -operator<<(std::ostream& os, const TZ_DB& db); - -const TZ_DB& get_tzdb(); -const TZ_DB& reload_tzdb(); - -#if HAS_REMOTE_API -std::string remote_version(); -bool remote_download(const std::string& version); -bool remote_install(const std::string& version); -#endif - -const time_zone* locate_zone(const std::string& tz_name); -#ifdef TZ_TEST -# if _WIN32 -const time_zone* locate_native_zone(const std::string& native_tz_name); -# endif // _WIN32 -#endif // TZ_TEST -const time_zone* current_zone(); - -// zoned_time - -template -inline -zoned_time::zoned_time(const sys_time& st) - : zone_(locate_zone("UTC")) - , tp_(st) - {} - -template -inline -zoned_time::zoned_time(const time_zone* z) - : zone_(z) - {assert(zone_ != nullptr);} - -template -inline -zoned_time::zoned_time(const std::string& name) - : zoned_time(locate_zone(name)) - {} - -template -inline -zoned_time::zoned_time(const time_zone* z, const local_time& t) - : zone_(z) - , tp_(z->to_sys(t)) - {} - -template -inline -zoned_time::zoned_time(const std::string& name, const local_time& t) - : zoned_time(locate_zone(name), t) - {} - -template -inline -zoned_time::zoned_time(const time_zone* z, const local_time& t, - choose c) - : zone_(z) - , tp_(z->to_sys(t, c)) - {} - -template -inline -zoned_time::zoned_time(const std::string& name, const local_time& t, - choose c) - : zoned_time(locate_zone(name), t, c) - {} - -template -template -inline -zoned_time::zoned_time(const zoned_time& zt) NOEXCEPT - : zone_(zt.zone_) - , tp_(zt.tp_) - {} - -template -inline -zoned_time::zoned_time(const time_zone* z, const zoned_time& zt) - : zone_(z) - , tp_(zt.tp_) - {} - -template -inline -zoned_time::zoned_time(const std::string& name, const zoned_time& zt) - : zoned_time(locate_zone(name), zt) - {} - -template -inline -zoned_time::zoned_time(const time_zone* z, const zoned_time& zt, choose) - : zoned_time(z, zt) - {} - -template -inline -zoned_time::zoned_time(const std::string& name, - const zoned_time& zt, choose c) - : zoned_time(locate_zone(name), zt, c) - {} - -template -inline -zoned_time::zoned_time(const time_zone* z, const sys_time& st) - : zone_(z) - , tp_(st) - {} - -template -inline -zoned_time::zoned_time(const std::string& name, const sys_time& st) - : zoned_time(locate_zone(name), st) - {} - - -template -inline -zoned_time& -zoned_time::operator=(const sys_time& st) -{ - tp_ = st; - return *this; -} - -template -inline -zoned_time& -zoned_time::operator=(const local_time& ut) -{ - tp_ = zone_->to_sys(ut); - return *this; -} - -template -inline -zoned_time::operator local_time() const -{ - return get_local_time(); -} - -template -inline -zoned_time::operator sys_time() const -{ - return get_sys_time(); -} - -template -inline -const time_zone* -zoned_time::get_time_zone() const -{ - return zone_; -} - -template -inline -local_time -zoned_time::get_local_time() const -{ - return zone_->to_local(tp_); -} - -template -inline -sys_time -zoned_time::get_sys_time() const -{ - return tp_; -} - -template -inline -sys_info -zoned_time::get_info() const -{ - return zone_->get_info(tp_); -} - -// make_zoned_time - -template -inline -zoned_time::type> -make_zoned(const sys_time& tp) -{ - return {tp}; -} - -template -inline -zoned_time::type> -make_zoned(const time_zone* zone, const local_time& tp) -{ - return {zone, tp}; -} - -template -inline -zoned_time::type> -make_zoned(const std::string& name, const local_time& tp) -{ - return {name, tp}; -} - -template -inline -zoned_time::type> -make_zoned(const time_zone* zone, const local_time& tp, choose c) -{ - return {zone, tp, c}; -} - -template -inline -zoned_time::type> -make_zoned(const std::string& name, const local_time& tp, choose c) -{ - return {name, tp, c}; -} - -template -inline -zoned_time::type> -make_zoned(const time_zone* zone, const zoned_time& zt) -{ - return {zone, zt}; -} - -template -inline -zoned_time::type> -make_zoned(const std::string& name, const zoned_time& zt) -{ - return {name, zt}; -} - -template -inline -zoned_time::type> -make_zoned(const time_zone* zone, const zoned_time& zt, choose c) -{ - return {zone, zt, c}; -} - -template -inline -zoned_time::type> -make_zoned(const std::string& name, const zoned_time& zt, choose c) -{ - return {name, zt, c}; -} - -template -inline -zoned_time::type> -make_zoned(const time_zone* zone, const sys_time& st) -{ - return {zone, st}; -} - -template -inline -zoned_time::type> -make_zoned(const std::string& name, const sys_time& st) -{ - return {name, st}; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const zoned_time& t) -{ - auto i = t.zone_->get_info(t.tp_); - auto lt = t.tp_ + i.offset; - return os << lt << ' ' << i.abbrev; -} - -class utc_clock -{ -public: - using duration = std::chrono::system_clock::duration; - using rep = duration::rep; - using period = duration::period; - using time_point = std::chrono::time_point; - static CONSTDATA bool is_steady = false; - - static time_point now(); -}; - -template - using utc_time = std::chrono::time_point; - -using utc_seconds = utc_time; - -template -inline -utc_time::type> -to_utc_time(const sys_time& st) -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - auto const& leaps = get_tzdb().leaps; - auto const lt = std::upper_bound(leaps.begin(), leaps.end(), st); - return utc_time{st.time_since_epoch() + seconds{lt-leaps.begin()}}; -} - -template -inline -sys_time::type> -to_sys_time(const utc_time& ut) -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - auto const& leaps = get_tzdb().leaps; - auto tp = sys_time{ut.time_since_epoch()}; - if (tp >= leaps.front()) - { - auto const lt = std::upper_bound(leaps.begin(), leaps.end(), tp); - tp -= seconds{lt-leaps.begin()}; - if (tp < lt[-1]) - { - if (tp >= lt[-1].date() - seconds{1}) - tp = lt[-1].date() - duration{1}; - else - tp += seconds{1}; - } - } - return tp; -} - -inline -utc_clock::time_point -utc_clock::now() -{ - using namespace std::chrono; - return to_utc_time(system_clock::now()); -} - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const utc_time& t) -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - auto const& leaps = get_tzdb().leaps; - auto tp = sys_time{t.time_since_epoch()}; - if (tp >= leaps.front()) - { - auto const lt = std::upper_bound(leaps.begin(), leaps.end(), tp); - tp -= seconds{lt-leaps.begin()}; - if (tp < lt[-1]) - { - if (tp >= lt[-1].date() - seconds{1}) - { - auto const dp = floor(tp); - auto time = make_time(tp-dp); - time.seconds() += seconds{1}; - return os << year_month_day(dp) << ' ' << time; - } - else - tp += seconds{1}; - } - } - return os << tp; -} - -// tai_clock - -class tai_clock -{ -public: - using duration = std::chrono::system_clock::duration; - using rep = duration::rep; - using period = duration::period; - using time_point = std::chrono::time_point; - static const bool is_steady = false; - - static time_point now() NOEXCEPT; -}; - -template - using tai_time = std::chrono::time_point; - -using tai_seconds = tai_time; - -template -inline -utc_time::type> -to_utc_time(const tai_time& t) NOEXCEPT -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - return utc_time{t.time_since_epoch()} - - (sys_days{year{1970}/jan/1} - sys_days{year{1958}/jan/1} + seconds{10}); -} - -template -inline -tai_time::type> -to_tai_time(const utc_time& t) NOEXCEPT -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - return tai_time{t.time_since_epoch()} + - (sys_days{year{1970}/jan/1} - sys_days{year{1958}/jan/1} + seconds{10}); -} - -template -inline -tai_time::type> -to_tai_time(const sys_time& t) -{ - return to_tai_time(to_utc_time(t)); -} - -inline -tai_clock::time_point -tai_clock::now() NOEXCEPT -{ - using namespace std::chrono; - return to_tai_time(system_clock::now()); -} - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const tai_time& t) -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - auto tp = sys_time{t.time_since_epoch()} - - (sys_days{year{1970}/jan/1} - sys_days{year{1958}/jan/1}); - return os << tp; -} - -// gps_clock - -class gps_clock -{ -public: - using duration = std::chrono::system_clock::duration; - using rep = duration::rep; - using period = duration::period; - using time_point = std::chrono::time_point; - static const bool is_steady = false; - - static time_point now() NOEXCEPT; -}; - -template - using gps_time = std::chrono::time_point; - -using gps_seconds = gps_time; - -template -inline -utc_time::type> -to_utc_time(const gps_time& t) NOEXCEPT -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - return utc_time{t.time_since_epoch()} + - (sys_days{year{1980}/jan/sun[1]} - sys_days{year{1970}/jan/1} + seconds{9}); -} - -template -inline -gps_time::type> -to_gps_time(const utc_time& t) -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - return gps_time{t.time_since_epoch()} - - (sys_days{year{1980}/jan/sun[1]} - sys_days{year{1970}/jan/1} + seconds{9}); -} - -template -inline -gps_time::type> -to_gps_time(const sys_time& t) -{ - return to_gps_time(to_utc_time(t)); -} - -inline -gps_clock::time_point -gps_clock::now() NOEXCEPT -{ - using namespace std::chrono; - return to_gps_time(system_clock::now()); -} - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const gps_time& t) -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - auto tp = sys_time{t.time_since_epoch()} + - (sys_days{year{1980}/jan/sun[1]} - sys_days{year{1970}/jan/1}); - return os << tp; -} - -template -inline -sys_time::type> -to_sys_time(const tai_time& t) -{ - return to_sys_time(to_utc_time(t)); -} - -template -inline -sys_time::type> -to_sys_time(const gps_time& t) -{ - return to_sys_time(to_utc_time(t)); -} - -template -inline -tai_time::type> -to_tai_time(const gps_time& t) NOEXCEPT -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - return tai_time{t.time_since_epoch()} + - (sys_days{year{1980}/jan/sun[1]} - sys_days{year{1958}/jan/1} + seconds{19}); -} - -template -inline -gps_time::type> -to_gps_time(const tai_time& t) NOEXCEPT -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - return gps_time{t.time_since_epoch()} - - (sys_days{year{1980}/jan/sun[1]} - sys_days{year{1958}/jan/1} + seconds{19}); -} - -// format - -template -inline -std::basic_string -format(const std::locale& loc, std::basic_string fmt, - const zoned_time& tp) -{ - auto const info = tp.get_info(); - return detail::format(loc, std::move(fmt), tp.get_local_time(), - &info.abbrev, &info.offset); -} - -template -inline -std::basic_string -format(std::basic_string fmt, const zoned_time& tp) -{ - auto const info = tp.get_info(); - return detail::format(std::locale{}, std::move(fmt), tp.get_local_time(), - &info.abbrev, &info.offset); -} - -// const CharT* formats - -template -inline -std::basic_string -format(const std::locale& loc, const CharT* fmt, const zoned_time& tp) -{ - auto const info = tp.get_info(); - return detail::format(loc, std::basic_string(fmt), tp.get_local_time(), - &info.abbrev, &info.offset); -} - -template -inline -std::basic_string -format(const CharT* fmt, const zoned_time& tp) -{ - auto const info = tp.get_info(); - return detail::format(std::locale{}, std::basic_string(fmt), - tp.get_local_time(), &info.abbrev, &info.offset); -} - -} // namespace date - -#endif // TZ_H diff --git a/ext/date/tz_private.h b/ext/date/tz_private.h deleted file mode 100644 index e796e9c..0000000 --- a/ext/date/tz_private.h +++ /dev/null @@ -1,265 +0,0 @@ -#ifndef TZ_PRIVATE_H -#define TZ_PRIVATE_H - -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -// -// Our apologies. When the previous paragraph was written, lowercase had not yet -// been invented (that woud involve another several millennia of evolution). -// We did not mean to shout. - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -#include "tz.h" -#else -#include "date.h" -#include -#endif - -namespace date -{ - -namespace detail -{ - -enum class tz {utc, local, standard}; - -//forward declare to avoid warnings in gcc 6.2 -class MonthDayTime; -std::istream& operator>>(std::istream& is, MonthDayTime& x); -std::ostream& operator<<(std::ostream& os, const MonthDayTime& x); - - -class MonthDayTime -{ -private: - struct pair - { -#if defined(_MSC_VER) && (_MSC_VER < 1900) - pair() : month_day_(date::jan / 1), weekday_(0U) {} - - pair(const date::month_day& month_day, const date::weekday& weekday) - : month_day_(month_day), weekday_(weekday) {} -#endif - - date::month_day month_day_; - date::weekday weekday_; - }; - - enum Type {month_day, month_last_dow, lteq, gteq}; - - Type type_{month_day}; - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) - union U -#else - struct U -#endif - { - date::month_day month_day_; - date::month_weekday_last month_weekday_last_; - pair month_day_weekday_; - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) - U() : month_day_{date::jan/1} {} -#else - U() : - month_day_(date::jan/1), - month_weekday_last_(date::month(0U), date::weekday_last(date::weekday(0U))) - {} - -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - - U& operator=(const date::month_day& x); - U& operator=(const date::month_weekday_last& x); - U& operator=(const pair& x); - } u; - - std::chrono::hours h_{0}; - std::chrono::minutes m_{0}; - std::chrono::seconds s_{0}; - tz zone_{tz::local}; - -public: - MonthDayTime() = default; - MonthDayTime(local_seconds tp, tz timezone); - MonthDayTime(const date::month_day& md, tz timezone); - - date::day day() const; - date::month month() const; - tz zone() const {return zone_;} - - void canonicalize(date::year y); - - sys_seconds - to_sys(date::year y, std::chrono::seconds offset, std::chrono::seconds save) const; - sys_days to_sys_days(date::year y) const; - - sys_seconds to_time_point(date::year y) const; - int compare(date::year y, const MonthDayTime& x, date::year yx, - std::chrono::seconds offset, std::chrono::minutes prev_save) const; - - friend std::istream& operator>>(std::istream& is, MonthDayTime& x); - friend std::ostream& operator<<(std::ostream& os, const MonthDayTime& x); -}; - -// A Rule specifies one or more set of datetimes without using an offset. -// Multiple dates are specified with multiple years. The years in effect -// go from starting_year_ to ending_year_, inclusive. starting_year_ <= -// ending_year_. save_ is ineffect for times from the specified time -// onward, including the specified time. When the specified time is -// local, it uses the save_ from the chronologically previous Rule, or if -// there is none, 0. - -//forward declare to avoid warnings in gcc 6.2 -class Rule; -bool operator==(const Rule& x, const Rule& y); -bool operator<(const Rule& x, const Rule& y); -bool operator==(const Rule& x, const date::year& y); -bool operator<(const Rule& x, const date::year& y); -bool operator==(const date::year& x, const Rule& y); -bool operator<(const date::year& x, const Rule& y); -bool operator==(const Rule& x, const std::string& y); -bool operator<(const Rule& x, const std::string& y); -bool operator==(const std::string& x, const Rule& y); -bool operator<(const std::string& x, const Rule& y); -std::ostream& operator<<(std::ostream& os, const Rule& r); - -class Rule -{ -private: - std::string name_; - date::year starting_year_{0}; - date::year ending_year_{0}; - MonthDayTime starting_at_; - std::chrono::minutes save_{0}; - std::string abbrev_; - -public: - Rule() = default; - explicit Rule(const std::string& s); - Rule(const Rule& r, date::year starting_year, date::year ending_year); - - const std::string& name() const {return name_;} - const std::string& abbrev() const {return abbrev_;} - - const MonthDayTime& mdt() const {return starting_at_;} - const date::year& starting_year() const {return starting_year_;} - const date::year& ending_year() const {return ending_year_;} - const std::chrono::minutes& save() const {return save_;} - - static void split_overlaps(std::vector& rules); - - friend bool operator==(const Rule& x, const Rule& y); - friend bool operator<(const Rule& x, const Rule& y); - friend bool operator==(const Rule& x, const date::year& y); - friend bool operator<(const Rule& x, const date::year& y); - friend bool operator==(const date::year& x, const Rule& y); - friend bool operator<(const date::year& x, const Rule& y); - friend bool operator==(const Rule& x, const std::string& y); - friend bool operator<(const Rule& x, const std::string& y); - friend bool operator==(const std::string& x, const Rule& y); - friend bool operator<(const std::string& x, const Rule& y); - - friend std::ostream& operator<<(std::ostream& os, const Rule& r); - -private: - date::day day() const; - date::month month() const; - static void split_overlaps(std::vector& rules, std::size_t i, std::size_t& e); - static bool overlaps(const Rule& x, const Rule& y); - static void split(std::vector& rules, std::size_t i, std::size_t k, - std::size_t& e); -}; - -inline bool operator!=(const Rule& x, const Rule& y) {return !(x == y);} -inline bool operator> (const Rule& x, const Rule& y) {return y < x;} -inline bool operator<=(const Rule& x, const Rule& y) {return !(y < x);} -inline bool operator>=(const Rule& x, const Rule& y) {return !(x < y);} - -inline bool operator!=(const Rule& x, const date::year& y) {return !(x == y);} -inline bool operator> (const Rule& x, const date::year& y) {return y < x;} -inline bool operator<=(const Rule& x, const date::year& y) {return !(y < x);} -inline bool operator>=(const Rule& x, const date::year& y) {return !(x < y);} - -inline bool operator!=(const date::year& x, const Rule& y) {return !(x == y);} -inline bool operator> (const date::year& x, const Rule& y) {return y < x;} -inline bool operator<=(const date::year& x, const Rule& y) {return !(y < x);} -inline bool operator>=(const date::year& x, const Rule& y) {return !(x < y);} - -inline bool operator!=(const Rule& x, const std::string& y) {return !(x == y);} -inline bool operator> (const Rule& x, const std::string& y) {return y < x;} -inline bool operator<=(const Rule& x, const std::string& y) {return !(y < x);} -inline bool operator>=(const Rule& x, const std::string& y) {return !(x < y);} - -inline bool operator!=(const std::string& x, const Rule& y) {return !(x == y);} -inline bool operator> (const std::string& x, const Rule& y) {return y < x;} -inline bool operator<=(const std::string& x, const Rule& y) {return !(y < x);} -inline bool operator>=(const std::string& x, const Rule& y) {return !(x < y);} - -struct zonelet -{ - enum tag {has_rule, has_save, is_empty}; - - std::chrono::seconds gmtoff_; - tag tag_ = has_rule; - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) - union U -#else - struct U -#endif - { - std::string rule_; - std::chrono::minutes save_; - - ~U() {} - U() {} - U(const U&) {} - U& operator=(const U&) = delete; - } u; - - std::string format_; - date::year until_year_{0}; - MonthDayTime until_date_; - sys_seconds until_utc_; - local_seconds until_std_; - local_seconds until_loc_; - std::chrono::minutes initial_save_{}; - std::string initial_abbrev_; - std::pair first_rule_{nullptr, date::year::min()}; - std::pair last_rule_{nullptr, date::year::max()}; - - ~zonelet(); - zonelet(); - zonelet(const zonelet& i); - zonelet& operator=(const zonelet&) = delete; -}; - -} // namespace detail - -} // namespace date - -#if defined(_MSC_VER) && (_MSC_VER < 1900) -#include "tz.h" -#endif - -#endif // TZ_PRIVATE_H diff --git a/ext/mstch/include/mstch/mstch.hpp b/ext/mstch/include/mstch/mstch.hpp index 68a3cfd..2427b38 100644 --- a/ext/mstch/include/mstch/mstch.hpp +++ b/ext/mstch/include/mstch/mstch.hpp @@ -94,7 +94,7 @@ class lambda_t { } using node = boost::make_recursive_variant< - std::nullptr_t, std::string, int, double, bool, uint64_t, uint32_t, + std::nullptr_t, std::string, int, double, bool, uint64_t, int64_t, uint32_t, internal::lambda_t, std::shared_ptr>, std::map, diff --git a/ext/mstch/src/visitor/render_node.hpp b/ext/mstch/src/visitor/render_node.hpp index 88f115f..23535f3 100644 --- a/ext/mstch/src/visitor/render_node.hpp +++ b/ext/mstch/src/visitor/render_node.hpp @@ -38,6 +38,12 @@ class render_node: public boost::static_visitor { return ss.str(); } + std::string operator()(const int64_t& value) const { + std::stringstream ss; + ss << value; + return ss.str(); + } + std::string operator()(const uint32_t& value) const { std::stringstream ss; ss << value; diff --git a/ext/vpetrigocaches/cache.hpp b/ext/vpetrigocaches/cache.hpp new file mode 100644 index 0000000..c543ecd --- /dev/null +++ b/ext/vpetrigocaches/cache.hpp @@ -0,0 +1,138 @@ +#ifndef CACHE_HPP +#define CACHE_HPP + +#include +#include +#include +#include +#include +#include "cache_policy.hpp" + +namespace caches +{ + +// Base class for caching algorithms +template > +class fixed_sized_cache +{ + public: + + using iterator = typename std::unordered_map::iterator; + + using const_iterator = + typename std::unordered_map::const_iterator; + + using operation_guard = typename std::lock_guard; + + fixed_sized_cache( + size_t max_size, + const Policy& policy = Policy()) + : max_cache_size{max_size}, + cache_policy(policy) + { + if (max_cache_size == 0) + { + max_cache_size = std::numeric_limits::max(); + } + } + + void Put(const Key& key, const Value& value) + { + operation_guard{safe_op}; + auto elem_it = FindElem(key); + + if (elem_it == cache_items_map.end()) + { + // add new element to the cache + if (Size() + 1 > max_cache_size) + { + auto disp_candidate_key = cache_policy.ReplCandidate(); + + Erase(disp_candidate_key); + } + + Insert(key, value); + } + else + { + // update previous value + Update(key, value); + } + } + + bool Contains(const Key& key) + { + operation_guard{safe_op}; + auto elem_it = FindElem(key); + return elem_it != cache_items_map.end(); + } + + const Value& Get(const Key& key) const + { + operation_guard{safe_op}; + auto elem_it = FindElem(key); + + if (elem_it == cache_items_map.end()) + { + throw std::range_error{"No such element in the cache"}; + } + cache_policy.Touch(key); + + return elem_it->second; + } + + const size_t Size() const + { + operation_guard{safe_op}; + + return cache_items_map.size(); + } + + // return a key of a displacement candidate + void Clear() + { + operation_guard{safe_op}; + + cache_policy.Clear(); + cache_items_map.clear(); + } + + protected: + + void Insert(const Key& key, const Value& value) + { + cache_policy.Insert(key); + cache_items_map.emplace(std::make_pair(key, value)); + } + + void Erase(const Key& key) + { + cache_policy.Erase(key); + cache_items_map.erase(key); + } + + void Update(const Key& key, const Value& value) + { + cache_policy.Touch(key); + cache_items_map[key] = value; + } + + const_iterator FindElem(const Key& key) const + { + return cache_items_map.find(key); + } + + +private: + + std::unordered_map cache_items_map; + + mutable Policy cache_policy; + mutable std::mutex safe_op; + + size_t max_cache_size; + +}; +} + +#endif // CACHE_HPP diff --git a/ext/vpetrigocaches/cache_policy.hpp b/ext/vpetrigocaches/cache_policy.hpp new file mode 100644 index 0000000..19cf815 --- /dev/null +++ b/ext/vpetrigocaches/cache_policy.hpp @@ -0,0 +1,77 @@ +#ifndef CACHE_POLICY_HPP +#define CACHE_POLICY_HPP + +#include + +namespace caches +{ + +template + +class ICachePolicy +{ + public: + + virtual ~ICachePolicy() {} + + // handle element insertion in a cache + virtual void Insert(const Key& key) = 0; + + // handle request to the key-element in a cache + virtual void Touch(const Key& key) = 0; + + // handle element deletion from a cache + virtual void Erase(const Key& key) = 0; + + // return a key of a replacement candidate + virtual const Key& ReplCandidate() const = 0; + + // clear the cache + virtual void Clear() = 0; + +}; + +template +class NoCachePolicy : public ICachePolicy +{ + public: + + NoCachePolicy() = default; + + ~NoCachePolicy() override = default; + + void Insert(const Key& key) override + { + key_storage.emplace(key); + } + + void Touch(const Key& key) override + { + // do not do anything + } + + void Erase(const Key& key) override + { + key_storage.erase(key); + } + + // return a key of a displacement candidate + const Key& ReplCandidate() const override + { + return *key_storage.crbegin(); + } + + // return a key of a displacement candidate + void Clear() override + { + key_storage.clear(); + } + + private: + + std::unordered_set key_storage; +}; + +} // namespace caches + +#endif // CACHE_POLICY_HPP diff --git a/ext/vpetrigocaches/fifo_cache_policy.hpp b/ext/vpetrigocaches/fifo_cache_policy.hpp new file mode 100644 index 0000000..fa17757 --- /dev/null +++ b/ext/vpetrigocaches/fifo_cache_policy.hpp @@ -0,0 +1,53 @@ +#ifndef FIFO_CACHE_POLICY_HPP +#define FIFO_CACHE_POLICY_HPP + +#include +#include "cache_policy.hpp" + +namespace caches +{ + +template +class FIFOCachePolicy : public ICachePolicy +{ + public: + + FIFOCachePolicy() = default; + ~FIFOCachePolicy() = default; + + void Insert(const Key& key) override + { + fifo_queue.emplace_front(key); + } + + // handle request to the key-element in a cache + void Touch(const Key& key) override + { + // nothing to do here in the FIFO strategy + } + + // handle element deletion from a cache + void Erase(const Key& key) override + { + fifo_queue.pop_back(); + } + + // return a key of a replacement candidate + const Key& ReplCandidate() const override + { + return fifo_queue.back(); + } + + // return a key of a displacement candidate + void Clear() override + { + fifo_queue.clear(); + } + +private: + + std::list fifo_queue; +}; +} // namespace caches + +#endif // FIFO_CACHE_POLICY_HPP diff --git a/ext/vpetrigocaches/lfu_cache_policy.hpp b/ext/vpetrigocaches/lfu_cache_policy.hpp new file mode 100644 index 0000000..0f735d7 --- /dev/null +++ b/ext/vpetrigocaches/lfu_cache_policy.hpp @@ -0,0 +1,76 @@ +#ifndef LFU_CACHE_POLICY_HPP +#define LFU_CACHE_POLICY_HPP + +#include +#include +#include +#include +#include "cache_policy.hpp" + +namespace caches +{ +template +class LFUCachePolicy : public ICachePolicy +{ + public: + + using lfu_iterator = typename std::multimap::iterator; + + LFUCachePolicy() = default; + + ~LFUCachePolicy() override = default; + + void Insert(const Key& key) override + { + constexpr std::size_t INIT_VAL = 1; + + // all new value initialized with the frequency 1 + lfu_storage[key] = frequency_storage.emplace_hint( + frequency_storage.cbegin(), INIT_VAL, key); + } + + void Touch(const Key& key) override + { + // get the previous frequency value of a key + auto elem_for_update = lfu_storage[key]; + + auto updated_elem = std::make_pair( + elem_for_update->first + 1, elem_for_update->second); + + // update the previous value + frequency_storage.erase(elem_for_update); + + lfu_storage[key] = frequency_storage.emplace_hint( + frequency_storage.cend(), std::move(updated_elem)); + } + + void Erase(const Key& key) override + { + frequency_storage.erase(lfu_storage[key]); + lfu_storage.erase(key); + } + + const Key& ReplCandidate() const override + { + // at the beginning of the frequency_storage we have the + // least frequency used value + return frequency_storage.cbegin()->second; + } + + // return a key of a displacement candidate + void Clear() override + { + frequency_storage.clear(); + lfu_storage.clear(); + } + + + private: + + std::multimap frequency_storage; + + std::unordered_map lfu_storage; +}; +} // namespace caches + +#endif // LFU_CACHE_POLICY_HPP diff --git a/ext/vpetrigocaches/lru_cache_policy.hpp b/ext/vpetrigocaches/lru_cache_policy.hpp new file mode 100644 index 0000000..5dcdac0 --- /dev/null +++ b/ext/vpetrigocaches/lru_cache_policy.hpp @@ -0,0 +1,63 @@ +#ifndef LRU_CACHE_POLICY_HPP +#define LRU_CACHE_POLICY_HPP + +#include +#include +#include "cache_policy.hpp" + +namespace caches +{ +template +class LRUCachePolicy : public ICachePolicy +{ + + public: + + using lru_iterator = typename std::list::const_iterator; + + LRUCachePolicy() = default; + ~LRUCachePolicy() = default; + + void Insert(const Key& key) override + { + lru_queue.emplace_front(key); + key_finder[key] = lru_queue.cbegin(); + } + + void Touch(const Key& key) override + { + // move the touched element at the beginning of the lru_queue + lru_queue.splice(lru_queue.cbegin(), lru_queue, key_finder[key]); + } + + void Erase(const Key& key) override + { + // remove the least recently used element + key_finder.erase(lru_queue.back()); + + lru_queue.pop_back(); + } + + // return a key of a displacement candidate + const Key& ReplCandidate() const override + { + return lru_queue.back(); + } + + // return a key of a displacement candidate + void Clear() override + { + lru_queue.clear(); + key_finder.clear(); + } + + private: + + std::list lru_queue; + + std::unordered_map key_finder; +}; + +} // namespace caches + +#endif // LRU_CACHE_POLICY_HPP diff --git a/main.cpp b/main.cpp index e5d0b8c..4e1d2fc 100644 --- a/main.cpp +++ b/main.cpp @@ -6,10 +6,8 @@ #include "src/MicroCore.h" #include "src/page.h" - -#include "ext/member_checker.h" - #include +#include using boost::filesystem::path; @@ -21,11 +19,6 @@ int main(int ac, const char* av[]) { xmreg::CmdLineOptions opts {ac, av}; auto help_opt = opts.get_option("help"); - auto testnet_opt = opts.get_option("testnet"); - auto enable_key_image_checker_opt = opts.get_option("enable-key-image-checker"); - auto enable_output_key_checker_opt = opts.get_option("enable-output-key-checker"); - auto enable_autorefresh_option_opt = opts.get_option("enable-autorefresh-option"); - auto enable_pusher_opt = opts.get_option("enable-pusher"); // if help was chosen, display help text and finish if (*help_opt) @@ -33,19 +26,38 @@ int main(int ac, const char* av[]) { return EXIT_SUCCESS; } - bool testnet {*testnet_opt}; - bool enable_pusher {*enable_pusher_opt}; - bool enable_key_image_checker {*enable_key_image_checker_opt}; - bool enable_autorefresh_option {*enable_autorefresh_option_opt}; - bool enable_output_key_checker {*enable_output_key_checker_opt}; + auto port_opt = opts.get_option("port"); + auto bc_path_opt = opts.get_option("bc-path"); + auto deamon_url_opt = opts.get_option("deamon-url"); + auto ssl_crt_file_opt = opts.get_option("ssl-crt-file"); + auto ssl_key_file_opt = opts.get_option("ssl-key-file"); + auto no_blocks_on_index_opt = opts.get_option("no-blocks-on-index"); + auto testnet_url = opts.get_option("testnet-url"); + auto mainnet_url = opts.get_option("mainnet-url"); + auto testnet_opt = opts.get_option("testnet"); + auto enable_key_image_checker_opt = opts.get_option("enable-key-image-checker"); + auto enable_output_key_checker_opt = opts.get_option("enable-output-key-checker"); + auto enable_autorefresh_option_opt = opts.get_option("enable-autorefresh-option"); + auto enable_pusher_opt = opts.get_option("enable-pusher"); + auto enable_mixin_details_opt = opts.get_option("enable-mixin-details"); + auto enable_mempool_cache_opt = opts.get_option("enable-mempool-cache"); + auto enable_json_api_opt = opts.get_option("enable-json-api"); + auto enable_tx_cache_opt = opts.get_option("enable-tx-cache"); + auto enable_block_cache_opt = opts.get_option("enable-block-cache"); + auto show_cache_times_opt = opts.get_option("show-cache-times"); + + bool testnet {*testnet_opt}; + bool enable_pusher {*enable_pusher_opt}; + bool enable_key_image_checker {*enable_key_image_checker_opt}; + bool enable_autorefresh_option {*enable_autorefresh_option_opt}; + bool enable_output_key_checker {*enable_output_key_checker_opt}; + bool enable_mixin_details {*enable_mixin_details_opt}; + bool enable_mempool_cache {*enable_mempool_cache_opt}; + bool enable_json_api {*enable_json_api_opt}; + bool enable_tx_cache {*enable_tx_cache_opt}; + bool enable_block_cache {*enable_block_cache_opt}; + bool show_cache_times {*show_cache_times_opt}; - auto port_opt = opts.get_option("port"); - auto bc_path_opt = opts.get_option("bc-path"); - auto custom_db_path_opt = opts.get_option("custom-db-path"); - auto deamon_url_opt = opts.get_option("deamon-url"); - auto ssl_crt_file_opt = opts.get_option("ssl-crt-file"); - auto ssl_key_file_opt = opts.get_option("ssl-key-file"); - auto no_blocks_on_index_opt = opts.get_option("no-blocks-on-index"); // set monero log output level uint32_t log_level = 0; @@ -114,36 +126,6 @@ int main(int ac, const char* av[]) { return EXIT_FAILURE; } - // check if we have path to lmdb2 (i.e., custom db) - // and if it exists - - string custom_db_path_str; - - if (custom_db_path_opt) - { - if (boost::filesystem::exists(boost::filesystem::path(*custom_db_path_opt))) - { - custom_db_path_str = *custom_db_path_opt; - } - else - { - cerr << "Custom db path: " << *custom_db_path_opt - << "does not exist" << endl; - - return EXIT_FAILURE; - } - } - else - { - // if not given assume it is located in ~./bitmonero/lmdb2 folder - // or ~./bitmonero/testnet/lmdb2 for testnet network - custom_db_path_str = blockchain_path.parent_path().string() - + string("/lmdb2"); - } - - custom_db_path_str = xmreg::remove_trailing_path_separator(custom_db_path_str); - - string deamon_url {*deamon_url_opt}; if (testnet && deamon_url == "http:://127.0.0.1:18081") @@ -154,13 +136,19 @@ int main(int ac, const char* av[]) { xmreg::page xmrblocks(&mcore, core_storage, deamon_url, - custom_db_path_str, testnet, enable_pusher, enable_key_image_checker, enable_output_key_checker, enable_autorefresh_option, - no_blocks_on_index); + enable_mixin_details, + enable_mempool_cache, + enable_tx_cache, + enable_block_cache, + show_cache_times, + no_blocks_on_index, + *testnet_url, + *mainnet_url); // crow instance crow::SimpleApp app; @@ -350,6 +338,108 @@ int main(int ac, const char* av[]) { return text; }); + if (enable_json_api) + { + CROW_ROUTE(app, "/api/transaction/") + ([&](const crow::request &req, string tx_hash) { + + crow::response r{xmrblocks.json_transaction(tx_hash).dump()}; + + r.add_header("Access-Control-Allow-Origin", "*"); + r.add_header("Access-Control-Allow-Headers", "Content-Type"); + r.add_header("Content-Type", "application/json"); + + return r; + }); + + CROW_ROUTE(app, "/api/block/") + ([&](const crow::request &req, string block_no_or_hash) { + + crow::response r{xmrblocks.json_block(block_no_or_hash).dump()}; + + r.add_header("Access-Control-Allow-Origin", "*"); + r.add_header("Access-Control-Allow-Headers", "Content-Type"); + r.add_header("Content-Type", "application/json"); + + return r; + }); + + + CROW_ROUTE(app, "/api/transactions").methods("GET"_method) + ([&](const crow::request &req) { + + string page = regex_search(req.raw_url, regex {"page=\\d+"}) ? + req.url_params.get("page") : "0"; + + string limit = regex_search(req.raw_url, regex {"limit=\\d+"}) ? + req.url_params.get("limit") : "25"; + + crow::response r{xmrblocks.json_transactions(page, limit).dump()}; + + r.add_header("Access-Control-Allow-Origin", "*"); + r.add_header("Access-Control-Allow-Headers", "Content-Type"); + r.add_header("Content-Type", "application/json"); + + return r; + }); + + CROW_ROUTE(app, "/api/mempool") + ([&](const crow::request &req) { + + crow::response r{xmrblocks.json_mempool().dump()}; + + r.add_header("Access-Control-Allow-Origin", "*"); + r.add_header("Access-Control-Allow-Headers", "Content-Type"); + r.add_header("Content-Type", "application/json"); + + return r; + }); + + CROW_ROUTE(app, "/api/search/") + ([&](const crow::request &req, string search_value) { + + crow::response r{xmrblocks.json_search(search_value).dump()}; + + r.add_header("Access-Control-Allow-Origin", "*"); + r.add_header("Access-Control-Allow-Headers", "Content-Type"); + r.add_header("Content-Type", "application/json"); + + return r; + }); + + CROW_ROUTE(app, "/api/outputs").methods("GET"_method) + ([&](const crow::request &req) { + + string tx_hash = regex_search(req.raw_url, regex {"txhash=\\w+"}) ? + req.url_params.get("txhash") : ""; + + string address = regex_search(req.raw_url, regex {"address=\\w+"}) ? + req.url_params.get("address") : ""; + + string viewkey = regex_search(req.raw_url, regex {"viewkey=\\w+"}) ? + req.url_params.get("viewkey") : ""; + + bool tx_prove{false}; + + try { + tx_prove = regex_search(req.raw_url, regex {"txprove=[01]"}) ? + boost::lexical_cast(req.url_params.get("txprove")) : + false; + } + catch (const boost::bad_lexical_cast &e) { + cerr << "Cant parse tx_prove as bool. Using default value" << endl; + } + + crow::response r{xmrblocks.json_outputs( + tx_hash, address, viewkey, tx_prove).dump()}; + + r.add_header("Access-Control-Allow-Origin", "*"); + r.add_header("Access-Control-Allow-Headers", "Content-Type"); + r.add_header("Content-Type", "application/json"); + + return r; + }); + } if (enable_autorefresh_option) { diff --git a/screenshot/screenshot_01.jpg b/screenshot/screenshot_01.jpg deleted file mode 100644 index 5558856830a70e7316ed4d785b99957c7b69d6cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 588341 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Ð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%0D;4IFMpYB_In~)j@WZsLWA)n;*ciBn^m; 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�Y9&T3)j509eY7rf_1+Luvy&c~LR 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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4437c5b..a15dc01 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -13,7 +13,8 @@ set(SOURCE_FILES tools.cpp CmdLineOptions.cpp page.h - rpccalls.cpp rpccalls.h version.h.in) + rpccalls.cpp rpccalls.h + version.h.in) # make static library called libmyxrm # that we are going to link to diff --git a/src/CmdLineOptions.cpp b/src/CmdLineOptions.cpp index aa2fe07..2a2830a 100644 --- a/src/CmdLineOptions.cpp +++ b/src/CmdLineOptions.cpp @@ -27,14 +27,30 @@ namespace xmreg "use testnet blockchain") ("enable-pusher", value()->default_value(false)->implicit_value(true), "enable pushing signed tx") + ("enable-mixin-details", value()->default_value(false)->implicit_value(true), + "enable mixin details for key images, e.g., timescale, mixin of mixins, in tx context") ("enable-key-image-checker", value()->default_value(false)->implicit_value(true), "enable key images file checker") ("enable-output-key-checker", value()->default_value(false)->implicit_value(true), "enable outputs key file checker") + ("enable-mempool-cache", value()->default_value(true), + "enable caching txs in the mempool") + ("enable-json-api", value()->default_value(true), + "enable JSON REST api") + ("enable-tx-cache", value()->default_value(false)->implicit_value(true), + "enable caching of tx details") + ("show-cache-times", value()->default_value(false)->implicit_value(true), + "show times of getting data from cache vs no cache") + ("enable-block-cache", value()->default_value(false)->implicit_value(true), + "enable caching of block details") ("enable-autorefresh-option", value()->default_value(false)->implicit_value(true), "enable users to have the index page on autorefresh") ("port,p", value()->default_value("8081"), "default port") + ("testnet-url", value()->default_value(""), + "you can specifiy testnet url, if you run it on mainet. link will show on front page to testnet explorer") + ("mainnet-url", value()->default_value(""), + "you can specifiy mainnet url, if you run it on testnet. link will show on front page to mainnet explorer") ("no-blocks-on-index", value()->default_value("10"), "number of last blocks to be shown on index page") ("bc-path,b", value(), @@ -43,8 +59,6 @@ namespace xmreg "A path to crt file for ssl (https) functionality") ("ssl-key-file", value(), "A path to key file for ssl (https) functionality") - ("custom-db-path,c", value(), - "path to the custom lmdb database used for searching things") ("deamon-url,d", value()->default_value("http:://127.0.0.1:18081"), "monero address string"); diff --git a/src/MicroCore.cpp b/src/MicroCore.cpp index 66e4124..a75f24a 100644 --- a/src/MicroCore.cpp +++ b/src/MicroCore.cpp @@ -17,344 +17,344 @@ namespace namespace xmreg { - /** - * The constructor is interesting, as - * m_mempool and m_blockchain_storage depend - * on each other. - * - * So basically m_mempool is initialized with - * reference to Blockchain (i.e., Blockchain&) - * and m_blockchain_storage is initialized with - * reference to m_mempool (i.e., tx_memory_pool&) - * - * The same is done in cryptonode::core. - */ - MicroCore::MicroCore(): - m_mempool(m_blockchain_storage), - m_blockchain_storage(m_mempool) - {} - - - /** - * Initialized the MicroCore object. - * - * Create BlockchainLMDB on the heap. - * Open database files located in blockchain_path. - * Initialize m_blockchain_storage with the BlockchainLMDB object. - */ - bool - MicroCore::init(const string& _blockchain_path) - { - int db_flags = 0; - - blockchain_path = _blockchain_path; +/** + * The constructor is interesting, as + * m_mempool and m_blockchain_storage depend + * on each other. + * + * So basically m_mempool is initialized with + * reference to Blockchain (i.e., Blockchain&) + * and m_blockchain_storage is initialized with + * reference to m_mempool (i.e., tx_memory_pool&) + * + * The same is done in cryptonode::core. + */ +MicroCore::MicroCore(): + m_mempool(m_blockchain_storage), + m_blockchain_storage(m_mempool) +{} + + +/** + * Initialized the MicroCore object. + * + * Create BlockchainLMDB on the heap. + * Open database files located in blockchain_path. + * Initialize m_blockchain_storage with the BlockchainLMDB object. + */ +bool +MicroCore::init(const string& _blockchain_path) +{ + int db_flags = 0; - //db_flags |= MDB_RDONLY; - db_flags |= MDB_NOLOCK; - //db_flags |= MDB_SYNC; + blockchain_path = _blockchain_path; - // uint64_t DEFAULT_FLAGS = MDB_NOMETASYNC | MDB_NORDAHEAD; + //db_flags |= MDB_RDONLY; + db_flags |= MDB_NOLOCK; + //db_flags |= MDB_SYNC; - //db_flags = DEFAULT_FLAGS; + // uint64_t DEFAULT_FLAGS = MDB_NOMETASYNC | MDB_NORDAHEAD; - HardFork* m_hardfork = nullptr; + //db_flags = DEFAULT_FLAGS; - BlockchainDB* db = nullptr; - db = new BlockchainLMDB(); + HardFork* m_hardfork = nullptr; - bool use_testnet {false}; + BlockchainDB* db = nullptr; + db = new BlockchainLMDB(); - uint64_t hard_fork_version_1_till = use_testnet ? testnet_hard_fork_version_1_till : mainnet_hard_fork_version_1_till; + bool use_testnet {false}; - m_hardfork = new HardFork(*db, 1, hard_fork_version_1_till); + uint64_t hard_fork_version_1_till = use_testnet ? testnet_hard_fork_version_1_till : mainnet_hard_fork_version_1_till; - try - { - // try opening lmdb database files - db->open(blockchain_path, db_flags); - } - catch (const std::exception& e) - { - cerr << "Error opening database: " << e.what(); - return false; - } + m_hardfork = new HardFork(*db, 1, hard_fork_version_1_till); - // check if the blockchain database - // is successful opened - if(!db->is_open()) - { - return false; - } - - // initialize Blockchain object to manage - // the database. - return m_blockchain_storage.init(db, m_hardfork, false); + try + { + // try opening lmdb database files + db->open(blockchain_path, db_flags); } - - /** - * Get m_blockchain_storage. - * Initialize m_blockchain_storage with the BlockchainLMDB object. - */ - Blockchain& - MicroCore::get_core() + catch (const std::exception& e) { - return m_blockchain_storage; + cerr << "Error opening database: " << e.what(); + return false; } - /** - * Get block by its height - * - * returns true if success - */ - bool - MicroCore::get_block_by_height(const uint64_t& height, block& blk) + // check if the blockchain database + // is successful opened + if(!db->is_open()) { - try - { - blk = m_blockchain_storage.get_db().get_block_from_height(height); - } - catch (const BLOCK_DNE& e) - { - cerr << "Block of height " << height - << " not found in the blockchain!" - << e.what() - << endl; - - return false; - } - catch (const DB_ERROR& e) - { - cerr << "Blockchain access error when getting block " << height - << e.what() - << endl; - - return false; - } - catch (...) - { - cerr << "Something went terribly wrong when getting block " << height - << endl; - - return false; - } - - return true; + return false; } + // initialize Blockchain object to manage + // the database. + return m_blockchain_storage.init(db, m_hardfork, false); +} +/** +* Get m_blockchain_storage. +* Initialize m_blockchain_storage with the BlockchainLMDB object. +*/ +Blockchain& +MicroCore::get_core() +{ + return m_blockchain_storage; +} - /** - * Get transaction tx from the blockchain using it hash - */ - bool - MicroCore::get_tx(const crypto::hash& tx_hash, transaction& tx) +/** + * Get block by its height + * + * returns true if success + */ +bool +MicroCore::get_block_by_height(const uint64_t& height, block& blk) +{ + try { - if (m_blockchain_storage.have_tx(tx_hash)) - { - // get transaction with given hash - tx = m_blockchain_storage.get_db().get_tx(tx_hash); - } - else - { - cerr << "MicroCore::get_tx tx does not exist in blockchain: " << tx_hash << endl; - return false; - } - - - return true; + blk = m_blockchain_storage.get_db().get_block_from_height(height); } + catch (const BLOCK_DNE& e) + { + cerr << "Block of height " << height + << " not found in the blockchain!" + << e.what() + << endl; - bool - MicroCore::get_tx(const string& tx_hash_str, transaction& tx) + return false; + } + catch (const DB_ERROR& e) { + cerr << "Blockchain access error when getting block " << height + << e.what() + << endl; - // parse tx hash string to hash object - crypto::hash tx_hash; + return false; + } + catch (...) + { + cerr << "Something went terribly wrong when getting block " << height + << endl; - if (!xmreg::parse_str_secret_key(tx_hash_str, tx_hash)) - { - cerr << "Cant parse tx hash: " << tx_hash_str << endl; - return false; - } + return false; + } + return true; +} - if (!get_tx(tx_hash, tx)) - { - return false; - } - return true; +/** + * Get transaction tx from the blockchain using it hash + */ +bool +MicroCore::get_tx(const crypto::hash& tx_hash, transaction& tx) +{ + if (m_blockchain_storage.have_tx(tx_hash)) + { + // get transaction with given hash + tx = m_blockchain_storage.get_db().get_tx(tx_hash); + } + else + { + cerr << "MicroCore::get_tx tx does not exist in blockchain: " << tx_hash << endl; + return false; } + return true; +} + +bool +MicroCore::get_tx(const string& tx_hash_str, transaction& tx) +{ + // parse tx hash string to hash object + crypto::hash tx_hash; - /** - * Find output with given public key in a given transaction - */ - bool - MicroCore::find_output_in_tx(const transaction& tx, - const public_key& output_pubkey, - tx_out& out, - size_t& output_index) + if (!xmreg::parse_str_secret_key(tx_hash_str, tx_hash)) { + cerr << "Cant parse tx hash: " << tx_hash_str << endl; + return false; + } - size_t idx {0}; + if (!get_tx(tx_hash, tx)) + { + return false; + } - // search in the ouputs for an output which - // public key matches to what we want - auto it = std::find_if(tx.vout.begin(), tx.vout.end(), - [&](const tx_out& o) - { - const txout_to_key& tx_in_to_key - = boost::get(o.target); - ++idx; + return true; +} - return tx_in_to_key.key == output_pubkey; - }); - if (it != tx.vout.end()) - { - // we found the desired public key - out = *it; - output_index = idx > 0 ? idx - 1 : idx; - //cout << idx << " " << output_index << endl; - return true; - } +/** + * Find output with given public key in a given transaction + */ +bool +MicroCore::find_output_in_tx(const transaction& tx, + const public_key& output_pubkey, + tx_out& out, + size_t& output_index) +{ - return false; - } + size_t idx {0}; - /** - * Returns tx hash in a given block which - * contains given output's public key - */ - bool - MicroCore::get_tx_hash_from_output_pubkey(const public_key& output_pubkey, - const uint64_t& block_height, - crypto::hash& tx_hash, - cryptonote::transaction& tx_found) - { + // search in the ouputs for an output which + // public key matches to what we want + auto it = std::find_if(tx.vout.begin(), tx.vout.end(), + [&](const tx_out& o) + { + const txout_to_key& tx_in_to_key + = boost::get(o.target); - tx_hash = null_hash; + ++idx; - // get block of given height - block blk; - if (!get_block_by_height(block_height, blk)) - { - cerr << "Cant get block of height: " << block_height << endl; - return false; - } + return tx_in_to_key.key == output_pubkey; + }); + if (it != tx.vout.end()) + { + // we found the desired public key + out = *it; + output_index = idx > 0 ? idx - 1 : idx; - // get all transactions in the block found - // initialize the first list with transaction for solving - // the block i.e. coinbase. - list txs {blk.miner_tx}; - list missed_txs; + //cout << idx << " " << output_index << endl; - if (!m_blockchain_storage.get_transactions(blk.tx_hashes, txs, missed_txs)) - { - cerr << "Cant find transcations in block: " << block_height << endl; - return false; - } + return true; + } - if (!missed_txs.empty()) - { - cerr << "Transactions not found in blk: " << block_height << endl; + return false; +} - for (const crypto::hash& h : missed_txs) - { - cerr << " - tx hash: " << h << endl; - } - return false; - } +/** + * Returns tx hash in a given block which + * contains given output's public key + */ +bool +MicroCore::get_tx_hash_from_output_pubkey(const public_key& output_pubkey, + const uint64_t& block_height, + crypto::hash& tx_hash, + cryptonote::transaction& tx_found) +{ + tx_hash = null_hash; - // search outputs in each transactions - // until output with pubkey of interest is found - for (const transaction& tx : txs) - { + // get block of given height + block blk; + if (!get_block_by_height(block_height, blk)) + { + cerr << "Cant get block of height: " << block_height << endl; + return false; + } - tx_out found_out; - // we dont need here output_index - size_t output_index; + // get all transactions in the block found + // initialize the first list with transaction for solving + // the block i.e. coinbase. + list txs {blk.miner_tx}; + list missed_txs; - if (find_output_in_tx(tx, output_pubkey, found_out, output_index)) - { - // we found the desired public key - tx_hash = get_transaction_hash(tx); - tx_found = tx; + if (!m_blockchain_storage.get_transactions(blk.tx_hashes, txs, missed_txs)) + { + cerr << "Cant find transcations in block: " << block_height << endl; + return false; + } - return true; - } + if (!missed_txs.empty()) + { + cerr << "Transactions not found in blk: " << block_height << endl; + for (const crypto::hash& h : missed_txs) + { + cerr << " - tx hash: " << h << endl; } return false; } - uint64_t - MicroCore::get_blk_timestamp(uint64_t blk_height) + // search outputs in each transactions + // until output with pubkey of interest is found + for (const transaction& tx : txs) { - cryptonote::block blk; - if (!get_block_by_height(blk_height, blk)) + tx_out found_out; + + // we dont need here output_index + size_t output_index; + + if (find_output_in_tx(tx, output_pubkey, found_out, output_index)) { - cerr << "Cant get block by height: " << blk_height << endl; - return 0; + // we found the desired public key + tx_hash = get_transaction_hash(tx); + tx_found = tx; + + return true; } - return blk.timestamp; } + return false; +} + - /** - * De-initialized Blockchain. - * - * since blockchain is opened as MDB_RDONLY - * need to manually free memory taken on heap - * by BlockchainLMDB - */ - MicroCore::~MicroCore() +uint64_t +MicroCore::get_blk_timestamp(uint64_t blk_height) +{ + cryptonote::block blk; + + if (!get_block_by_height(blk_height, blk)) { - delete &m_blockchain_storage.get_db(); + cerr << "Cant get block by height: " << blk_height << endl; + return 0; } + return blk.timestamp; +} - bool - init_blockchain(const string& path, - MicroCore& mcore, - Blockchain*& core_storage) - { - // initialize the core using the blockchain path - if (!mcore.init(path)) - { - cerr << "Error accessing blockchain." << endl; - return false; - } +/** + * De-initialized Blockchain. + * + * since blockchain is opened as MDB_RDONLY + * need to manually free memory taken on heap + * by BlockchainLMDB + */ +MicroCore::~MicroCore() +{ + delete &m_blockchain_storage.get_db(); +} - // get the high level Blockchain object to interact - // with the blockchain lmdb database - core_storage = &(mcore.get_core()); - return true; - } +bool +init_blockchain(const string& path, + MicroCore& mcore, + Blockchain*& core_storage) +{ - string - MicroCore::get_blkchain_path() + // initialize the core using the blockchain path + if (!mcore.init(path)) { - return blockchain_path; + cerr << "Error accessing blockchain." << endl; + return false; } + // get the high level Blockchain object to interact + // with the blockchain lmdb database + core_storage = &(mcore.get_core()); + + return true; +} + +string +MicroCore::get_blkchain_path() +{ + return blockchain_path; +} + } diff --git a/src/mylmdb.h b/src/mylmdb.h deleted file mode 100644 index ead7edf..0000000 --- a/src/mylmdb.h +++ /dev/null @@ -1,755 +0,0 @@ -// -// Created by mwo on 27/04/16. -// -#ifndef XMRLMDBCPP_MYLMDB_H -#define XMRLMDBCPP_MYLMDB_H - -#include "../ext/lmdb++.h" - -#include -#include - -namespace xmreg -{ - - using epee::string_tools::pod_to_hex; - using epee::string_tools::hex_to_pod; - - using namespace std; - - - - /** - * Stores info about outputs useful - * for checking which ouputs belong to a - * given address and viewkey - */ - struct output_info - { - crypto::public_key out_pub_key; - crypto::hash tx_hash; - crypto::public_key tx_pub_key; - uint64_t amount; - uint64_t index_in_tx; - }; - - std::ostream& operator<<(std::ostream& os, const output_info& out_info) - { - os << ", out_pub_key: " << out_info.out_pub_key - << ", tx_hash: " << out_info.tx_hash - << ", tx_pub_key: " << out_info.tx_pub_key - << ", amount: " << XMR_AMOUNT(out_info.amount) - << ", index_in_tx: " << out_info.index_in_tx; - - return os; - } - - class MyLMDB - { - - - static const uint64_t DEFAULT_MAPSIZE = 30UL * 1024UL * 1024UL * 1024UL; /* 30 GiB */ - static const uint64_t DEFAULT_NO_DBs = 10; - - - string m_db_path; - - uint64_t m_mapsize; - uint64_t m_no_dbs; - - lmdb::env m_env; - - - public: - MyLMDB(string _path, - uint64_t _mapsize = DEFAULT_MAPSIZE, - uint64_t _no_dbs = DEFAULT_NO_DBs) - : m_db_path {_path}, - m_mapsize {_mapsize}, - m_no_dbs {_no_dbs}, - m_env {nullptr} - { - create_and_open_env(); - } - - bool - create_and_open_env() - { - try - { m_env = lmdb::env::create(); - m_env.set_mapsize(m_mapsize); - m_env.set_max_dbs(m_no_dbs); - m_env.open(m_db_path.c_str(), MDB_CREATE, 0664); - } - catch (lmdb::error& e ) - { - cerr << e.what() << endl; - return false; - } - - return true; - } - - - bool - write_key_images(const transaction& tx) - { - crypto::hash tx_hash = get_transaction_hash(tx); - - string tx_hash_str = pod_to_hex(tx_hash); - - vector key_images - = xmreg::get_key_images(tx); - - lmdb::txn wtxn {nullptr}; - lmdb::dbi wdbi {0}; - - unsigned int flags = MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED; - - try - { - wtxn = lmdb::txn::begin(m_env); - wdbi = lmdb::dbi::open(wtxn, "key_images", flags); - } - catch (lmdb::error& e ) - { - cerr << e.what() << endl; - return false; - } - - for (const cryptonote::txin_to_key& key_image: key_images) - { - string key_img_str = pod_to_hex(key_image.k_image); - - lmdb::val key_img_val {key_img_str}; - lmdb::val tx_hash_val {tx_hash_str}; - - wdbi.put(wtxn, key_img_val, tx_hash_val); - } - - try - { - wtxn.commit(); - } - catch (lmdb::error& e ) - { - cerr << e.what() << endl; - return false; - } - - return true; - } - - bool - write_output_public_keys(const transaction& tx, const block& blk) - { - crypto::hash tx_hash = get_transaction_hash(tx); - - crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx); - - string tx_hash_str = pod_to_hex(tx_hash); - - vector> outputs = - xmreg::get_ouputs_tuple(tx); - - lmdb::txn wtxn {nullptr}; - lmdb::dbi wdbi1 {0}; - lmdb::dbi wdbi2 {0}; - lmdb::dbi wdbi3 {0}; - - unsigned int flags = MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED; - - try - { - wtxn = lmdb::txn::begin(m_env); - wdbi1 = lmdb::dbi::open(wtxn, "output_public_keys", flags); - wdbi2 = lmdb::dbi::open(wtxn, "output_amounts", flags); - wdbi3 = lmdb::dbi::open(wtxn, "output_info", - flags | MDB_INTEGERKEY | MDB_INTEGERDUP); - } - catch (lmdb::error& e ) - { - cerr << e.what() << endl; - return false; - } - - for (auto& output: outputs) - { - - public_key out_pub_key = std::get<0>(output).key; - - string public_key_str = pod_to_hex(out_pub_key); - - lmdb::val public_key_val {public_key_str}; - lmdb::val tx_hash_val {tx_hash_str}; - - uint64_t amount = std::get<1>(output); - - lmdb::val amount_val {static_cast(&amount), sizeof(amount)}; - - uint64_t index_in_tx = std::get<2>(output); - - output_info out_info {out_pub_key, tx_hash, - tx_pub_key, amount, - index_in_tx}; - - uint64_t out_timestamp = blk.timestamp; - - lmdb::val out_timestamp_val {static_cast(&out_timestamp), - sizeof(out_timestamp)}; - lmdb::val out_info_val {static_cast(&out_info), - sizeof(out_info)}; - - wdbi1.put(wtxn, public_key_val, tx_hash_val); - wdbi2.put(wtxn, public_key_val, amount_val); - wdbi3.put(wtxn, out_timestamp_val, out_info_val); - } - - try - { - wtxn.commit(); - } - catch (lmdb::error& e ) - { - cerr << e.what() << endl; - return false; - } - - return true; - } - - bool - write_tx_public_key(const transaction& tx) - { - crypto::hash tx_hash = get_transaction_hash(tx); - - string tx_hash_str = pod_to_hex(tx_hash); - - unsigned int flags = MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED; - - public_key pk = get_tx_pub_key_from_extra(tx); - - string pk_str = pod_to_hex(pk); - - try - { - lmdb::txn wtxn = lmdb::txn::begin(m_env); - lmdb::dbi wdbi = lmdb::dbi::open(wtxn, "tx_public_keys", flags); - - //cout << "Saving public_key: " << pk_str << endl; - - lmdb::val public_key_val {pk_str}; - lmdb::val tx_hash_val {tx_hash_str}; - - wdbi.put(wtxn, public_key_val, tx_hash_val); - - wtxn.commit(); - } - catch (lmdb::error& e) - { - cerr << e.what() << endl; - return false; - } - - return true; - } - - bool - write_payment_id(const transaction& tx) - { - crypto::hash tx_hash = get_transaction_hash(tx); - - string tx_hash_str = pod_to_hex(tx_hash); - - crypto::hash payment_id; - crypto::hash8 payment_id8; - - get_payment_id(tx, payment_id, payment_id8); - - if (payment_id == null_hash) - { - return true; - } - - unsigned int flags = MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED; - - string payment_id_str = pod_to_hex(payment_id); - - try - { - lmdb::txn wtxn = lmdb::txn::begin(m_env); - lmdb::dbi wdbi = lmdb::dbi::open(wtxn, "payments_id", flags); - - //cout << "Saving payiment_id: " << payment_id_str << endl; - - lmdb::val payment_id_val {payment_id_str}; - lmdb::val tx_hash_val {tx_hash_str}; - - wdbi.put(wtxn, payment_id_val, tx_hash_val); - - wtxn.commit(); - } - catch (lmdb::error& e) - { - cerr << e.what() << endl; - return false; - } - - return true; - } - - bool - write_encrypted_payment_id(const transaction& tx) - { - crypto::hash tx_hash = get_transaction_hash(tx); - - string tx_hash_str = pod_to_hex(tx_hash); - - crypto::hash payment_id; - crypto::hash8 payment_id8; - - get_payment_id(tx, payment_id, payment_id8); - - if (payment_id8 == null_hash8) - { - return true; - } - - unsigned int flags = MDB_CREATE | MDB_DUPSORT | MDB_DUPFIXED; - - string payment_id_str = pod_to_hex(payment_id8); - - try - { - lmdb::txn wtxn = lmdb::txn::begin(m_env); - lmdb::dbi wdbi = lmdb::dbi::open(wtxn, "encrypted_payments_id", flags); - - //cout << "Saving encrypted payiment_id: " << payment_id_str << endl; - //string wait_for_enter; - //cin >> wait_for_enter; - - lmdb::val payment_id_val {payment_id_str}; - lmdb::val tx_hash_val {tx_hash_str}; - - wdbi.put(wtxn, payment_id_val, tx_hash_val); - - wtxn.commit(); - } - catch (lmdb::error& e) - { - cerr << e.what() << endl; - return false; - } - - return true; - } - -// // this seems to be not needed as outputs are written based on timestamps -// -// bool -// write_block_timestamp(uint64_t& blk_timestamp, uint64_t& blk_height) -// { -// -// unsigned int flags = MDB_CREATE | MDB_INTEGERKEY; -// -// try -// { -// lmdb::txn wtxn = lmdb::txn::begin(m_env); -// lmdb::dbi wdbi = lmdb::dbi::open(wtxn, "block_timestamps", flags); -// -// lmdb::val blk_timestamp_val {static_cast(&blk_timestamp), -// sizeof(blk_timestamp)}; -// lmdb::val blk_height_val {static_cast(&blk_height), -// sizeof(blk_height)}; -// -// wdbi.put(wtxn, blk_timestamp_val, blk_height_val); -// -// wtxn.commit(); -// } -// catch (lmdb::error& e) -// { -// cerr << e.what() << endl; -// return false; -// } -// -// return true; -// } - - bool - search(const string& key, - vector& found_tx_hashes, - const string& db_name = "key_images") - { - unsigned int flags = MDB_DUPSORT | MDB_DUPFIXED; - - try - { - - lmdb::txn rtxn = lmdb::txn::begin(m_env, nullptr, MDB_RDONLY); - lmdb::dbi rdbi = lmdb::dbi::open(rtxn, db_name.c_str(), flags); - lmdb::cursor cr = lmdb::cursor::open(rtxn, rdbi); - - lmdb::val key_to_find{key}; - lmdb::val tx_hash_val; - - // set cursor the the first item - if (cr.get(key_to_find, tx_hash_val, MDB_SET)) - { - //cout << key_val_to_str(key_to_find, tx_hash_val) << endl; - found_tx_hashes.push_back(string(tx_hash_val.data(), tx_hash_val.size())); - - // process other values for the same key - while (cr.get(key_to_find, tx_hash_val, MDB_NEXT_DUP)) - { - //cout << key_val_to_str(key_to_find, tx_hash_val) << endl; - found_tx_hashes.push_back(string(tx_hash_val.data(), tx_hash_val.size())); - } - } - else - { - return false; - } - - cr.close(); - rtxn.abort(); - - } - catch (lmdb::error& e) - { - cerr << e.what() << endl; - return false; - } - - return true; - } - - bool - get_output_amount(const string& key, - uint64_t& amount, - const string& db_name = "output_amounts") - { - - unsigned int flags = 0; - - try - { - - lmdb::txn rtxn = lmdb::txn::begin(m_env, nullptr, MDB_RDONLY); - lmdb::dbi rdbi = lmdb::dbi::open(rtxn, db_name.c_str(), flags); - - lmdb::val key_to_find{key}; - lmdb::val amount_val; - - if(!rdbi.get(rtxn, key_to_find, amount_val)) - { - return false; - } - - amount = *(amount_val.data()); - - rtxn.abort(); - - } - catch (lmdb::error& e) - { - cerr << e.what() << endl; - return false; - } - - return true; - } - - - bool - get_output_info(uint64_t key_timestamp, - vector& out_infos, - const string& db_name = "output_info") - { - - unsigned int flags = 0; - - try - { - - lmdb::txn rtxn = lmdb::txn::begin(m_env, nullptr, MDB_RDONLY); - lmdb::dbi rdbi = lmdb::dbi::open(rtxn, db_name.c_str(), flags); - - lmdb::val key_to_find{static_cast(&key_timestamp), - sizeof(key_timestamp)}; - lmdb::val info_val; - - lmdb::cursor cr = lmdb::cursor::open(rtxn, rdbi); - - // set cursor the the first item - if (cr.get(key_to_find, info_val, MDB_SET_RANGE)) - { - out_infos.push_back(*(info_val.data())); - - // process other values for the same key - while (cr.get(key_to_find, info_val, MDB_NEXT_DUP)) - { - //cout << key_val_to_str(key_to_find, tx_hash_val) << endl; - out_infos.push_back(*(info_val.data())); - } - } - else - { - return false; - } - - rtxn.abort(); - - } - catch (lmdb::error& e) - { - cerr << e.what() << endl; - return false; - } - - return true; - } - - bool - get_output_info_range(uint64_t key_timestamp_start, - uint64_t key_timestamp_end, - vector>& out_infos, - const string& db_name = "output_info") - { - - unsigned int flags = 0; - - try - { - lmdb::txn rtxn = lmdb::txn::begin(m_env, nullptr, MDB_RDONLY); - lmdb::dbi rdbi = lmdb::dbi::open(rtxn, db_name.c_str(), flags); - - lmdb::val key_to_find{static_cast(&key_timestamp_start), - sizeof(key_timestamp_start)}; - lmdb::val info_val; - - lmdb::cursor cr = lmdb::cursor::open(rtxn, rdbi); - - uint64_t current_timestamp = key_timestamp_start; - - // set cursor the the first item - if (cr.get(key_to_find, info_val, MDB_SET_RANGE)) - { - - current_timestamp = *key_to_find.data(); - - if (current_timestamp > key_timestamp_end) - { - return false; - } - - out_infos.push_back(make_pair( - current_timestamp, - *(info_val.data()))); - - // process other values for the same key - while (cr.get(key_to_find, info_val, MDB_NEXT)) - { - current_timestamp = *key_to_find.data(); - - if (current_timestamp > key_timestamp_end) - { - break; - } - - out_infos.push_back(make_pair( - current_timestamp, - *(info_val.data()))); - } - } - else - { - return false; - } - - rtxn.abort(); - - } - catch (lmdb::error& e) - { - cerr << e.what() << endl; - return false; - } - - return true; - } - - /** - * Returns sorted and unique tx hashes withing a - * given timestamp range - * - * @param key_timestamp_start - * @param key_timestamp_end - * @param out_txs - * @return bool - */ - bool - get_txs_from_timestamp_range(uint64_t key_timestamp_start, - uint64_t key_timestamp_end, - vector& out_txs) - { - using output_pair = pair; - - auto sort_by_timestamp = [](const output_pair& l, - const output_pair& r) - { - return l.first < r.first; - }; - - vector out_infos; - - if (get_output_info_range(key_timestamp_start, - key_timestamp_end, - out_infos)) - { - - set unique_txs(sort_by_timestamp); - - for (auto oi: out_infos) - unique_txs.insert(oi); - - for (auto ut: unique_txs) - out_txs.push_back(ut.second.tx_hash); - - return true; - } - - return false; - } - - - - void - for_all_outputs( - std::function f) - { - unsigned int flags = MDB_DUPSORT | MDB_DUPFIXED; - - try - { - - lmdb::txn rtxn = lmdb::txn::begin(m_env, nullptr, MDB_RDONLY); - lmdb::dbi rdbi = lmdb::dbi::open(rtxn, "output_info", flags); - lmdb::cursor cr = lmdb::cursor::open(rtxn, rdbi); - - lmdb::val key_to_find; - lmdb::val amount_val; - - - // process all values for the same key - while (cr.get(key_to_find, amount_val, MDB_NEXT)) - { - public_key pub_key; - - hex_to_pod(string(key_to_find.data(), key_to_find.size()), - pub_key); - - output_info out_info = *(amount_val.data()); - - if (f(pub_key, out_info) == false) - { - break; - } - } - - cr.close(); - rtxn.abort(); - - } - catch (lmdb::error& e) - { - cerr << e.what() << endl; - } - } - - - void - print_all(const string& db_name) - { - unsigned int flags = MDB_DUPSORT | MDB_DUPFIXED; - - try - { - - lmdb::txn rtxn = lmdb::txn::begin(m_env, nullptr, MDB_RDONLY); - lmdb::dbi rdbi = lmdb::dbi::open(rtxn, db_name.c_str(), flags); - lmdb::cursor cr = lmdb::cursor::open(rtxn, rdbi); - - lmdb::val key_to_find; - lmdb::val tx_hash_val; - - - // process other values for the same key - while (cr.get(key_to_find, tx_hash_val, MDB_NEXT)) - { - cout << key_val_to_str(key_to_find, tx_hash_val) << endl; - } - - cr.close(); - rtxn.abort(); - - } - catch (lmdb::error& e) - { - cerr << e.what() << endl; - } - } - - static uint64_t - get_blockchain_height(string blk_path = "/home/mwo/.blockchain/lmdb") - { - uint64_t height {0}; - - try - { - auto env = lmdb::env::create(); - env.set_mapsize(DEFAULT_MAPSIZE * 3); - env.set_max_dbs(20); - env.open(blk_path.c_str(), MDB_CREATE, 0664); - - //auto rtxn = lmdb::txn::begin(env, nullptr, MDB_RDONLY); - auto rtxn = lmdb::txn::begin(env, nullptr); - auto rdbi = lmdb::dbi::open(rtxn, "blocks"); - - MDB_stat stats = rdbi.stat(rtxn); - - height = static_cast(stats.ms_entries); - - rtxn.abort(); - } - catch (lmdb::error& e) - { - cerr << e.what() << endl; - return height; - } - catch (exception& e) - { - cerr << e.what() << endl; - return height; - } - - //cout << height << endl; - - return height; - - } - - string - key_val_to_str(const lmdb::val& key, const lmdb::val& val) - { - return "key: " + string(key.data(), key.size()) - + ", val: " + string(val.data(), val.size()); - } - - - - }; - -} - -#endif //XMRLMDBCPP_MYLMDB_H diff --git a/src/page.h b/src/page.h index eb3bc45..8c794fb 100644 --- a/src/page.h +++ b/src/page.h @@ -16,9 +16,11 @@ #include "MicroCore.h" #include "tools.h" #include "rpccalls.h" -#include "mylmdb.h" #include "../ext/crow/http_request.h" +#include "../ext/vpetrigocaches/cache.hpp" +#include "../ext/vpetrigocaches/lru_cache_policy.hpp" +#include "../ext/vpetrigocaches/fifo_cache_policy.hpp" #include #include #include @@ -44,56 +46,61 @@ #define TMPL_MY_RAWOUTPUTKEYS TMPL_DIR "/rawoutputkeys.html" #define TMPL_MY_CHECKRAWOUTPUTKEYS TMPL_DIR "/checkrawoutputkeys.html" -namespace xmreg -{ -using namespace cryptonote; -using namespace crypto; -using namespace std; -// define a checker to test if a structure has "tx_blob" -// member variable. I use modified daemon with few extra -// bits and pieces here and there. One of them is -// tx_blob in cryptonote::tx_info structure -// thus I check if I run my version, or just -// generic one -DEFINE_MEMBER_CHECKER(tx_blob) +// basic info about tx to be stored in cashe. +// we need to store block_no and timestamp, +// as this time and number of confirmation needs +// to be updated between requests. Just cant +// get it from cash, as it will be old very soon +struct tx_info_cache +{ + uint64_t block_no; + uint64_t timestamp; + mstch::map tx_map; -// define getter to get tx_blob, i.e., get_tx_blob function -// as string if exists. the getter return empty string if -// tx_blob does not exist -DEFINE_MEMBER_GETTER(tx_blob, string) + // custom key for use in cache. + // cache uses unordeded map for keys + struct key + { + crypto::hash tx_hash; + bool detailed; + bool operator==(const key &other) const + { + return (tx_hash == other.tx_hash && detailed == other.detailed); + } + }; +}; -/** - * Check if a given header filed contains value string - * - * @param req - * @param field - * @param value - * @return string - */ -string -does_header_has(const crow::request& req, - const string& field = "Accept", - const string& value = "q=.2, */*; q=.2") +// indect overload of hash for tx_info_cache::key +namespace std { - string accept = req.get_header_value(field); - - if (!accept.empty()) + template<> + struct hash { - if (accept.find(value) != std::string::npos) + size_t operator()(const tx_info_cache::key& k) const { - return accept; - } - } - - return string {}; + size_t const h1 ( std::hash{}(k.tx_hash) ); + size_t const h2 ( std::hash{}(k.detailed) ); + return h1 ^ (h2 << 1); + }; + }; } +namespace xmreg +{ + + +using namespace cryptonote; +using namespace crypto; +using namespace std; + +using epee::string_tools::pod_to_hex; +using epee::string_tools::hex_to_pod; /** * @brief The tx_details struct @@ -121,9 +128,7 @@ struct tx_details crypto::hash payment_id = null_hash; // normal crypto::hash8 payment_id8 = null_hash8; // encrypted - string json_representation; - - std::vector > signatures; + std::vector> signatures; // key images of inputs vector input_key_imgs; @@ -132,38 +137,39 @@ struct tx_details vector> output_pub_keys; mstch::map - get_mstch_map() + get_mstch_map() const { // remove "<" and ">" from the hash string - string tx_hash_str = pod_to_hex(hash); + string tx_hash_str = REMOVE_HASH_BRAKETS(fmt::format("{:s}", hash)); - string tx_prefix_hash_str = pod_to_hex(prefix_hash); + string tx_prefix_hash_str = REMOVE_HASH_BRAKETS(fmt::format("{:s}", prefix_hash)); - string tx_pk_str = pod_to_hex(pk); + string tx_pk_str = REMOVE_HASH_BRAKETS(fmt::format("{:s}", pk)); //cout << "payment_id: " << payment_id << endl; - string pid_str = pod_to_hex(payment_id); - string pid8_str = pod_to_hex(payment_id8); + string pid_str = REMOVE_HASH_BRAKETS(fmt::format("{:s}", payment_id)); + string pid8_str = REMOVE_HASH_BRAKETS(fmt::format("{:s}", payment_id8)); string mixin_str {"N/A"}; string fee_str {"N/A"}; string fee_short_str {"N/A"}; + const double& xmr_amount = XMR_AMOUNT(fee); if (!input_key_imgs.empty()) { mixin_str = std::to_string(mixin_no - 1); - fee_str = fmt::format("{:0.6f}", XMR_AMOUNT(fee)); - fee_short_str = fmt::format("{:0.3f}", XMR_AMOUNT(fee)); + fee_str = fmt::format("{:0.6f}", xmr_amount); + fee_short_str = fmt::format("{:0.3f}", xmr_amount); } - //cout << "extra: " << extra_str << endl; + const double& tx_size = static_cast(size)/1024.0; mstch::map txd_map { - {"hash" , tx_hash_str}, - {"prefix_hash" , tx_prefix_hash_str}, - {"pub_key" , tx_pk_str}, + {"hash" , pod_to_hex(hash)}, + {"prefix_hash" , pod_to_hex(prefix_hash)}, + {"pub_key" , pod_to_hex(pk)}, {"tx_fee" , fee_str}, {"tx_fee_short" , fee_short_str}, {"sum_inputs" , xmr_amount_to_str(xmr_inputs , "{:0.6f}")}, @@ -175,18 +181,16 @@ struct tx_details {"no_nonrct_inputs" , num_nonrct_inputs}, {"mixin" , mixin_str}, {"blk_height" , blk_height}, - {"version" , std::to_string(version)}, + {"version" , version}, {"has_payment_id" , payment_id != null_hash}, {"has_payment_id8" , payment_id8 != null_hash8}, - {"payment_id" , pid_str}, + {"payment_id" , pod_to_hex(payment_id)}, {"confirmations" , no_confirmations}, {"extra" , get_extra_str()}, - {"payment_id8" , pid8_str}, - {"unlock_time" , std::to_string(unlock_time)}, - {"tx_size" , fmt::format("{:0.4f}", - static_cast(size)/1024.0)}, - {"tx_size_short" , fmt::format("{:0.2f}", - static_cast(size)/1024.0)} + {"payment_id8" , pod_to_hex(payment_id8)}, + {"unlock_time" , unlock_time}, + {"tx_size" , fmt::format("{:0.4f}", tx_size)}, + {"tx_size_short" , fmt::format("{:0.2f}", tx_size)} }; @@ -195,13 +199,11 @@ struct tx_details string - get_extra_str() + get_extra_str() const { - string extra_str = epee::string_tools::buff_to_hex_nodelimer( - string{reinterpret_cast(extra.data()), extra.size()}); - - return extra_str; + return epee::string_tools::buff_to_hex_nodelimer( + string{reinterpret_cast(extra.data()), extra.size()}); } @@ -237,21 +239,17 @@ struct tx_details } }; -class page { - // check if we have tx_blob member in tx_info structure - static const bool HAVE_TX_BLOB { - HAS_MEMBER(cryptonote::tx_info, tx_blob) - }; +class page +{ static const bool FULL_AGE_FORMAT {true}; MicroCore* mcore; Blockchain* core_storage; rpccalls rpc; - time_t server_timestamp; - string lmdb2_path; + atomic server_timestamp; bool testnet; @@ -259,15 +257,21 @@ class page { bool enable_key_image_checker; bool enable_output_key_checker; + bool enable_mixins_details; + bool enable_mempool_cache; + bool enable_tx_cache; + bool enable_block_cache; + bool show_cache_times; bool enable_autorefresh_option; - bool have_custom_lmdb; uint64_t no_of_mempool_tx_of_frontpage; uint64_t no_blocks_on_index; + string testnet_url; + string mainnet_url; // instead of constatnly reading template files // from hard drive for each request, we can read // them only once, when the explorer starts into this map @@ -276,58 +280,92 @@ class page { map template_file; + // alias for easy class typing + template + using lru_cache_t = caches::fixed_sized_cache>; + + + + // alias for easy class typing + template + using fifo_cache_t = caches::fixed_sized_cache>; + + + // this struct is used to keep info about mempool + // txs in FIFO cache. Should speed up processing + // mempool txs for each request + struct mempool_tx_info + { + uint64_t sum_inputs; + uint64_t sum_outputs; + uint64_t no_inputs; + uint64_t no_outputs; + + uint64_t num_nonrct_inputs; + + uint64_t mixin_no; + + string hash; + string fee; + string xmr_inputs_str; + string xmr_outputs_str; + string timestamp; + + string txsize; + }; + + // cache of txs in mempool, so that we dont + // parse their json for each request + fifo_cache_t mempool_tx_json_cache; + + // cache of txs_map of txs in blocks. this is useful for + // index2 page, so that we dont parse txs in each block + // for each request. + fifo_cache_t>> block_tx_cache; + + lru_cache_t tx_context_cache; public: - page(MicroCore* _mcore, Blockchain* _core_storage, - string _deamon_url, string _lmdb2_path, - bool _testnet, bool _enable_pusher, + page(MicroCore* _mcore, + Blockchain* _core_storage, + string _deamon_url, + bool _testnet, + bool _enable_pusher, bool _enable_key_image_checker, bool _enable_output_key_checker, bool _enable_autorefresh_option, - uint64_t _no_blocks_on_index) + bool _enable_mixins_details, + bool _enable_mempool_cache, + bool _enable_tx_cache, + bool _enable_block_cache, + bool _show_cache_times, + uint64_t _no_blocks_on_index, + string _testnet_url, + string _mainnet_url) : mcore {_mcore}, core_storage {_core_storage}, rpc {_deamon_url}, server_timestamp {std::time(nullptr)}, - lmdb2_path {_lmdb2_path}, testnet {_testnet}, enable_pusher {_enable_pusher}, - have_custom_lmdb {false}, enable_key_image_checker {_enable_key_image_checker}, enable_output_key_checker {_enable_output_key_checker}, enable_autorefresh_option {_enable_autorefresh_option}, - no_blocks_on_index {_no_blocks_on_index} + enable_mixins_details {_enable_mixins_details}, + enable_mempool_cache {_enable_mempool_cache}, + enable_tx_cache {_enable_tx_cache}, + enable_block_cache {_enable_block_cache}, + show_cache_times {_show_cache_times}, + no_blocks_on_index {_no_blocks_on_index}, + testnet_url {_testnet_url}, + mainnet_url {_mainnet_url}, + mempool_tx_json_cache(1000), + block_tx_cache(200), + tx_context_cache(1000) { no_of_mempool_tx_of_frontpage = 25; - // just moneky patching now, to check - // if custom lmdb database exist, so that - // we can search for, e.g., key images, - // payments ids. try to open this database. - // if it fails, we assume it does not exist. - // this is ugly check, but will do for now. - // it does not even check if this custom lmdb - // is up to date. - try - { - unique_ptr mylmdb; - - if (bf::is_directory(lmdb2_path)) - { - mylmdb = make_unique(lmdb2_path); - - // if we got to here, it seems that database exist - have_custom_lmdb = true; - } - - } - catch (const std::exception& e) - { - cerr << "Custom lmdb databse seem not to exist. Its not big deal. " - "Just some searches wont be possible" - << endl; - } // read template files for all the pages @@ -351,10 +389,10 @@ public: template_file["checkoutputkeys"] = get_full_page(xmreg::read(TMPL_MY_CHECKRAWOUTPUTKEYS)); template_file["address"] = get_full_page(xmreg::read(TMPL_ADDRESS)); template_file["search_results"] = get_full_page(xmreg::read(TMPL_SEARCH_RESULTS)); + template_file["tx_details"] = xmreg::read(string(TMPL_PARIALS_DIR) + "/tx_details.html"); - template_file["tx_table_head"] = xmreg::read(string(TMPL_PARIALS_DIR) + "/tx_table_head.html"); + template_file["tx_table_header"] = xmreg::read(string(TMPL_PARIALS_DIR) + "/tx_table_header.html"); template_file["tx_table_row"] = xmreg::read(string(TMPL_PARIALS_DIR) + "/tx_table_row.html"); - } /** @@ -370,7 +408,6 @@ public: server_timestamp = std::time(nullptr); uint64_t local_copy_server_timestamp = server_timestamp; - // number of last blocks to show uint64_t no_of_last_blocks {no_blocks_on_index + 1}; @@ -379,22 +416,24 @@ public: // initalise page tempate map with basic info about blockchain mstch::map context { - {"testnet" , testnet}, - {"have_custom_lmdb" , have_custom_lmdb}, - {"refresh" , refresh_page}, - {"height" , std::to_string(height)}, - {"server_timestamp" , xmreg::timestamp_to_str(local_copy_server_timestamp)}, - {"age_format" , string("[h:m:d]")}, - {"page_no" , std::to_string(page_no)}, - {"total_page_no" , std::to_string(height / (no_of_last_blocks))}, - {"is_page_zero" , !bool(page_no)}, - {"no_of_last_blocks", no_of_last_blocks}, - {"next_page" , std::to_string(page_no + 1)}, - {"prev_page" , std::to_string((page_no > 0 ? page_no - 1 : 0))}, + {"testnet" , testnet}, + {"testnet_url" , testnet_url}, + {"mainnet_url" , mainnet_url}, + {"refresh" , refresh_page}, + {"height" , height}, + {"server_timestamp" , xmreg::timestamp_to_str_gm(local_copy_server_timestamp)}, + {"age_format" , string("[h:m:d]")}, + {"page_no" , page_no}, + {"total_page_no" , (height / no_of_last_blocks)}, + {"is_page_zero" , !bool(page_no)}, + {"no_of_last_blocks" , no_of_last_blocks}, + {"next_page" , (page_no + 1)}, + {"prev_page" , (page_no > 0 ? page_no - 1 : 0)}, {"enable_pusher" , enable_pusher}, {"enable_key_image_checker" , enable_key_image_checker}, {"enable_output_key_checker", enable_output_key_checker}, - {"enable_autorefresh_option", enable_autorefresh_option} + {"enable_autorefresh_option", enable_autorefresh_option}, + {"show_cache_times" , show_cache_times} }; context.emplace("txs", mstch::array()); // will keep tx to show @@ -402,24 +441,25 @@ public: mstch::array& txs = boost::get(context["txs"]); // calculate starting and ending block numbers to show - uint64_t start_height = height - no_of_last_blocks * (page_no + 1); - uint64_t end_height = height - no_of_last_blocks * (page_no); + int64_t start_height = height - no_of_last_blocks * (page_no + 1); - // check few conditions to make sure we are whithin the avaliable range - //@TODO its too messed up. needs to find cleaner way. - start_height = start_height > 0 ? start_height : 0; - end_height = end_height < height ? end_height : height; - start_height = start_height > end_height ? 0 : start_height; - end_height = end_height - start_height > no_of_last_blocks - ? no_of_last_blocks : end_height; + // check if start height is not below range + start_height = start_height < 0 ? 0 : start_height; - // previous blk timestamp, initalised to lowest possible value - double prev_blk_timestamp {std::numeric_limits::lowest()}; + int64_t end_height = start_height + no_of_last_blocks - 1; vector blk_sizes; + // measure time of cache based execution, and non-cached execution + double duration_cached {0.0}; + double duration_non_cached {0.0}; + uint64_t cache_hits {0}; + uint64_t cache_misses {0}; + + // loop index + int64_t i = end_height; // iterate over last no_of_last_blocks of blocks - for (uint64_t i = start_height; i <= end_height; ++i) + while (i >= start_height) { // get block at the given height i block blk; @@ -427,6 +467,7 @@ public: if (!mcore->get_block_by_height(i, blk)) { cerr << "Cant get block: " << i << endl; + --i; continue; } @@ -441,88 +482,226 @@ public: blk_sizes.push_back(blk_size); // remove "<" and ">" from the hash string - string blk_hash_str = REMOVE_HASH_BRAKETS(fmt::format("{:s}", blk_hash)); + string blk_hash_str = pod_to_hex(blk_hash); // get block age pair age = get_age(local_copy_server_timestamp, blk.timestamp); context["age_format"] = age.second; - // get time difference [m] between previous and current blocks - string time_delta_str {}; - if (prev_blk_timestamp > std::numeric_limits::lowest()) + if (enable_block_cache && block_tx_cache.Contains(i)) { - time_delta_str = fmt::format("({:06.2f})", - (double(blk.timestamp) - double(prev_blk_timestamp))/60.0); - } + // get txs info in the ith block from + // our cache - // get all transactions in the block found - // initialize the first list with transaction for solving - // the block i.e. coinbase. - list blk_txs {blk.miner_tx}; - list missed_txs; + // start measure time here + auto start = std::chrono::steady_clock::now(); - if (!core_storage->get_transactions(blk.tx_hashes, blk_txs, missed_txs)) - { - cerr << "Cant get transactions in block: " << i << endl; - continue; - } + const vector>& txd_pairs + = block_tx_cache.Get(i); + + // copy tx maps from txs_maps_tmp into txs array, + // that will go to templates + for (const pair& txd_pair: txd_pairs) + { + // we need to check if the given transaction is still + // in the same block as when it was cached. it is possible + // the block got orphaned, and this tx is in mempool + // or different block, and what we have in cache + // is thus wrong + + // but we do this only for first top blocks. no sense + // doing it for all blocks + + bool is_tx_still_in_block_as_expected {true}; + + if (i + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE > height) + { + const crypto::hash& tx_hash = txd_pair.first; + + if (core_storage->have_tx(tx_hash)) + { + try + { + uint64_t tx_height_in_blockchain = + core_storage->get_db().get_tx_block_height(tx_hash); + + // check if height of the given tx that we have in cache, + // denoted by i, is same as what is acctually stored + // in blockchain + if (tx_height_in_blockchain == i) + { + is_tx_still_in_block_as_expected = true; + } + else + { + // if no tx in the given block, just stop + // any futher search. no need. we are going + // to ditch the cache, in a monent + is_tx_still_in_block_as_expected = false; + break; + } + } + catch (const TX_DNE& e) + { + cerr << "Tx from cache" << pod_to_hex(tx_hash) + << " is no longer in the blockchain " + << endl; + + is_tx_still_in_block_as_expected = false; + break; + } + } + else + { + is_tx_still_in_block_as_expected = false; + break; + } + + } // if (i + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE > height) + + + if (!is_tx_still_in_block_as_expected) + { + // if some tx in cache is not in blockchain + // where it should be, its probably better to + // ditch entire cache, as redo it below. + + block_tx_cache.Clear(); + txs.clear(); + i = end_height; + continue; // reado the main loop + } + + // if we got to here, it means that everything went fine + // and no unexpeced things happended. + mstch::map txd_map = boost::get(txd_pair.second); + + // now we need to update age of txs from cashe + if (!boost::get(txd_map["age"]).empty()) + { + txd_map["age"] = age.first; + } + + txs.push_back(txd_map); + + } // for (const pair& txd_pair: txd_pairs) - uint64_t tx_i {0}; + auto duration = std::chrono::duration_cast + (std::chrono::steady_clock::now() - start); - for(list::reverse_iterator rit = blk_txs.rbegin(); - rit != blk_txs.rend(); ++rit) + // cout << "block_tx_json_cache from cache" << endl; + + duration_cached += duration.count(); + + ++cache_hits; + } + else { - const cryptonote::transaction& tx = *rit; + // this is new block. not in cashe. + // need to process its txs and add to cache + + // start measure time here + auto start = std::chrono::steady_clock::now(); + + // get all transactions in the block found + // initialize the first list with transaction for solving + // the block i.e. coinbase. + list blk_txs {blk.miner_tx}; + list missed_txs; + + if (!core_storage->get_transactions(blk.tx_hashes, blk_txs, missed_txs)) + { + cerr << "Cant get transactions in block: " << i << endl; + --i; + continue; + } + + uint64_t tx_i {0}; + + // this vector will go into block_tx cache + // tx_hash , txd_map + vector> txd_pairs; + + for(auto it = blk_txs.begin(); it != blk_txs.end(); ++it) + { + const cryptonote::transaction& tx = *it; + + const tx_details& txd = get_tx_details(tx, false, i, height); - tx_details txd = get_tx_details(tx); + mstch::map txd_map = txd.get_mstch_map(); + + //add age to the txd mstch map + txd_map.insert({"height" , i}); + txd_map.insert({"blk_hash" , blk_hash_str}); + txd_map.insert({"age" , age.first}); + txd_map.insert({"is_ringct" , (tx.version > 1)}); + txd_map.insert({"rct_type" , tx.rct_signatures.type}); + txd_map.insert({"blk_size" , blk_size_str}); + + + // do not show block info for other than first tx in a block + if (tx_i > 0) + { + txd_map["height"] = string(""); + txd_map["age"] = string(""); + txd_map["blk_size"] = string(""); + } - mstch::map txd_map = txd.get_mstch_map(); + txd_pairs.emplace_back(txd.hash, txd_map); - //add age to the txd mstch map - txd_map.insert({"height" , i}); - txd_map.insert({"blk_hash" , blk_hash_str}); - txd_map.insert({"time_delta", time_delta_str}); - txd_map.insert({"age" , age.first}); - txd_map.insert({"is_ringct" , (tx.version > 1)}); - txd_map.insert({"rct_type" , tx.rct_signatures.type}); - txd_map.insert({"blk_size" , blk_size_str}); + ++tx_i; + } // for(list::reverse_iterator rit = blk_txs.rbegin(); - // do not show block info for other than - // last (i.e., first after reverse below) - // tx in the block - if (tx_i < blk_txs.size() - 1) + // copy tx maps from txs_maps_tmp into txs array, + // that will go to templates + for (const pair& txd_pair: txd_pairs) { - txd_map["height"] = string(""); - txd_map["age"] = string(""); - txd_map["time_delta"] = string(""); - txd_map["blk_size"] = string(""); + txs.push_back(boost::get(txd_pair.second)); } - txs.push_back(txd_map); + auto duration = std::chrono::duration_cast + (std::chrono::steady_clock::now() - start); - ++tx_i; - } + duration_non_cached += duration.count(); - // save current's block timestamp as reference for the next one - prev_blk_timestamp = static_cast(blk.timestamp); + ++cache_misses; - } // for (uint64_t i = start_height; i <= end_height; ++i) + if (enable_block_cache) + { + // save in block_tx cache + block_tx_cache.Put(i, txd_pairs); + } + + } // else if (block_tx_json_cache.Contains(i)) + + --i; // go to next block number + + } // while (i <= end_height) // calculate median size of the blocks shown double blk_size_median = xmreg::calc_median(blk_sizes.begin(), blk_sizes.end()); context["blk_size_median"] = fmt::format("{:0.2f}", blk_size_median); - // reverse txs and remove last (i.e., oldest) - // tx. This is done so that time delats - // are easier to calcualte in the above for loop - std::reverse(txs.begin(), txs.end()); + // save computational times for disply in the frontend + + context["construction_time_cached"] = fmt::format( + "{:0.4f}", duration_cached/1.0e6); + + context["construction_time_non_cached"] = fmt::format( + "{:0.4f}", duration_non_cached/1.0e6); + + context["construction_time_total"] = fmt::format( + "{:0.4f}", (duration_non_cached+duration_cached)/1.0e6); + + context["cache_hits"] = cache_hits; + context["cache_misses"] = cache_misses; // get memory pool rendered template - string mempool_html = mempool(); + string mempool_html = mempool(false, no_of_mempool_tx_of_frontpage); // append mempool_html to the index context map context["mempool_info"] = mempool_html; @@ -539,7 +718,7 @@ public: * Render mempool data */ string - mempool(bool add_header_and_footer = false) + mempool(bool add_header_and_footer = false, uint64_t no_of_mempool_tx = 25) { std::vector mempool_txs; @@ -550,7 +729,8 @@ public: // initalise page tempate map with basic info about mempool mstch::map context { - {"mempool_size", std::to_string(mempool_txs.size())}, + {"mempool_size" , mempool_txs.size()}, + {"show_cache_times" , show_cache_times} }; context.emplace("mempooltxs" , mstch::array()); @@ -558,12 +738,36 @@ public: // get reference to blocks template map to be field below mstch::array& txs = boost::get(context["mempooltxs"]); - uint64_t mempool_size_bytes {0}; + // process only up to no_of_mempool_tx txs of mempool. + // this is useful from the front page were we show by default + // only 25 mempool txs. this way, we just parse 25 txs, rather + // than potentially hundrets just to ditch most of them later. + + if (add_header_and_footer == false) + { + // this is to show limited number of txs in mempool + // for example, in the front page + no_of_mempool_tx = mempool_txs.size() > no_of_mempool_tx + ? no_of_mempool_tx + : mempool_txs.size(); + } + else + { + // if we are adding footers and headers, means we + // disply mempool on its own page, thus show all mempoool txs. + no_of_mempool_tx = mempool_txs.size(); + } + + + double duration_cached {0.0}; + double duration_non_cached {0.0}; + uint64_t cache_hits {0}; + uint64_t cache_misses {0}; uint64_t local_copy_server_timestamp = server_timestamp; // for each transaction in the memory pool - for (size_t i = 0; i < mempool_txs.size(); ++i) + for (size_t i = 0; i < no_of_mempool_tx; ++i) { // get transaction info of the tx in the mempool tx_info _tx_info = mempool_txs.at(i); @@ -591,84 +795,165 @@ public: } // sum xmr in inputs and ouputs in the given tx - pair sum_inputs; - pair sum_outputs; - uint64_t num_nonrct_inputs; - - // get mixin number in each transaction - vector mixin_numbers; - + uint64_t sum_inputs {0}; + uint64_t sum_outputs {0}; + uint64_t no_inputs {0}; + uint64_t no_outputs {0}; + uint64_t num_nonrct_inputs {0}; uint64_t mixin_no {0}; - string is_ringct_str {"N/A"}; - string rct_type_str {"N/A"}; + string hash_str; + string fee_str; + string xmr_inputs_str; + string xmr_outputs_str; + string timestamp_str; + + string txsize; try { + // get the above incormation from json of that tx json j_tx; - j_tx = json::parse(_tx_info.tx_json); + if (enable_mempool_cache && mempool_tx_json_cache.Contains(_tx_info.id_hash)) + { + // maybe its already in cashe, so we can save some time + // by using this, rather then making parsing json + // and calculating it from json - // sum xmr in inputs and ouputs in the given tx - sum_inputs = xmreg::sum_money_in_inputs(j_tx); - sum_outputs = xmreg::sum_money_in_outputs(j_tx); - num_nonrct_inputs = xmreg::count_nonrct_inputs(j_tx); - mixin_numbers = xmreg::get_mixin_no(j_tx); + // start measure time here + auto start = std::chrono::steady_clock::now(); - if (!mixin_numbers.empty()) - mixin_no = mixin_numbers.at(0) - 1; + const mempool_tx_info& cached_tx_info = mempool_tx_json_cache.Get(_tx_info.id_hash); + sum_inputs = cached_tx_info.sum_inputs; + sum_outputs = cached_tx_info.sum_outputs; + no_inputs = cached_tx_info.no_inputs; + no_outputs = cached_tx_info.no_outputs; + num_nonrct_inputs = cached_tx_info.num_nonrct_inputs; + mixin_no = cached_tx_info.mixin_no; + hash_str = cached_tx_info.hash; + fee_str = cached_tx_info.fee; + xmr_inputs_str = cached_tx_info.xmr_inputs_str; + xmr_outputs_str = cached_tx_info.xmr_outputs_str; + timestamp_str = cached_tx_info.timestamp; + txsize = cached_tx_info.txsize; - if (j_tx["version"].get() > 1) - { - is_ringct_str = "yes"; - rct_type_str = string("/") + to_string(j_tx["rct_signatures"]["type"].get()); + auto duration = std::chrono::duration_cast + (std::chrono::steady_clock::now() - start); + + // cout << "block_tx_json_cache from cache" << endl; + + duration_cached += duration.count(); + + ++cache_hits; + + //cout << "getting json from cash for: " << _tx_info.id_hash << endl; } else { - is_ringct_str = "no"; - rct_type_str = ""; - } + // its not in cash. Its new tx in mempool, so + // construct this data and save into cash for later use + + // start measure time here + auto start = std::chrono::steady_clock::now(); + + j_tx = json::parse(_tx_info.tx_json); + + // sum xmr in inputs and ouputs in the given tx + const array& sum_data = summary_of_in_out_rct(j_tx); + + sum_outputs = sum_data[0]; + sum_inputs = sum_data[1]; + no_outputs = sum_data[2]; + no_inputs = sum_data[3]; + mixin_no = sum_data[4]; + num_nonrct_inputs = sum_data[5]; + + hash_str = _tx_info.id_hash; + fee_str = xmreg::xmr_amount_to_str(_tx_info.fee, "{:0.3f}"); + xmr_inputs_str = xmreg::xmr_amount_to_str(sum_inputs , "{:0.3f}"); + xmr_outputs_str = xmreg::xmr_amount_to_str(sum_outputs, "{:0.3f}"); + timestamp_str = xmreg::timestamp_to_str_gm(_tx_info.receive_time); + + txsize = fmt::format("{:0.2f}", + static_cast(_tx_info.blob_size)/1024.0); + + auto duration = std::chrono::duration_cast + (std::chrono::steady_clock::now() - start); + + // cout << "block_tx_json_cache from cache" << endl; + + duration_non_cached += duration.count(); + + ++cache_misses; + + if (enable_mempool_cache) + { + // save in mempool cache + mempool_tx_json_cache.Put( + _tx_info.id_hash, + mempool_tx_info { + sum_inputs, sum_outputs, + no_inputs, no_outputs, + num_nonrct_inputs, mixin_no, + hash_str, fee_str, + xmr_inputs_str, xmr_outputs_str, + timestamp_str, txsize + }); + } + } // else if (mempool_tx_json_cache.Contains(_tx_info.id_hash)) } catch (std::invalid_argument& e) { - cerr << " j_tx = json::parse(_tx_info.tx_json);: " << e.what() << endl; + cerr << " j_tx = json::parse(_tx_info.tx_json): " << e.what() << endl; } // set output page template map txs.push_back(mstch::map { - {"timestamp_no" , _tx_info.receive_time}, - {"timestamp" , xmreg::timestamp_to_str(_tx_info.receive_time)}, - {"age" , age_str}, - {"hash" , fmt::format("{:s}", _tx_info.id_hash)}, - {"fee" , xmreg::xmr_amount_to_str(_tx_info.fee , "{:0.3f}")}, - {"xmr_inputs" , xmreg::xmr_amount_to_str(sum_inputs.first , "{:0.3f}")}, - {"xmr_outputs" , xmreg::xmr_amount_to_str(sum_outputs.first, "{:0.3f}")}, - {"no_inputs" , sum_inputs.second}, - {"no_outputs" , sum_outputs.second}, + {"timestamp_no" , _tx_info.receive_time}, + {"timestamp" , timestamp_str}, + {"age" , age_str}, + {"hash" , hash_str}, + {"fee" , fee_str}, + {"xmr_inputs" , xmr_inputs_str}, + {"xmr_outputs" , xmr_outputs_str}, + {"no_inputs" , no_inputs}, + {"no_outputs" , no_outputs}, {"no_nonrct_inputs", num_nonrct_inputs}, {"is_ringct" , is_ringct_str}, {"rct_type" , rct_type_str}, - {"mixin" , mixin_no}, + {"mixin" , fmt::format("{:d}", mixin_no)}, {"txsize" , fmt::format("{:0.2f}", static_cast(_tx_info.blob_size)/1024.0)} }); + } + + // calculate mempool size using all txs in mempool. + // not only those shown on the front page + uint64_t mempool_size_bytes {0}; + + for (const tx_info& _tx_info: mempool_txs) + { mempool_size_bytes += _tx_info.blob_size; } context.insert({"mempool_size_kB", - fmt::format("{:0.2f}", static_cast(mempool_size_bytes)/1024.0)}); + fmt::format("{:0.2f}", + static_cast(mempool_size_bytes)/1024.0)}); - // sort txs in mempool based on their age - std::sort(txs.begin(), txs.end(), [](mstch::node& m1, mstch::node& m2) - { - uint64_t t1 = boost::get(boost::get(m1)["timestamp_no"]); - uint64_t t2 = boost::get(boost::get(m2)["timestamp_no"]); + context["construction_time_cached"] = fmt::format( + "{:0.4f}", duration_cached/1.0e6); - return t1 > t2; - }); + context["construction_time_non_cached"] = fmt::format( + "{:0.4f}", duration_non_cached/1.0e6); + context["construction_time_total"] = fmt::format( + "{:0.4f}", (duration_non_cached+duration_cached)/1.0e6); + + context["cache_hits"] = cache_hits; + context["cache_misses"] = cache_misses; if (add_header_and_footer) { @@ -683,15 +968,8 @@ public: // this is for partial disply on front page. - context["mempool_fits_on_front_page"] = (txs.size() <= no_of_mempool_tx_of_frontpage); - context["no_of_mempool_tx_of_frontpage"] = no_of_mempool_tx_of_frontpage; - - if (txs.size() > no_of_mempool_tx_of_frontpage) - { - // dont show more than the specific number mempool txs on - // the front page - txs.resize(no_of_mempool_tx_of_frontpage); - } + context["mempool_fits_on_front_page"] = (mempool_txs.size() <= no_of_mempool_tx); + context["no_of_mempool_tx_of_frontpage"] = no_of_mempool_tx; context["partial_mempool_shown"] = true; @@ -744,14 +1022,14 @@ public: bool have_prev_hash = (prev_hash == null_hash ? false : true); // remove "<" and ">" from the hash string - string prev_hash_str = REMOVE_HASH_BRAKETS(fmt::format("{:s}", prev_hash)); - string next_hash_str = REMOVE_HASH_BRAKETS(fmt::format("{:s}", next_hash)); + string prev_hash_str = pod_to_hex(prev_hash); + string next_hash_str = pod_to_hex(next_hash); // remove "<" and ">" from the hash string - string blk_hash_str = REMOVE_HASH_BRAKETS(fmt::format("{:s}", blk_hash)); + string blk_hash_str = pod_to_hex(blk_hash); // get block timestamp in user friendly format - string blk_timestamp = xmreg::timestamp_to_str(blk.timestamp); + string blk_timestamp = xmreg::timestamp_to_str_gm(blk.timestamp); // get age of the block relative to the server time pair age = get_age(server_timestamp, blk.timestamp); @@ -783,12 +1061,12 @@ public: uint64_t sum_fees = 0; // get tx details for the coinbase tx, i.e., miners reward - tx_details txd_coinbase = get_tx_details(blk.miner_tx, true); + tx_details txd_coinbase = get_tx_details(blk.miner_tx, true, + _blk_height, current_blockchain_height); // initalise page tempate map with basic info about blockchain mstch::map context { {"testnet" , testnet}, - {"have_custom_lmdb" , have_custom_lmdb}, {"blk_hash" , blk_hash_str}, {"blk_height" , _blk_height}, {"blk_timestamp" , blk_timestamp}, @@ -830,7 +1108,7 @@ public: const crypto::hash& tx_hash = blk.tx_hashes.at(i); // remove "<" and ">" from the hash string - string tx_hash_str = REMOVE_HASH_BRAKETS(fmt::format("{:s}", tx_hash)); + string tx_hash_str = pod_to_hex(tx_hash); // get transaction @@ -842,7 +1120,9 @@ public: continue; } - tx_details txd = get_tx_details(tx); + tx_details txd = get_tx_details(tx, false, + _blk_height, + current_blockchain_height); // add fee to the rest sum_fees += txd.fee; @@ -941,14 +1221,14 @@ public: uint64_t tx_recieve_timestamp = found_txs.at(0).first.receive_time; - blk_timestamp = xmreg::timestamp_to_str(tx_recieve_timestamp); + blk_timestamp = xmreg::timestamp_to_str_gm(tx_recieve_timestamp); age = get_age(server_timestamp, tx_recieve_timestamp, FULL_AGE_FORMAT); // for mempool tx, we dont show more details, e.g., json tx representation // so no need for the link - show_more_details_link = false; + // show_more_details_link = false; } else { @@ -957,7 +1237,151 @@ public: } } - mstch::map tx_context = construct_tx_context(tx, with_ring_signatures); + mstch::map tx_context; + + if (enable_tx_cache && tx_context_cache.Contains({tx_hash, with_ring_signatures})) + { + // with_ring_signatures == 0 means that cache is not used + // when obtaining detailed information about tx is requested. + + // we are going to measure time for the construction of the + // tx context from cashe. just for fun, to see if cache is any faster. + auto start = std::chrono::steady_clock::now(); + + const tx_info_cache& tx_info_cashed + = tx_context_cache.Get({tx_hash, with_ring_signatures}); + + tx_context = tx_info_cashed.tx_map; + + //cout << "get tx from cash: " << tx_hash_str <(tx_context["tx_blk_height"]) <(tx_context["blk_timestamp_uint"]) <(tx_context["tx_blk_height"]); + uint64_t blk_timestamp_uint = boost::get(tx_context["blk_timestamp_uint"]); + + if (tx_blk_height > 0) + { + // seems to be in blockchain. off course it could have been orphaned + // so double check if its for sure in blockchain + + if (core_storage->have_tx(tx_hash)) + { + // ok, it is still in blockchain + // update its age and number of confirmations + + pair age + = get_age(std::time(nullptr), + blk_timestamp_uint, + FULL_AGE_FORMAT); + + tx_context["delta_time"] = age.first; + + uint64_t bc_height = core_storage->get_current_blockchain_height(); + + tx_context["confirmations"] = bc_height - (tx_blk_height - 1); + + // marke it as from cashe. useful if we want to show + // info about cashed/not cashed in frontend. + tx_context["from_cache"] = true; + + auto duration = std::chrono::duration_cast + (std::chrono::steady_clock::now() - start); + + tx_context["construction_time"] = fmt::format( + "{:0.4f}", static_cast(duration.count())/1.0e6); + + // normally we should update this into in the cache. + // but since we make this check all the time, + // we can skip updating cashed version + + } // if (core_storage->have_tx(tx_hash)) + else + { + // its not in blockchain, but it was there when we cashed it. + // so we update it in cash, as it should be back in mempool + + tx_context = construct_tx_context(tx, with_ring_signatures); + + tx_context_cache.Put( + {tx_hash, with_ring_signatures}, + tx_info_cache { + boost::get(tx_context["tx_blk_height"]), + boost::get(tx_context["blk_timestamp_uint"]), + tx_context} + ); + } + } // if (tx_blk_height > 0) + else + { + // the tx was cashed when in mempool. + // since then, it might have been included in some block. + // so we check it. + + if (core_storage->have_tx(tx_hash)) + { + // checking if in blockchain already + // it was before in mempool, but now maybe already in blockchain + + tx_context = construct_tx_context(tx, with_ring_signatures); + + tx_context_cache.Put( + {tx_hash, with_ring_signatures}, + tx_info_cache { + boost::get(tx_context["tx_blk_height"]), + boost::get(tx_context["blk_timestamp_uint"]), + tx_context}); + + + } // if (core_storage->have_tx(tx_hash)) + else + { + // still seems to be in mempool only. + // so just get its time duration, as its read only + // from cache + + tx_context["from_cache"] = true; + + auto duration = std::chrono::duration_cast + (std::chrono::steady_clock::now() - start); + + tx_context["construction_time"] = fmt::format( + "{:0.4f}", static_cast(duration.count())/1.0e6); + + } + + } // else if (tx_blk_height > 0) + + } // if (tx_context_cache.Contains(tx_hash)) + else + { + + // we are going to measure time for the construction of the + // tx context. just for fun, to see if cache is any faster. + auto start = std::chrono::steady_clock::now(); + + tx_context = construct_tx_context(tx, with_ring_signatures); + + auto duration = std::chrono::duration_cast + (std::chrono::steady_clock::now() - start); + + if (enable_tx_cache) + { + tx_context_cache.Put( + {tx_hash, with_ring_signatures}, + tx_info_cache { + boost::get(tx_context["tx_blk_height"]), + boost::get(tx_context["blk_timestamp_uint"]), + tx_context}); + } + + tx_context["construction_time"] = fmt::format( + "{:0.4f}", static_cast(duration.count())/1.0e6); + + } // else if (tx_context_cache.Contains(tx_hash)) + tx_context["show_more_details_link"] = show_more_details_link; @@ -968,9 +1392,9 @@ public: mstch::map context { {"testnet" , this->testnet}, - {"have_custom_lmdb" , have_custom_lmdb} + {"show_cache_times" , show_cache_times}, + {"txs" , mstch::array{}} }; - context.emplace("txs" , mstch::array{}); boost::get(context["txs"]).push_back(tx_context); @@ -978,8 +1402,10 @@ public: {"tx_details", template_file["tx_details"]}, }; + add_css_style(context); + // render the page return mstch::render(template_file["tx"], context, partials); } @@ -1117,7 +1543,7 @@ public: uint64_t tx_recieve_timestamp = found_txs.at(0).first.receive_time; - blk_timestamp = xmreg::timestamp_to_str(tx_recieve_timestamp); + blk_timestamp = xmreg::timestamp_to_str_gm(tx_recieve_timestamp); age = get_age(server_timestamp, tx_recieve_timestamp, @@ -1163,25 +1589,24 @@ public: // calculate difference between tx and server timestamps age = get_age(server_timestamp, blk.timestamp, FULL_AGE_FORMAT); - blk_timestamp = xmreg::timestamp_to_str(blk.timestamp); + blk_timestamp = xmreg::timestamp_to_str_gm(blk.timestamp); tx_blk_height_str = std::to_string(tx_blk_height); } // payments id. both normal and encrypted (payment_id8) - string pid_str = REMOVE_HASH_BRAKETS(fmt::format("{:s}", txd.payment_id)); - string pid8_str = REMOVE_HASH_BRAKETS(fmt::format("{:s}", txd.payment_id8)); + string pid_str = pod_to_hex(txd.payment_id); + string pid8_str = pod_to_hex(txd.payment_id8); // initalise page tempate map with basic info about blockchain mstch::map context { {"testnet" , testnet}, - {"have_custom_lmdb" , have_custom_lmdb}, {"tx_hash" , tx_hash_str}, {"tx_prefix_hash" , pod_to_hex(txd.prefix_hash)}, {"xmr_address" , xmr_address_str}, {"viewkey" , viewkey_str}, - {"tx_pub_key" , REMOVE_HASH_BRAKETS(fmt::format("{:s}", txd.pk))}, + {"tx_pub_key" , pod_to_hex(txd.pk)}, {"blk_height" , tx_blk_height_str}, {"tx_size" , fmt::format("{:0.4f}", static_cast(txd.size) / 1024.0)}, @@ -1196,7 +1621,7 @@ public: {"tx_prove" , tx_prove} }; - string server_time_str = xmreg::timestamp_to_str(server_timestamp, "%F"); + string server_time_str = xmreg::timestamp_to_str_gm(server_timestamp, "%F"); @@ -1283,9 +1708,7 @@ public: } outputs.push_back(mstch::map { - {"out_pub_key" , REMOVE_HASH_BRAKETS( - fmt::format("{:s}", - outp.first.key))}, + {"out_pub_key" , pod_to_hex(outp.first.key)}, {"amount" , xmreg::xmr_amount_to_str(outp.second)}, {"mine_output" , mine_output}, {"output_idx" , fmt::format("{:02d}", output_idx)} @@ -1542,7 +1965,7 @@ public: {"my_public_key" , pod_to_hex(txout_k.key)}, {"tx_hash" , tx_hash_str}, {"mine_output" , mine_output}, - {"out_idx" , to_string(output_idx_in_tx)}, + {"out_idx" , output_idx_in_tx}, {"formed_output_pk", out_pub_key_str}, {"out_in_match" , output_match}, {"amount" , xmreg::xmr_amount_to_str(amount)} @@ -1678,8 +2101,7 @@ public: // initalise page tempate map with basic info about blockchain mstch::map context { - {"testnet" , testnet}, - {"have_custom_lmdb" , have_custom_lmdb} + {"testnet" , testnet} }; add_css_style(context); @@ -1711,13 +2133,17 @@ public: // initalize page template context map mstch::map context { {"testnet" , testnet}, - {"have_custom_lmdb" , have_custom_lmdb}, {"unsigned_tx_given" , unsigned_tx_given}, {"have_raw_tx" , true}, + {"has_error" , false}, + {"error_msg" , string {}}, {"data_prefix" , data_prefix}, }; context.emplace("txs", mstch::array{}); + string full_page = template_file["checkrawtx"]; + + add_css_style(context); if (unsigned_tx_given) { @@ -1952,8 +2378,8 @@ public: ); tx_cd_data.emplace("timescales", mixins_timescales.first); - tx_cd_data["min_mix_time"] = xmreg::timestamp_to_str(min_mix_timestamp); - tx_cd_data["max_mix_time"] = xmreg::timestamp_to_str(max_mix_timestamp); + tx_cd_data["min_mix_time"] = xmreg::timestamp_to_str_gm(min_mix_timestamp); + tx_cd_data["max_mix_time"] = xmreg::timestamp_to_str_gm(max_mix_timestamp); tx_cd_data["timescales_scale"] = fmt::format("{:0.2f}", mixins_timescales.second / 3600.0 / 24.0); // in days @@ -2017,11 +2443,12 @@ public: tx_hash_from_blob, tx_prefix_hash_from_blob)) { - string msg = fmt::format("failed to validate transaction"); + string error_msg = fmt::format("failed to validate transaction"); - cout << msg << endl; + context["has_error"] = true; + context["error_msg"] = error_msg; - return string(msg); + return mstch::render(full_page, context); } //cout << "tx_from_blob.vout.size(): " << tx_from_blob.vout.size() << endl; @@ -2054,6 +2481,7 @@ public: {"tx_details", template_file["tx_details"]}, }; + add_css_style(context); // render the page @@ -2095,7 +2523,7 @@ public: for (tools::wallet2::pending_tx& ptx: ptxs) { - mstch::map tx_context = construct_tx_context(ptx.tx); + mstch::map tx_context = construct_tx_context(ptx.tx, 1); if (boost::get(tx_context["has_error"])) { @@ -2303,10 +2731,9 @@ public: {"tx_details", template_file["tx_details"]}, }; - add_css_style(context); // render the page - return mstch::render(template_file["checkrawtx"], context, partials); + return mstch::render(full_page, context, partials); } string @@ -2323,7 +2750,6 @@ public: // initalize page template context map mstch::map context { {"testnet" , testnet}, - {"have_custom_lmdb" , have_custom_lmdb}, {"have_raw_tx" , true}, {"has_error" , false}, {"error_msg" , string {}}, @@ -2503,7 +2929,6 @@ public: // initalize page template context map mstch::map context { {"testnet" , testnet}, - {"have_custom_lmdb" , have_custom_lmdb} }; add_css_style(context); @@ -2517,8 +2942,7 @@ public: { // initalize page template context map mstch::map context { - {"testnet" , testnet}, - {"have_custom_lmdb" , have_custom_lmdb} + {"testnet" , testnet} }; add_css_style(context); @@ -2542,7 +2966,6 @@ public: // initalize page template context map mstch::map context{ {"testnet" , testnet}, - {"have_custom_lmdb", have_custom_lmdb}, {"has_error" , false}, {"error_msg" , string{}}, }; @@ -2633,16 +3056,6 @@ public: context.insert({"total_xmr" , string{}}); context.insert({"key_imgs" , mstch::array{}}); - unique_ptr mylmdb; - - if (bf::is_directory(lmdb2_path)) - { - mylmdb = make_unique(lmdb2_path); - } - else - { - cout << "Custom lmdb database seem does not exist at: " << lmdb2_path << endl; - } size_t no_key_images = (decoded_raw_data.size() - header_lenght) / record_lenght; @@ -2665,13 +3078,10 @@ public: = *reinterpret_cast(record_ptr + key_img_size); + // found_tx_hashes was filed using custom lmdb which was droped. + // so this will be empty always for now. vector found_tx_hashes; - if (mylmdb) - { - mylmdb->search(epee::string_tools::pod_to_hex(key_image), - found_tx_hashes, "key_images"); - } mstch::map key_img_info { {"key_no" , fmt::format("{:03d}", n)}, @@ -2868,7 +3278,7 @@ public: } // for (it = tx_key_imgs.begin(); it != tx_key_imgs.end(); ++it) - key_img_info["timestamp"] = xmreg::timestamp_to_str(blk_timestamp); + key_img_info["timestamp"] = xmreg::timestamp_to_str_gm(blk_timestamp); } // if (mcore->get_tx(tx_hash_str, tx)) @@ -2902,7 +3312,6 @@ public: // initalize page template context map mstch::map context{ {"testnet" , testnet}, - {"have_custom_lmdb", have_custom_lmdb}, {"has_error" , false}, {"error_msg" , string{}} }; @@ -2984,16 +3393,6 @@ public: mstch::array& output_keys_ctx = boost::get(context["output_keys"]); - unique_ptr mylmdb; - - if (bf::is_directory(lmdb2_path)) - { - mylmdb = make_unique(lmdb2_path); - } - else - { - cout << "Custom lmdb database seem does not exist at: " << lmdb2_path << endl; - } std::vector outputs; @@ -3095,7 +3494,7 @@ public: {"output_pub_key" , REMOVE_HASH_BRAKETS(fmt::format("{:s}", txout_key.key))}, {"amount" , xmreg::xmr_amount_to_str(xmr_amount)}, {"tx_hash" , REMOVE_HASH_BRAKETS(fmt::format("{:s}", td.m_txid))}, - {"timestamp" , xmreg::timestamp_to_str(blk_timestamp)}, + {"timestamp" , xmreg::timestamp_to_str_gm(blk_timestamp)}, {"is_spent" , is_output_spent}, {"is_ringct" , td.m_rct} }; @@ -3130,18 +3529,20 @@ public: string result_html {default_txt}; - // check first if we look for output with given global index - // such search start with "goi_", e.g., "goi_543" - bool search_for_global_output_idx = (search_text.substr(0, 4) == "goi_"); + uint64_t search_str_length = search_text.length(); + + // first let try searching for tx + result_html = show_tx(search_text); - // check if we look for output with amout index and amount - // such search start with "aoi_", e.g., "aoi_444-23.00" - bool search_for_amount_output_idx = (search_text.substr(0, 4) == "aoi_"); + // nasty check if output is "Cant get" as a sign of + // a not found tx. Later need to think of something better. + if (result_html.find("Cant get") == string::npos) + { + return result_html; + } // first check if searching for block of given height - if (search_text.size() < 12 && - (search_for_global_output_idx == false - ||search_for_amount_output_idx == false)) + if (search_text.size() < 12) { uint64_t blk_height; @@ -3155,7 +3556,7 @@ public: // a not found tx. Later need to think of something better. if (result_html.find("Cant get") == string::npos) { - return result_html; + return result_html; } } catch(boost::bad_lexical_cast &e) @@ -3165,10 +3566,20 @@ public: } } + // if tx search not successful, check if we are looking + // for a block with given hash + result_html = show_block(search_text); + + if (result_html.find("Cant get") == string::npos) + { + return result_html; + } + + result_html = default_txt; // check if monero address is given based on its length // if yes, then we can only show its public components - if (search_text.length() == 95) + if (search_str_length == 95) { // parse string representing given monero address cryptonote::account_public_address address; @@ -3190,7 +3601,7 @@ public: // check if integrated monero address is given based on its length // if yes, then show its public components search tx based on encrypted id - if (search_text.length() == 106) + if (search_str_length == 106) { cryptonote::account_public_address address; @@ -3215,434 +3626,12 @@ public: return show_integrated_address_details(address, encrypted_payment_id, testnet); } - // second let try searching for tx - result_html = show_tx(search_text); - - // nasty check if output is "Cant get" as a sign of - // a not found tx. Later need to think of something better. - if (result_html.find("Cant get") == string::npos) - { - return result_html; - } - - // if tx search not successful, check if we are looking - // for a block with given hash - result_html = show_block(search_text); - - if (result_html.find("Cant get") == string::npos) - { - return result_html; - } - - result_html = default_txt; - - // get mempool transaction so that what we search, - // might be there. Note: show_tx above already searches it - // but only looks for tx hash. Now want to check - // for key_images, public_keys, payments_id, etc. - vector mempool_txs = get_mempool_txs(); - - // key is string indicating where search_text was found. - map> tx_search_results - = search_txs(mempool_txs, search_text); - - // now search my own custom lmdb database - // with key_images, public_keys, payments_id etc. + // all_possible_tx_hashes was field using custom lmdb database + // it was dropped, so all_possible_tx_hashes will be alwasy empty + // for now vector>> all_possible_tx_hashes; - try - { - unique_ptr mylmdb; - - if (!bf::is_directory(lmdb2_path)) - { - cout << "Custom lmdb database seem does not exist at: " << lmdb2_path << endl; - - result_html = show_search_results(search_text, all_possible_tx_hashes); - - return result_html; - } - - cout << "Custom lmdb database seem to exist at: " << lmdb2_path << endl; - cout << "So lets try to search there for what we are after." << endl; - - mylmdb = make_unique(lmdb2_path); - - // check if date given in format: 2015-04-15 12:02:33 - // this is 19 characters - if (search_text.length() == 19) - { - uint64_t estimated_blk_height {0}; - - // first parse the string to date::sys_seconds and then to timestamp - // since epoch - uint64_t blk_timestamp_utc = parse(search_text).time_since_epoch().count(); - - if (blk_timestamp_utc) - { - // seems we have a correct date! - // so try to estimate block height from it. - // - // to find block we can use our lmdb outputs_info table - // its indexes are timestamps. - - vector out_infos; - - if (mylmdb->get_output_info(blk_timestamp_utc, out_infos)) - { - // since many outputs can be in a single block - // just get the first one to obtained its block - - uint64_t found_blk_height = core_storage->get_db() - .get_tx_block_height(out_infos.at(0).tx_hash); - - return show_block(found_blk_height); - } - } - } - else if (search_text.length() == 16) - { - // check if date given in format: 2015-04-15 12:02 - // this is 16 characters, i.e., only minut given - // so search all blocks made within that minute - - // first parse the string to date::sys_seconds and then to timestamp - // since epoch - uint64_t blk_timestamp_utc_start - = parse(search_text, "%Y-%m-%d %H:%M") - .time_since_epoch().count(); - - if (blk_timestamp_utc_start) - { - // seems we have a correct date! - - // add 60 seconds, i.e. 1 min - uint64_t blk_timestamp_utc_end - = blk_timestamp_utc_start + 59; - - all_possible_tx_hashes.push_back( - make_pair("tx_in_the_minute", vector{})); - - vector& txs_found_ref - = all_possible_tx_hashes.back().second; - - get_txs_from_timestamp_range( - blk_timestamp_utc_start, - blk_timestamp_utc_end, - mylmdb, - txs_found_ref); - } - } - else if (search_text.length() == 13) - { - // check if date given in format: 2015-04-15 12 - // this is 13 characters, i.e., only hour given - // so search all blocks made within that hour - - // first parse the string to date::sys_seconds and then to timestamp - // since epoch - uint64_t blk_timestamp_utc_start - = parse(search_text, "%Y-%m-%d %H") - .time_since_epoch().count(); - - if (blk_timestamp_utc_start) - { - // seems we have a correct date! - - // add 60 seconds, i.e. 1 hour - uint64_t blk_timestamp_utc_end - = blk_timestamp_utc_start + 3599; - - all_possible_tx_hashes.push_back( - make_pair("tx_in_the_hour", vector{})); - - vector& txs_found_ref - = all_possible_tx_hashes.back().second; - - get_txs_from_timestamp_range( - blk_timestamp_utc_start, - blk_timestamp_utc_end, - mylmdb, - txs_found_ref); - } - } - else if (search_text.length() == 10) - { - // check if date given in format: 2015-04-15 - // this is 10 characters, i.e., only day given - // so search all blocks made within that day - - // first parse the string to date::sys_seconds and then to timestamp - // since epoch - uint64_t blk_timestamp_utc_start - = parse(search_text, "%Y-%m-%d") - .time_since_epoch().count(); - - if (blk_timestamp_utc_start) - { - // seems we have a correct date! - - // add 60 seconds, i.e. 1 day - uint64_t blk_timestamp_utc_end - = blk_timestamp_utc_start + 86399; - - all_possible_tx_hashes.push_back( - make_pair("tx_in_the_day", vector{})); - - vector& txs_found_ref - = all_possible_tx_hashes.back().second; - - get_txs_from_timestamp_range( - blk_timestamp_utc_start, - blk_timestamp_utc_end, - mylmdb, - txs_found_ref); - } - } - - mylmdb->search(search_text, - tx_search_results["key_images"], - "key_images"); - - //cout << "size: " << tx_search_results["key_images"].size() << endl; - - all_possible_tx_hashes.push_back( - make_pair("key_images", - tx_search_results["key_images"])); - - - // search the custum lmdb for tx_public_keys and append the result - // to those from the mempool search if found - - mylmdb->search(search_text, - tx_search_results["tx_public_keys"], - "tx_public_keys"); - - if (!tx_search_results["tx_public_keys"].empty()) - { - all_possible_tx_hashes.push_back( - make_pair("tx_public_keys", - tx_search_results["tx_public_keys"])); - } - else - { - // if private tx key is added, use it to obtained tx_public_key - // and than search for corresponding tx - - public_key tx_pub_key = null_pkey; - secret_key tx_prv_key; - - if (hex_to_pod(search_text, tx_prv_key)) - { - secret_key recovery_key = tx_prv_key; - - const unsigned char * tx_prv_key_ptr = reinterpret_cast(&tx_prv_key); - unsigned char * tx_pub_key_ptr = reinterpret_cast(&tx_pub_key); - - //memcpy(&tx_pub_key.data, reinterpret_cast(tx_pub_key_ptr), sizeof(tx_pub_key.data)); - - ge_p3 point; - ge_scalarmult_base(&point, tx_prv_key_ptr); - ge_p3_tobytes(tx_pub_key_ptr, &point); - - string tx_pub_key_str = pod_to_hex(tx_pub_key); - - mylmdb->search(tx_pub_key_str, - tx_search_results["tx_public_keys"], - "tx_public_keys"); - - all_possible_tx_hashes.push_back( - make_pair("tx_public_keys", - tx_search_results["tx_public_keys"])); - } - } - - - // search the custum lmdb for payments_id and append the result - // to those from the mempool search if found - - mylmdb->search(search_text, - tx_search_results["payments_id"], - "payments_id"); - - all_possible_tx_hashes.push_back( - make_pair("payments_id", - tx_search_results["payments_id"])); - - // search the custum lmdb for encrypted_payments_id and append the result - // to those from the mempool search if found - - mylmdb->search(search_text, - tx_search_results["encrypted_payments_id"], - "encrypted_payments_id"); - - all_possible_tx_hashes.push_back( - make_pair("encrypted_payments_id", - tx_search_results["encrypted_payments_id"])); - - // search the custum lmdb for output_public_keys and append the result - // to those from the mempool search if found - - mylmdb->search(search_text, - tx_search_results["output_public_keys"], - "output_public_keys"); - - all_possible_tx_hashes.push_back( - make_pair("output_public_keys", - tx_search_results["output_public_keys"])); - - - // seach for output using output global index - - if (search_for_global_output_idx) - { - try - { - uint64_t global_idx = boost::lexical_cast( - search_text.substr(4)); - - - output_data_t output_data; - - try - { - // get info about output of a given global index - output_data = core_storage->get_db() - .get_output_key(global_idx); - } - catch (const OUTPUT_DNE& e) - { - string out_msg = fmt::format( - "Output with index {:d} does not exist!", - global_idx - ); - - cerr << out_msg << endl; - - return out_msg; - } - - //cout << "tx_out.first: " << tx_out.first << endl; - //cout << "tx_out.second: " << tx_out.second << endl; - - string output_pub_key = pod_to_hex(output_data.pubkey); - - //cout << "output_pub_key: " << output_pub_key << endl; - - vector found_outputs; - - mylmdb->search(output_pub_key, - found_outputs, - "output_public_keys"); - - //cout << "found_outputs.size(): " << found_outputs.size() << endl; - - all_possible_tx_hashes.push_back( - make_pair("output_public_keys_based_on_global_idx", - found_outputs)); - - } - catch(boost::bad_lexical_cast &e) - { - cerr << "Cant cast global_idx string: " - << search_text.substr(4) << endl; - } - } // if (search_for_global_output_idx) - - // seach for output using output amount index and amount - - if (search_for_amount_output_idx) - { - try - { - - string str_to_split = search_text.substr(4); - - vector string_parts; - - boost::split(string_parts, str_to_split, - boost::is_any_of("-")); - - if (string_parts.size() != 2) - { - throw; - } - - uint64_t amount_idx = boost::lexical_cast( - string_parts[0]); - - uint64_t amount = static_cast - (boost::lexical_cast( - string_parts[1]) * 1e12); - - - //cout << "amount_idx: " << amount_idx << endl; - //cout << "amount: " << amount << endl; - - output_data_t output_data; - - try - { - // get info about output of a given global index - output_data = core_storage->get_db() - .get_output_key( - amount, amount_idx); - } - catch (const OUTPUT_DNE& e) - { - string out_msg = fmt::format( - "Output with amount {:d} and index {:d} does not exist!", - amount, amount_idx - ); - - cerr << out_msg << endl; - - return out_msg; - } - - string output_pub_key = pod_to_hex(output_data.pubkey); - - //cout << "output_pub_key: " << output_pub_key << endl; - - vector found_outputs; - - mylmdb->search(output_pub_key, - found_outputs, - "output_public_keys"); - - //cout << "found_outputs.size(): " << found_outputs.size() << endl; - - all_possible_tx_hashes.push_back( - make_pair("output_public_keys_based_on_amount_idx", - found_outputs)); - - } - catch(boost::bad_lexical_cast& e) - { - cerr << "Cant parse amout index and amout string: " - << search_text.substr(4) << endl; - } - catch(const OUTPUT_DNE& e) - { - cerr << "Output not found in the blockchain: " - << search_text.substr(4) << endl; - - return(string("Output not found in the blockchain: ") - + search_text.substr(4)); - } - } // if (search_for_amount_output_idx) - } - catch (const lmdb::runtime_error& e) - { - cerr << "Error opening/accessing custom lmdb database: " - << e.what() << endl; - } - catch (std::exception& e) - { - cerr << "Error opening/accessing custom lmdb database: " - << e.what() << endl; - } result_html = show_search_results(search_text, all_possible_tx_hashes); @@ -3663,8 +3652,7 @@ public: {"public_viewkey" , REMOVE_HASH_BRAKETS(pub_viewkey_str)}, {"public_spendkey" , REMOVE_HASH_BRAKETS(pub_spendkey_str)}, {"is_integrated_addr" , false}, - {"testnet" , testnet}, - {"have_custom_lmdb" , have_custom_lmdb} + {"testnet" , testnet} }; add_css_style(context); @@ -3691,8 +3679,7 @@ public: {"public_spendkey" , REMOVE_HASH_BRAKETS(pub_spendkey_str)}, {"encrypted_payment_id" , REMOVE_HASH_BRAKETS(enc_payment_id_str)}, {"is_integrated_addr" , true}, - {"testnet" , testnet}, - {"have_custom_lmdb" , have_custom_lmdb} + {"testnet" , testnet} }; add_css_style(context); @@ -3775,24 +3762,6 @@ public: } - vector - get_mempool_txs() - { - // get mempool data using rpc call - vector> mempool_data = search_mempool(); - - // output only transactions - vector mempool_txs; - - mempool_txs.reserve(mempool_data.size()); - - for (const auto& a_pair: mempool_data) - { - mempool_txs.push_back(a_pair.second); - } - - return mempool_txs; - } string show_search_results(const string& search_text, @@ -3804,8 +3773,7 @@ public: {"testnet" , testnet}, {"search_text" , search_text}, {"no_results" , true}, - {"to_many_results" , false}, - {"have_custom_lmdb", have_custom_lmdb} + {"to_many_results" , false} }; for (const pair>& found_txs: all_possible_tx_hashes) @@ -3881,7 +3849,7 @@ public: // add the timestamp to tx mstch map - txd_map.insert({"timestamp", xmreg::timestamp_to_str(blk_timestamp)}); + txd_map.insert({"timestamp", xmreg::timestamp_to_str_gm(blk_timestamp)}); boost::get((res.first)->second).push_back(txd_map); @@ -3905,7 +3873,7 @@ public: // read partial for showing details of tx(s) found map partials { - {"tx_table_head", template_file["tx_table_head"]}, + {"tx_table_head", template_file["tx_table_header"]}, {"tx_table_row" , template_file["tx_table_row"]} }; @@ -3916,38 +3884,792 @@ public: } -private: - - - void - mark_real_mixins_on_timescales( - const vector& real_output_indices, - mstch::map& tx_context) + /* + * Lets use this json api convention for success and error + * https://labs.omniti.com/labs/jsend + */ + json + json_transaction(string tx_hash_str) { - // mark real mixing in the mixins timescale graph - mstch::array& mixins_timescales - = boost::get(tx_context["timescales"]); + json j_response { + {"status", "fail"}, + {"data" , json {}} + }; - uint64_t idx {0}; + json& j_data = j_response["data"]; - for (mstch::node& timescale_node: mixins_timescales) + // parse tx hash string to hash object + crypto::hash tx_hash; + + if (!xmreg::parse_str_secret_key(tx_hash_str, tx_hash)) { + j_data["title"] = fmt::format("Cant parse tx hash: {:s}", tx_hash_str); + return j_response; + } - string& timescale = boost::get( - boost::get(timescale_node)["timescale"] - ); + // get transaction + transaction tx; - // claculated number of timescale points - // due to resolution, no of points might be lower than no of mixins - size_t no_points = std::count(timescale.begin(), timescale.end(), '*'); + // flag to indicate if tx is in mempool + bool found_in_mempool {false}; - size_t point_to_find = real_output_indices.at(idx); + // for tx in blocks we get block timestamp + // for tx in mempool we get recievive time + uint64_t tx_timestamp {0}; - // adjust point to find based on total number of points - if (point_to_find >= no_points) - point_to_find = no_points - 1; + if (!find_tx(tx_hash, tx, found_in_mempool, tx_timestamp)) + { + j_data["title"] = fmt::format("Cant find tx hash: {:s}", tx_hash_str); + return j_response; + } - boost::iterator_range r + uint64_t block_height {0}; + uint64_t is_coinbase_tx = is_coinbase(tx); + uint64_t no_confirmations {0}; + + if (found_in_mempool == false) + { + + block blk; + + try + { + // get block cointaining this tx + block_height = core_storage->get_db().get_tx_block_height(tx_hash); + + if (!mcore->get_block_by_height(block_height, blk)) + { + j_data["title"] = fmt::format("Cant get block: {:d}", block_height); + return j_response; + } + + tx_timestamp = blk.timestamp; + } + catch (const exception& e) + { + j_response["status"] = "error"; + j_response["message"] = fmt::format("Tx does not exist in blockchain, " + "but was there before: {:s}", tx_hash_str); + return j_response; + } + } + + string blk_timestamp_utc = xmreg::timestamp_to_str_gm(tx_timestamp); + + // get the current blockchain height. Just to check + uint64_t bc_height = core_storage->get_current_blockchain_height(); + + tx_details txd = get_tx_details(tx, is_coinbase_tx, block_height, bc_height); + + json outputs; + + for (const auto& output: txd.output_pub_keys) + { + outputs.push_back(json { + {"public_key", pod_to_hex(output.first.key)}, + {"amount" , output.second} + }); + } + + json inputs; + + for (const auto& input: txd.input_key_imgs) + { + inputs.push_back(json { + {"key_image" , pod_to_hex(input.k_image)}, + {"amount" , input.amount} + }); + } + + if (found_in_mempool == false) + { + no_confirmations = txd.no_confirmations; + } + + // get tx from tx fetched. can be use to double check + // if what we return in the json response agrees with + // what tx_hash was requested + string tx_hash_str_again = pod_to_hex(get_transaction_hash(tx)); + + // get basic tx info + j_data = get_tx_json(tx, txd); + + // append additional info from block, as we don't + // return block data in this function + j_data["timestamp"] = tx_timestamp; + j_data["timestamp_utc"] = blk_timestamp_utc; + j_data["block_height"] = block_height; + j_data["confirmations"] = no_confirmations; + j_data["outputs"] = outputs; + j_data["inputs"] = inputs; + j_data["current_height"] = bc_height; + + j_response["status"] = "success"; + + return j_response; + } + + /* + * Lets use this json api convention for success and error + * https://labs.omniti.com/labs/jsend + */ + json + json_block(string block_no_or_hash) + { + json j_response { + {"status", "fail"}, + {"data" , json {}} + }; + + json& j_data = j_response["data"]; + + uint64_t current_blockchain_height + = core_storage->get_current_blockchain_height(); + + uint64_t block_height {0}; + + crypto::hash blk_hash; + + block blk; + + if (block_no_or_hash.length() <= 8) + { + // we have something that seems to be a block number + try + { + block_height = boost::lexical_cast(block_no_or_hash); + } + catch (const boost::bad_lexical_cast& e) + { + j_data["title"] = fmt::format( + "Cant parse block number: {:s}", block_no_or_hash); + return j_response; + } + + if (block_height > current_blockchain_height) + { + j_data["title"] = fmt::format( + "Requested block is higher than blockchain:" + " {:d}, {:d}", block_height,current_blockchain_height); + return j_response; + } + + if (!mcore->get_block_by_height(block_height, blk)) + { + j_data["title"] = fmt::format("Cant get block: {:d}", block_height); + return j_response; + } + + blk_hash = core_storage->get_block_id_by_height(block_height); + + } + else if (block_no_or_hash.length() == 64) + { + // this seems to be block hash + if (!xmreg::parse_str_secret_key(block_no_or_hash, blk_hash)) + { + j_data["title"] = fmt::format("Cant parse blk hash: {:s}", block_no_or_hash); + return j_response; + } + + if (!core_storage->get_block_by_hash(blk_hash, blk)) + { + j_data["title"] = fmt::format("Cant get block: {:s}", blk_hash); + return j_response; + } + + block_height = core_storage->get_db().get_block_height(blk_hash); + } + else + { + j_data["title"] = fmt::format("Cant find blk using search string: {:s}", block_no_or_hash); + return j_response; + } + + + // get block size in bytes + uint64_t blk_size = core_storage->get_db().get_block_size(block_height); + + // miner reward tx + transaction coinbase_tx = blk.miner_tx; + + // transcation in the block + vector tx_hashes = blk.tx_hashes; + + // sum of all transactions in the block + uint64_t sum_fees = 0; + + // get tx details for the coinbase tx, i.e., miners reward + tx_details txd_coinbase = get_tx_details(blk.miner_tx, true, + block_height, + current_blockchain_height); + + json j_txs; + + j_txs.push_back(get_tx_json(coinbase_tx, txd_coinbase)); + + // for each transaction in the block + for (size_t i = 0; i < blk.tx_hashes.size(); ++i) + { + const crypto::hash &tx_hash = blk.tx_hashes.at(i); + + // get transaction + transaction tx; + + if (!mcore->get_tx(tx_hash, tx)) + { + j_response["status"] = "error"; + j_response["message"] + = fmt::format("Cant get transactions in block: {:d}", block_height); + return j_response; + } + + tx_details txd = get_tx_details(tx, false, + block_height, + current_blockchain_height); + + j_txs.push_back(get_tx_json(tx, txd)); + + // add fee to the rest + sum_fees += txd.fee; + } + + j_data = json { + {"block_height" , block_height}, + {"hash" , pod_to_hex(blk_hash)}, + {"timestamp" , blk.timestamp}, + {"timestamp_utc" , xmreg::timestamp_to_str_gm(blk.timestamp)}, + {"block_height" , block_height}, + {"size" , blk_size}, + {"txs" , j_txs}, + {"current_height", current_blockchain_height} + }; + + j_response["status"] = "success"; + + return j_response; + } + + + + /* + * Lets use this json api convention for success and error + * https://labs.omniti.com/labs/jsend + */ + json + json_transactions(string _page, string _limit) + { + json j_response { + {"status", "fail"}, + {"data", json {}} + }; + + json& j_data = j_response["data"]; + + // parse page and limit into numbers + + uint64_t page {0}; + uint64_t limit {0}; + + try + { + page = boost::lexical_cast(_page); + limit = boost::lexical_cast(_limit); + } + catch (const boost::bad_lexical_cast& e) + { + j_data["title"] = fmt::format( + "Cant parse page and/or limit numbers: {:s}, {:s}", _page, _limit); + return j_response; + } + + // enforce maximum number of blocks per page to 100 + limit = limit > 100 ? 100 : limit; + + //get current server timestamp + server_timestamp = std::time(nullptr); + + uint64_t local_copy_server_timestamp = server_timestamp; + + uint64_t height = core_storage->get_current_blockchain_height(); + + // calculate starting and ending block numbers to show + int64_t start_height = height - limit * (page + 1); + + // check if start height is not below range + start_height = start_height < 0 ? 0 : start_height; + + int64_t end_height = start_height + limit - 1; + + // loop index + int64_t i = end_height; + + j_data["blocks"] = json::array(); + json& j_blocks = j_data["blocks"]; + + // iterate over last no_of_last_blocks of blocks + while (i >= start_height) + { + // get block at the given height i + block blk; + + if (!mcore->get_block_by_height(i, blk)) + { + j_response["status"] = "error"; + j_response["message"] = fmt::format("Cant get block: {:d}", i); + return j_response; + } + + // get block size in bytes + double blk_size = core_storage->get_db().get_block_size(i); + + crypto::hash blk_hash = core_storage->get_block_id_by_height(i); + + // get block age + pair age = get_age(local_copy_server_timestamp, blk.timestamp); + + j_blocks.push_back(json { + {"height" , i}, + {"hash" , pod_to_hex(blk_hash)}, + {"age" , age.first}, + {"size" , blk_size}, + {"timestamp" , blk.timestamp}, + {"timestamp_utc", xmreg::timestamp_to_str_gm(blk.timestamp)}, + {"txs" , json::array()} + }); + + json& j_txs = j_blocks.back()["txs"]; + + list blk_txs {blk.miner_tx}; + list missed_txs; + + if (!core_storage->get_transactions(blk.tx_hashes, blk_txs, missed_txs)) + { + j_response["status"] = "error"; + j_response["message"] = fmt::format("Cant get transactions in block: {:d}", i); + return j_response; + } + + (void) missed_txs; + + for(auto it = blk_txs.begin(); it != blk_txs.end(); ++it) + { + const cryptonote::transaction &tx = *it; + + const tx_details& txd = get_tx_details(tx, false, i, height); + + j_txs.push_back(get_tx_json(tx, txd)); + } + + --i; + } + + j_data["page"] = page; + j_data["limit"] = limit; + j_data["current_height"] = height; + + j_response["status"] = "success"; + + return j_response; + } + + + /* + * Lets use this json api convention for success and error + * https://labs.omniti.com/labs/jsend + */ + json + json_mempool() + { + json j_response { + {"status", "fail"}, + {"data", json {}} + }; + + json& j_data = j_response["data"]; + + //get current server timestamp + server_timestamp = std::time(nullptr); + + uint64_t local_copy_server_timestamp = server_timestamp; + + uint64_t height = core_storage->get_current_blockchain_height(); + + vector> mempool_data = search_mempool(); + + // for each transaction in the memory pool + for (const auto& a_pair: mempool_data) + { + const tx_details& txd = get_tx_details(a_pair.second, false, 1, height); // 1 is dummy here + + // get basic tx info + json j_tx = get_tx_json(a_pair.second, txd); + + // we add some extra data, for mempool txs, such as recieve timestamp + j_tx["timestamp"] = a_pair.first.receive_time; + j_tx["timestamp_utc"] = xmreg::timestamp_to_str_gm(a_pair.first.receive_time); + + j_data.push_back(j_tx); + } + + j_response["status"] = "success"; + + return j_response; + } + + + /* + * Lets use this json api convention for success and error + * https://labs.omniti.com/labs/jsend + */ + json + json_search(const string& search_text) + { + json j_response { + {"status", "fail"}, + {"data", json {}} + }; + + json& j_data = j_response["data"]; + + //get current server timestamp + server_timestamp = std::time(nullptr); + + uint64_t local_copy_server_timestamp = server_timestamp; + + uint64_t height = core_storage->get_current_blockchain_height(); + + uint64_t search_str_length = search_text.length(); + + // first let check if the search_text matches any tx or block hash + if (search_str_length == 64) + { + // first check for tx + json j_tx = json_transaction(search_text); + + if (j_tx["status"] == "success") + { + j_response["data"] = j_tx["data"]; + j_response["data"]["title"] = "transaction"; + j_response["status"] = "success"; + return j_response; + } + + // now check for block + + json j_block = json_block(search_text); + + if (j_block["status"] == "success") + { + j_response["data"] = j_block["data"]; + j_response["data"]["title"] = "block"; + j_response["status"] = "success"; + return j_response; + } + } + + // now lets see if this is a block number + if (search_str_length <= 8) + { + json j_block = json_block(search_text); + + if (j_block["status"] == "success") + { + j_response["data"] = j_block["data"]; + j_response["data"]["title"] = "block"; + j_response["status"] = "success"; + return j_response; + } + } + + j_data["title"] = "Nothing was found that matches search string: " + search_text; + + return j_response; + } + + json + json_outputs(string tx_hash_str, + string address_str, + string viewkey_str, + bool tx_prove = false) + { + boost::trim(tx_hash_str); + boost::trim(address_str); + boost::trim(viewkey_str); + + json j_response { + {"status", "fail"}, + {"data", json {}} + }; + + json& j_data = j_response["data"]; + + + if (tx_hash_str.empty()) + { + j_response["status"] = "error"; + j_response["message"] = "Tx hash not provided"; + return j_response; + } + + if (address_str.empty()) + { + j_response["status"] = "error"; + j_response["message"] = "Monero address not provided"; + return j_response; + } + + if (viewkey_str.empty()) + { + if (!tx_prove) + { + j_response["status"] = "error"; + j_response["message"] = "Viewkey not provided"; + return j_response; + } + else + { + j_response["status"] = "error"; + j_response["message"] = "Tx private key not provided"; + return j_response; + } + } + + + // parse tx hash string to hash object + crypto::hash tx_hash; + + if (!xmreg::parse_str_secret_key(tx_hash_str, tx_hash)) + { + j_response["status"] = "error"; + j_response["message"] = "Cant parse tx hash: " + tx_hash_str; + return j_response; + } + + // parse string representing given monero address + cryptonote::account_public_address address; + + if (!xmreg::parse_str_address(address_str, address, testnet)) + { + j_response["status"] = "error"; + j_response["message"] = "Cant parse monero address: " + address_str; + return j_response; + + } + + // parse string representing given private key + crypto::secret_key prv_view_key; + + if (!xmreg::parse_str_secret_key(viewkey_str, prv_view_key)) + { + j_response["status"] = "error"; + j_response["message"] = "Cant parse view key or tx private key: " + + viewkey_str; + return j_response; + } + + // get transaction + transaction tx; + + // flag to indicate if tx is in mempool + bool found_in_mempool {false}; + + // for tx in blocks we get block timestamp + // for tx in mempool we get recievive time + uint64_t tx_timestamp {0}; + + if (!find_tx(tx_hash, tx, found_in_mempool, tx_timestamp)) + { + j_data["title"] = fmt::format("Cant find tx hash: {:s}", tx_hash_str); + return j_response; + } + + (void) tx_timestamp; + (void) found_in_mempool; + + tx_details txd = get_tx_details(tx); + + // public transaction key is combined with our viewkey + // to create, so called, derived key. + key_derivation derivation; + + public_key pub_key = tx_prove ? address.m_view_public_key : txd.pk; + + //cout << "txd.pk: " << pod_to_hex(txd.pk) << endl; + + if (!generate_key_derivation(pub_key, prv_view_key, derivation)) + { + j_response["status"] = "error"; + j_response["message"] = "Cant calculate key_derivation"; + return j_response; + } + + uint64_t output_idx {0}; + + std::vector money_transfered(tx.vout.size(), 0); + + j_data["outputs"] = json::array(); + json& j_outptus = j_data["outputs"]; + + for (pair& outp: txd.output_pub_keys) + { + + // get the tx output public key + // that normally would be generated for us, + // if someone had sent us some xmr. + public_key tx_pubkey; + + derive_public_key(derivation, + output_idx, + address.m_spend_public_key, + tx_pubkey); + + // check if generated public key matches the current output's key + bool mine_output = (outp.first.key == tx_pubkey); + + // if mine output has RingCT, i.e., tx version is 2 + if (mine_output && tx.version == 2) + { + // cointbase txs have amounts in plain sight. + // so use amount from ringct, only for non-coinbase txs + if (!is_coinbase(tx)) + { + + // initialize with regular amount + uint64_t rct_amount = money_transfered[output_idx]; + + bool r; + + r = decode_ringct(tx.rct_signatures, + pub_key, + prv_view_key, + output_idx, + tx.rct_signatures.ecdhInfo[output_idx].mask, + rct_amount); + + if (!r) + { + cerr << "\nshow_my_outputs: Cant decode ringCT! " << endl; + } + + outp.second = rct_amount; + money_transfered[output_idx] = rct_amount; + + } // if (!is_coinbase(tx)) + + } // if (mine_output && tx.version == 2) + + j_outptus.push_back(json { + {"output_pubkey", pod_to_hex(outp.first.key)}, + {"amount" , outp.second}, + {"match" , mine_output}, + {"output_idx" , output_idx}, + }); + + ++output_idx; + + } // for (pair& outp: txd.output_pub_keys) + + // return parsed values. can be use to double + // check if submited data in the request + // matches to what was used to produce response. + j_data["tx_hash"] = pod_to_hex(txd.hash); + j_data["address"] = pod_to_hex(address); + j_data["viewkey"] = pod_to_hex(prv_view_key); + j_data["tx_prove"] = tx_prove; + + j_response["status"] = "success"; + + return j_response; + } +private: + + json + get_tx_json(const transaction& tx, const tx_details& txd) + { + + json j_tx { + {"tx_hash" , pod_to_hex(txd.hash)}, + {"tx_fee" , txd.fee}, + {"mixin" , txd.mixin_no}, + {"tx_size" , txd.size}, + {"xmr_outputs" , txd.xmr_outputs}, + {"xmr_inputs" , txd.xmr_inputs}, + {"tx_version" , txd.version}, + {"rct_type" , tx.rct_signatures.type}, + {"coinbase" , is_coinbase(tx)}, + {"mixin" , txd.mixin_no}, + {"extra" , txd.get_extra_str()}, + {"payment_id" , (txd.payment_id != null_hash ? pod_to_hex(txd.payment_id) : "")}, + {"payment_id8" , (txd.payment_id8 != null_hash8 ? pod_to_hex(txd.payment_id8) : "")}, + }; + + return j_tx; + } + + bool + find_tx(const crypto::hash& tx_hash, + transaction& tx, + bool& found_in_mempool, + uint64_t& tx_timestamp) + { + + found_in_mempool = false; + + if (!mcore->get_tx(tx_hash, tx)) + { + cerr << "Cant get tx in blockchain: " << tx_hash + << ". \n Check mempool now" << endl; + + vector> found_txs + = search_mempool(tx_hash); + + if (!found_txs.empty()) + { + // there should be only one tx found + tx = found_txs.at(0).second; + found_in_mempool = true; + tx_timestamp = found_txs.at(0).first.receive_time; + } + else + { + // tx is nowhere to be found :-( + return false; + } + } + + return true; + } + + void + mark_real_mixins_on_timescales( + const vector& real_output_indices, + mstch::map& tx_context) + { + // mark real mixing in the mixins timescale graph + mstch::array& mixins_timescales + = boost::get(tx_context["timescales"]); + + uint64_t idx {0}; + + for (mstch::node& timescale_node: mixins_timescales) + { + + string& timescale = boost::get( + boost::get(timescale_node)["timescale"] + ); + + // claculated number of timescale points + // due to resolution, no of points might be lower than no of mixins + size_t no_points = std::count(timescale.begin(), timescale.end(), '*'); + + size_t point_to_find = real_output_indices.at(idx); + + // adjust point to find based on total number of points + if (point_to_find >= no_points) + point_to_find = no_points - 1; + + boost::iterator_range r = boost::find_nth(timescale, "*", point_to_find); *(r.begin()) = 'R'; @@ -3962,7 +4684,7 @@ private: tx_details txd = get_tx_details(tx); - crypto::hash tx_hash = txd.hash; + const crypto::hash& tx_hash = txd.hash; string tx_hash_str = pod_to_hex(tx_hash); @@ -3970,11 +4692,12 @@ private: bool tx_blk_found {false}; + bool detailed_view {enable_mixins_details || static_cast(with_ring_signatures)}; if (core_storage->have_tx(tx_hash)) { // currently get_tx_block_height seems to return a block hight // +1. Before it was not like this. - tx_blk_height = core_storage->get_db().get_tx_block_height(tx_hash) - 1; + tx_blk_height = core_storage->get_db().get_tx_block_height(tx_hash); tx_blk_found = true; } @@ -3998,7 +4721,7 @@ private: // calculate difference between tx and server timestamps age = get_age(server_timestamp, blk.timestamp, FULL_AGE_FORMAT); - blk_timestamp = xmreg::timestamp_to_str(blk.timestamp); + blk_timestamp = xmreg::timestamp_to_str_gm(blk.timestamp); tx_blk_height_str = std::to_string(tx_blk_height); } @@ -4013,15 +4736,15 @@ private: // initalise page tempate map with basic info about blockchain mstch::map context { {"testnet" , testnet}, - {"have_custom_lmdb" , have_custom_lmdb}, {"tx_hash" , tx_hash_str}, - {"tx_prefix_hash" , pod_to_hex(txd.prefix_hash)}, + {"tx_prefix_hash" , string{}}, {"tx_pub_key" , pod_to_hex(txd.pk)}, {"blk_height" , tx_blk_height_str}, + {"tx_blk_height" , tx_blk_height}, {"tx_size" , fmt::format("{:0.4f}", static_cast(txd.size) / 1024.0)}, {"tx_fee" , xmreg::xmr_amount_to_str(txd.fee)}, - {"tx_version" , fmt::format("{:d}", txd.version)}, + {"tx_version" , txd.version}, {"blk_timestamp" , blk_timestamp}, {"blk_timestamp_uint" , blk.timestamp}, {"delta_time" , age.first}, @@ -4034,17 +4757,20 @@ private: {"payment_id" , pid_str}, {"payment_id8" , pid8_str}, {"extra" , txd.get_extra_str()}, - {"with_ring_signatures" , static_cast(with_ring_signatures)}, + {"with_ring_signatures" , static_cast( + with_ring_signatures)}, {"tx_json" , tx_json}, {"is_ringct" , (tx.version > 1)}, {"rct_type" , tx.rct_signatures.type}, {"has_error" , false}, {"error_msg" , string("")}, {"have_raw_tx" , false}, - {"show_more_details_link", true} + {"show_more_details_link", true}, + {"from_cache" , false}, + {"construction_time" , string {}}, }; - string server_time_str = xmreg::timestamp_to_str(server_timestamp, "%F"); + string server_time_str = xmreg::timestamp_to_str_gm(server_timestamp, "%F"); mstch::array inputs = mstch::array{}; @@ -4060,11 +4786,27 @@ private: // umounts. bool have_any_unknown_amount {false}; + uint64_t max_no_of_inputs_to_show {10}; + + // if a tx has more inputs than max_no_of_inputs_to_show, + // we only show 10 first. + bool show_part_of_inputs = (txd.input_key_imgs.size() > max_no_of_inputs_to_show); + + // but if we show all details, i.e., + // the show all inputs, regardless of their number + if (detailed_view) + { + show_part_of_inputs = false; + } vector> mixin_timestamp_groups; // make timescale maps for mixins in input - for (const txin_to_key& in_key: txd.input_key_imgs) + for (const txin_to_key &in_key: txd.input_key_imgs) { + if (show_part_of_inputs && (input_idx > max_no_of_inputs_to_show)) + { + break; + } // get absolute offsets of mixins std::vector absolute_offsets = cryptonote::relative_output_offsets_to_absolute( @@ -4079,7 +4821,7 @@ private: absolute_offsets, outputs); } - catch (const OUTPUT_DNE& e) + catch (const OUTPUT_DNE &e) { string out_msg = fmt::format( "Outputs with amount {:d} do not exist and indexes ", @@ -4104,10 +4846,15 @@ private: {"amount" , xmreg::xmr_amount_to_str(in_key.amount)}, {"input_idx" , fmt::format("{:02d}", input_idx)}, {"mixins" , mstch::array{}}, - {"ring_sigs" , txd.get_ring_sig_for_input(input_idx)}, + {"ring_sigs" , mstch::array{}}, {"already_spent", false} // placeholder for later }); + if (detailed_view) + { + boost::get(inputs.back())["ring_sigs"] + = txd.get_ring_sig_for_input(input_idx); + } inputs_xmr_sum += in_key.amount; if (in_key.amount == 0) @@ -4127,7 +4874,7 @@ private: size_t count = 0; // for each found output public key find its block to get timestamp - for (const uint64_t &i: absolute_offsets) + for (const uint64_t& i: absolute_offsets) { // get basic information about mixn's output cryptonote::output_data_t output_data = outputs.at(count); @@ -4136,12 +4883,12 @@ private: try { - // get pair pair where first is tx hash - // and second is local index of the output i in that tx - tx_out_idx = core_storage->get_db() - .get_output_tx_and_index(in_key.amount, i); + // get pair pair where first is tx hash + // and second is local index of the output i in that tx + tx_out_idx = core_storage->get_db() + .get_output_tx_and_index(in_key.amount, i); } - catch (const OUTPUT_DNE& e) + catch (const OUTPUT_DNE &e) { string out_msg = fmt::format( @@ -4158,53 +4905,66 @@ private: } - // get block of given height, as we want to get its timestamp - cryptonote::block blk; - - if (!mcore->get_block_by_height(output_data.height, blk)) + if (detailed_view) { - cerr << "- cant get block of height: " << output_data.height << endl; + // get block of given height, as we want to get its timestamp + cryptonote::block blk; - context["has_error"] = true; - context["error_msg"] = fmt::format("- cant get block of height: {}", - output_data.height); - } + if (!mcore->get_block_by_height(output_data.height, blk)) + { + cerr << "- cant get block of height: " << output_data.height << endl; - // get age of mixin relative to server time - pair mixin_age = get_age(server_timestamp, - blk.timestamp, - FULL_AGE_FORMAT); - // get mixin transaction - transaction mixin_tx; + context["has_error"] = true; + context["error_msg"] = fmt::format("- cant get block of height: {}", + output_data.height); + } - if (!mcore->get_tx(tx_out_idx.first, mixin_tx)) - { - cerr << "Cant get tx: " << tx_out_idx.first << endl; + // get age of mixin relative to server time + pair mixin_age = get_age(server_timestamp, + blk.timestamp, + FULL_AGE_FORMAT); + // get mixin transaction + transaction mixin_tx; - context["has_error"] = true; - context["error_msg"] = fmt::format("Cant get tx: {:s}", tx_out_idx.first); - } + if (!mcore->get_tx(tx_out_idx.first, mixin_tx)) + { + cerr << "Cant get tx: " << tx_out_idx.first << endl; - // mixin tx details - tx_details mixin_txd = get_tx_details(mixin_tx, true); - - mixins.push_back(mstch::map { - {"mix_blk" , fmt::format("{:08d}", output_data.height)}, - {"mix_pub_key" , pod_to_hex(output_data.pubkey)}, - {"mix_tx_hash" , pod_to_hex(tx_out_idx.first)}, - {"mix_out_indx" , tx_out_idx.second}, - {"mix_timestamp" , xmreg::timestamp_to_str(blk.timestamp)}, - {"mix_age" , mixin_age.first}, - {"mix_mixin_no" , mixin_txd.mixin_no}, - {"mix_inputs_no" , static_cast(mixin_txd.input_key_imgs.size())}, - {"mix_outputs_no" , static_cast(mixin_txd.output_pub_keys.size())}, - {"mix_age_format" , mixin_age.second}, - {"mix_idx" , fmt::format("{:02d}", count)}, - {"mix_is_it_real" , false}, // a placeholder for future - }); + context["has_error"] = true; + context["error_msg"] = fmt::format("Cant get tx: {:s}", tx_out_idx.first); + } + + // mixin tx details + tx_details mixin_txd = get_tx_details(mixin_tx, true); + + mixins.push_back(mstch::map { + {"mix_blk", fmt::format("{:08d}", output_data.height)}, + {"mix_pub_key", pod_to_hex(output_data.pubkey)}, + {"mix_tx_hash", pod_to_hex(tx_out_idx.first)}, + {"mix_out_indx", tx_out_idx.second}, + {"mix_timestamp", xmreg::timestamp_to_str_gm(blk.timestamp)}, + {"mix_age", mixin_age.first}, + {"mix_mixin_no", mixin_txd.mixin_no}, + {"mix_inputs_no", static_cast(mixin_txd.input_key_imgs.size())}, + {"mix_outputs_no", static_cast(mixin_txd.output_pub_keys.size())}, + {"mix_age_format", mixin_age.second}, + {"mix_idx", fmt::format("{:02d}", count)}, + {"mix_is_it_real", false}, // a placeholder for future + }); + + // get mixin timestamp from its orginal block + mixin_timestamps.push_back(blk.timestamp); + } + else // if (detailed_view) + { + mixins.push_back(mstch::map { + {"mix_blk", fmt::format("{:08d}", output_data.height)}, + {"mix_pub_key", pod_to_hex(output_data.pubkey)}, + {"mix_idx", fmt::format("{:02d}", count)}, + {"mix_is_it_real", false}, // a placeholder for future + }); - // get mixin timestamp from its orginal block - mixin_timestamps.push_back(blk.timestamp); + } // else if (enable_mixins_details) ++count; @@ -4215,30 +4975,45 @@ private: input_idx++; } // for (const txin_to_key& in_key: txd.input_key_imgs) - uint64_t min_mix_timestamp; - uint64_t max_mix_timestamp; - pair mixins_timescales - = construct_mstch_mixin_timescales( - mixin_timestamp_groups, - min_mix_timestamp, - max_mix_timestamp - ); - context["have_any_unknown_amount"] = have_any_unknown_amount; - context["inputs_xmr_sum_not_zero"] = (inputs_xmr_sum > 0); - context["inputs_xmr_sum"] = xmreg::xmr_amount_to_str(inputs_xmr_sum); - context["server_time"] = server_time_str; + if (detailed_view) + { + uint64_t min_mix_timestamp {0}; + uint64_t max_mix_timestamp {0}; + + pair mixins_timescales + = construct_mstch_mixin_timescales( + mixin_timestamp_groups, + min_mix_timestamp, + max_mix_timestamp + ); + - context.emplace("inputs", inputs); + context["min_mix_time"] = xmreg::timestamp_to_str_gm(min_mix_timestamp); + context["max_mix_time"] = xmreg::timestamp_to_str_gm(max_mix_timestamp); + + context.emplace("timescales", mixins_timescales.first); + + + context["timescales_scale"] = fmt::format("{:0.2f}", + mixins_timescales.second / 3600.0 / 24.0); // in days + + context["tx_prefix_hash"] = pod_to_hex(get_transaction_prefix_hash(tx)); + + } - context["min_mix_time"] = xmreg::timestamp_to_str(min_mix_timestamp); - context["max_mix_time"] = xmreg::timestamp_to_str(max_mix_timestamp); - context.emplace("timescales", mixins_timescales.first); + context["have_any_unknown_amount"] = have_any_unknown_amount; + context["inputs_xmr_sum_not_zero"] = (inputs_xmr_sum > 0); + context["inputs_xmr_sum"] = xmreg::xmr_amount_to_str(inputs_xmr_sum); + context["server_time"] = server_time_str; + context["enable_mixins_details"] = detailed_view; + context["show_part_of_inputs"] = show_part_of_inputs; + context["max_no_of_inputs_to_show"] = max_no_of_inputs_to_show; - context["timescales_scale"] = fmt::format("{:0.2f}", - mixins_timescales.second / 3600.0 / 24.0); // in days + + context.emplace("inputs", inputs); // get indices of outputs in amounts tables vector out_amount_indices; @@ -4363,15 +5138,16 @@ private: tx_details - get_tx_details(const transaction& tx, bool coinbase = false) + get_tx_details(const transaction& tx, + bool coinbase = false, + uint64_t blk_height = 0, + uint64_t bc_height = 0) { tx_details txd; // get tx hash txd.hash = get_transaction_hash(tx); - // get tx prefix hash - txd.prefix_hash = get_transaction_prefix_hash(tx); // get tx public key from extra // this check if there are two public keys @@ -4380,18 +5156,19 @@ private: txd.pk = xmreg::get_tx_pub_key_from_received_outs(tx); // sum xmr in inputs and ouputs in the given tx - txd.xmr_inputs = sum_money_in_inputs(tx); - txd.xmr_outputs = sum_money_in_outputs(tx); - txd.num_nonrct_inputs = count_nonrct_inputs(tx); + const array& sum_data = summary_of_in_out_rct( + tx, txd.output_pub_keys, txd.input_key_imgs); - // get mixin number - txd.mixin_no = get_mixin_no(tx); + txd.xmr_outputs = sum_data[0]; + txd.xmr_inputs = sum_data[1]; + txd.mixin_no = sum_data[2]; + txd.num_nonrct_inputs = sum_data[3]; txd.fee = 0; transaction tx_copy = tx; - // txd.json_representation = obj_to_json_str(tx_copy); + txd.json_representation = obj_to_json_str(tx_copy); if (!coinbase && tx.vin.size() > 0) @@ -4408,15 +5185,9 @@ private: get_payment_id(tx, txd.payment_id, txd.payment_id8); - //blobdata tx_blob = t_serializable_object_to_blob(tx); // get tx size in bytes txd.size = get_object_blobsize(tx); - //txd.size = tx_blob.size(); - //txd.size = core_storage->get_db().get_block_size(); - - txd.input_key_imgs = get_key_images(tx); - txd.output_pub_keys = get_ouputs(tx); txd.extra = tx.extra; @@ -4431,14 +5202,24 @@ private: txd.no_confirmations = 0; - if (core_storage->have_tx(txd.hash)) + if (blk_height == 0 && core_storage->have_tx(txd.hash)) { + // if blk_height is zero then search for tx block in + // the blockchain. but since often block height is know a priory + // this is not needed txd.blk_height = core_storage->get_db().get_tx_block_height(txd.hash); // get the current blockchain height. Just to check uint64_t bc_height = core_storage->get_current_blockchain_height(); - txd.no_confirmations = bc_height - (txd.blk_height - 1); + txd.no_confirmations = bc_height - (txd.blk_height); + } + else + { + // if we know blk_height, and current blockchan height + // just use it to get no_confirmations. + + txd.no_confirmations = bc_height - (blk_height); } return txd; @@ -4458,36 +5239,13 @@ private: boost::erase_all(raw_tx_data, "-----END CERTIFICATE-----"); } - bool - get_txs_from_timestamp_range( - uint64_t timestamp_start, - uint64_t timestamp_end, - const unique_ptr& mylmdb, - vector& out_txs) - { - - vector txs_found; - - if (mylmdb->get_txs_from_timestamp_range( - timestamp_start, - timestamp_end, - txs_found)) - { - - for (auto tf: txs_found) - { - out_txs.push_back(pod_to_hex(tf)); - } - - return true; - } - - return false; - } vector> search_mempool(crypto::hash tx_hash = null_hash) { + // if tx_hash == null_hash then this method + // will just return the vector containing all + // txs in mempool vector> found_txs; @@ -4500,97 +5258,46 @@ private: return found_txs; } - // if we have tx blob disply more. - // this info can also be obtained from json that is - // normally returned by the RCP call (see below in detailed view) - if (HAVE_TX_BLOB) + // if dont have tx_blob member, construct tx + // from json obtained from the rpc call + + for (size_t i = 0; i < mempool_txs.size(); ++i) { - // get tx_blob if exists - //string tx_blob = get_tx_blob(_tx_info); + // get transaction info of the tx in the mempool + tx_info _tx_info = mempool_txs.at(i); - for (size_t i = 0; i < mempool_txs.size(); ++i) - { - // get transaction info of the tx in the mempool - tx_info _tx_info = mempool_txs.at(i); + crypto::hash mem_tx_hash = null_hash; - // get tx_blob if exists - string tx_blob = get_tx_blob(_tx_info); + if (hex_to_pod(_tx_info.id_hash, mem_tx_hash)) + { + transaction tx; - if (tx_blob.empty()) + if (!xmreg::make_tx_from_json(_tx_info.tx_json, tx)) { - cerr << "tx_blob is empty. Probably its not a custom deamon." << endl; + cerr << "Cant make tx from _tx_info.tx_json" << endl; continue; } - // pare tx_blob into tx class - transaction tx; - - if (!parse_and_validate_tx_from_blob( - tx_blob, tx)) + if (mem_tx_hash != get_transaction_hash(tx)) { - cerr << "Cant get tx from blob" << endl; + cerr << "Hash of reconstructed tx from json does not match " + "what we should get!" + << endl; continue; } - - // if we dont provide tx_hash, just get all txs in - // the mempool - if (tx_hash != null_hash) + if (tx_hash == mem_tx_hash || tx_hash == null_hash) { - // check if tx hash matches, and if yes, save it for return - if (tx_hash == get_transaction_hash(tx)) - { - found_txs.push_back(make_pair(_tx_info, tx)); + found_txs.push_back(make_pair(_tx_info, tx)); + + if (tx_hash != null_hash) break; - } - } - else - { - found_txs.push_back(make_pair(_tx_info, tx)); } - } - } - else - { - // if dont have tx_blob member, construct tx - // from json obtained from the rpc call - - for (size_t i = 0; i < mempool_txs.size(); ++i) - { - // get transaction info of the tx in the mempool - tx_info _tx_info = mempool_txs.at(i); - - crypto::hash mem_tx_hash = null_hash; - - if (hex_to_pod(_tx_info.id_hash, mem_tx_hash)) - { - transaction tx; - - //cout << "\n\n\n_tx_info.id_hash:" << _tx_info.id_hash << endl; - - if (!xmreg::make_tx_from_json(_tx_info.tx_json, tx)) - { - cerr << "Cant make tx from _tx_info.tx_json" << endl; - continue; - } + } // if (hex_to_pod(_tx_info.id_hash, mem_tx_hash)) - if (_tx_info.id_hash != pod_to_hex(get_transaction_hash(tx))) - { - cerr << "Hash of reconstructed tx from json does not match " - "what we should get!" - << endl; - continue; - } + } // for (size_t i = 0; i < mempool_txs.size(); ++i) - if (tx_hash == mem_tx_hash) - { - found_txs.push_back(make_pair(_tx_info, tx)); - break; - } - } - } - } return found_txs; } diff --git a/src/rpccalls.cpp b/src/rpccalls.cpp index a69350f..61bcf93 100644 --- a/src/rpccalls.cpp +++ b/src/rpccalls.cpp @@ -3,3 +3,150 @@ // #include "rpccalls.h" + +namespace xmreg +{ + + +rpccalls::rpccalls(string _deamon_url, + uint64_t _timeout) + : deamon_url {_deamon_url}, + timeout_time {_timeout} +{ + epee::net_utils::parse_url(deamon_url, url); + + port = std::to_string(url.port); + + timeout_time_ms = std::chrono::milliseconds {timeout_time}; + + m_http_client.set_server( + deamon_url, + boost::optional{}); +} + +bool +rpccalls::connect_to_monero_deamon() +{ + //std::lock_guard guard(m_daemon_rpc_mutex); + + if(m_http_client.is_connected()) + { + return true; + } + + return m_http_client.connect(timeout_time_ms); +} + +uint64_t +rpccalls::get_current_height() +{ + COMMAND_RPC_GET_HEIGHT::request req; + COMMAND_RPC_GET_HEIGHT::response res; + + std::lock_guard guard(m_daemon_rpc_mutex); + + if (!connect_to_monero_deamon()) + { + cerr << "get_current_height: not connected to deamon" << endl; + return false; + } + + bool r = epee::net_utils::invoke_http_json( + "/getheight", + req, res, m_http_client, timeout_time_ms); + + if (!r) + { + cerr << "Error connecting to Monero deamon at " + << deamon_url << endl; + return 0; + } + else + { + cout << "rpc call /getheight OK: " << endl; + } + + return res.height; +} + +bool +rpccalls::get_mempool(vector& mempool_txs) +{ + + COMMAND_RPC_GET_TRANSACTION_POOL::request req; + COMMAND_RPC_GET_TRANSACTION_POOL::response res; + + std::lock_guard guard(m_daemon_rpc_mutex); + + if (!connect_to_monero_deamon()) + { + cerr << "get_mempool: not connected to deamon" << endl; + return false; + } + + bool r = epee::net_utils::invoke_http_json( + "/get_transaction_pool", + req, res, m_http_client, timeout_time_ms); + + if (!r) + { + cerr << "Error connecting to Monero deamon at " + << deamon_url << endl; + return false; + } + + + mempool_txs = res.transactions; + + // mempool txs are not sorted base on their arival time, + // so we sort it here. + + std::sort(mempool_txs.begin(), mempool_txs.end(), + [](tx_info& t1, tx_info& t2) + { + return t1.receive_time > t2.receive_time; + }); + + + return true; +} + + +bool +rpccalls::commit_tx(tools::wallet2::pending_tx& ptx, string& error_msg) +{ + COMMAND_RPC_SEND_RAW_TX::request req; + COMMAND_RPC_SEND_RAW_TX::response res; + + req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer( + tx_to_blob(ptx.tx) + ); + + req.do_not_relay = false; + + std::lock_guard guard(m_daemon_rpc_mutex); + + if (!connect_to_monero_deamon()) + { + cerr << "commit_tx: not connected to deamon" << endl; + return false; + } + + bool r = epee::net_utils::invoke_http_json( + "/sendrawtransaction", + req, res, m_http_client, timeout_time_ms); + + if (!r || res.status == "Failed") + { + error_msg = res.reason; + + cerr << "Error sending tx: " << res.reason << endl; + return false; + } + + return true; +} + + + +} diff --git a/src/rpccalls.h b/src/rpccalls.h index 9959ded..95ac59f 100644 --- a/src/rpccalls.h +++ b/src/rpccalls.h @@ -13,157 +13,44 @@ namespace xmreg { - using namespace cryptonote; - using namespace crypto; - using namespace std; +using namespace cryptonote; +using namespace crypto; +using namespace std; - class rpccalls - { - string deamon_url ; - uint64_t timeout_time; - - std::chrono::milliseconds timeout_time_ms; - - epee::net_utils::http::url_content url; - - epee::net_utils::http::http_simple_client m_http_client; - std::mutex m_daemon_rpc_mutex; - - string port; - - public: - - rpccalls(string _deamon_url = "http:://127.0.0.1:18081", - uint64_t _timeout = 200000) - : deamon_url {_deamon_url}, - timeout_time {_timeout} - { - epee::net_utils::parse_url(deamon_url, url); - - port = std::to_string(url.port); - - timeout_time_ms = std::chrono::milliseconds {timeout_time}; - - m_http_client.set_server( - deamon_url, - boost::optional{}); - } - - bool - connect_to_monero_deamon() - { - //std::lock_guard guard(m_daemon_rpc_mutex); - - if(m_http_client.is_connected()) - { - return true; - } - - return m_http_client.connect(timeout_time_ms); - } - - uint64_t - get_current_height() - { - COMMAND_RPC_GET_HEIGHT::request req; - COMMAND_RPC_GET_HEIGHT::response res; - - std::lock_guard guard(m_daemon_rpc_mutex); - - if (!connect_to_monero_deamon()) - { - cerr << "get_current_height: not connected to deamon" << endl; - return false; - } - - bool r = epee::net_utils::invoke_http_json( - "/getheight", - req, res, m_http_client, timeout_time_ms); - - if (!r) - { - cerr << "Error connecting to Monero deamon at " - << deamon_url << endl; - return 0; - } - else - { - cout << "rpc call /getheight OK: " << endl; - } - - return res.height; - } - - bool - get_mempool(vector& mempool_txs) - { - - COMMAND_RPC_GET_TRANSACTION_POOL::request req; - COMMAND_RPC_GET_TRANSACTION_POOL::response res; - - std::lock_guard guard(m_daemon_rpc_mutex); - - if (!connect_to_monero_deamon()) - { - cerr << "get_mempool: not connected to deamon" << endl; - return false; - } - - bool r = epee::net_utils::invoke_http_json( - "/get_transaction_pool", - req, res, m_http_client, timeout_time_ms); - - if (!r) - { - cerr << "Error connecting to Monero deamon at " - << deamon_url << endl; - return false; - } - - - mempool_txs = res.transactions; +class rpccalls +{ + string deamon_url ; + uint64_t timeout_time; - return true; - } + std::chrono::milliseconds timeout_time_ms; + epee::net_utils::http::url_content url; - bool - commit_tx(tools::wallet2::pending_tx& ptx, string& error_msg) - { - COMMAND_RPC_SEND_RAW_TX::request req; - COMMAND_RPC_SEND_RAW_TX::response res; + epee::net_utils::http::http_simple_client m_http_client; + std::mutex m_daemon_rpc_mutex; - req.tx_as_hex = epee::string_tools::buff_to_hex_nodelimer( - tx_to_blob(ptx.tx) - ); + string port; - req.do_not_relay = false; +public: - std::lock_guard guard(m_daemon_rpc_mutex); + rpccalls(string _deamon_url = "http:://127.0.0.1:18081", + uint64_t _timeout = 200000); - if (!connect_to_monero_deamon()) - { - cerr << "commit_tx: not connected to deamon" << endl; - return false; - } + bool + connect_to_monero_deamon(); - bool r = epee::net_utils::invoke_http_json( - "/sendrawtransaction", - req, res, m_http_client, timeout_time_ms); + uint64_t + get_current_height(); - if (!r || res.status == "Failed") - { - error_msg = res.reason; + bool + get_mempool(vector& mempool_txs); - cerr << "Error sending tx: " << res.reason << endl; - return false; - } - return true; - } + bool + commit_tx(tools::wallet2::pending_tx& ptx, string& error_msg); - }; +}; } diff --git a/src/templates/checkrawtx.html b/src/templates/checkrawtx.html index 364d66e..37772b6 100644 --- a/src/templates/checkrawtx.html +++ b/src/templates/checkrawtx.html @@ -7,7 +7,13 @@
-

Data file prefix: {{data_prefix}}

+ {{#has_error}} +

Checking tx failed

+

{{error_msg}}

+ {{/has_error}} + {{^has_error}} +

Data file prefix: {{data_prefix}}

+ {{/has_error}} {{#unsigned_tx_given}}

Details of unsigned raw tx data given

@@ -16,7 +22,7 @@

Basic information

- {{#dest_infos}} + {{#dest_infos}} Send {{dest_amount}} to {{dest_address}}
{{/dest_infos}} diff --git a/src/templates/css/style.css b/src/templates/css/style.css index 8f90f7a..f11dee2 100644 --- a/src/templates/css/style.css +++ b/src/templates/css/style.css @@ -115,7 +115,7 @@ form { input#toggle-1[type=checkbox] { position: absolute; - top: -9999px; + /*top: -9999px;*/ left: -9999px; } diff --git a/src/templates/footer.html b/src/templates/footer.html index 3d286a1..d4ab012 100644 --- a/src/templates/footer.html +++ b/src/templates/footer.html @@ -4,7 +4,6 @@ | explorer version: {{last_git_commit_date}}-{{last_git_commit_hash}} | monero version: {{monero_version_full}}
-
diff --git a/src/templates/header.html b/src/templates/header.html index 3cb7817..140f09d 100644 --- a/src/templates/header.html +++ b/src/templates/header.html @@ -22,23 +22,12 @@
+
+
+ + +
+
- {{#have_custom_lmdb}} -
-
- - -
-
- {{/have_custom_lmdb}} - {{^have_custom_lmdb}} -
-
- - -
-
- {{/have_custom_lmdb}} - + diff --git a/src/templates/index2.html b/src/templates/index2.html index 62b251f..8e70134 100644 --- a/src/templates/index2.html +++ b/src/templates/index2.html @@ -17,12 +17,18 @@ {{#refresh}}
Autorefresh is ON (10 s) {{/refresh}} - {{^refresh}} - Autorefresh is OFF - {{/refresh}} + {{^refresh}} + Autorefresh is OFF + {{/refresh}} {{/enable_autorefresh_option}} + {{#testnet_url}} + | Go to testnet explorer + {{/testnet_url}} + {{#mainnet_url}} + | Go to mainnet explorer + {{/mainnet_url}} {{#testnet}} - | This is testnet blockchian + | This is testnet blockchian {{/testnet}} @@ -52,7 +58,6 @@ fees outputs in(nonrct)/out - rct/type mixin tx size [kB] @@ -65,10 +70,6 @@ {{tx_fee_short}} {{sum_outputs_short}} {{no_inputs}}({{no_nonrct_inputs}})/{{no_outputs}} - - {{#is_ringct}}yes/{{rct_type}}{{/is_ringct}} - {{^is_ringct}}no{{/is_ringct}} - {{mixin}} {{tx_size_short}} @@ -85,3 +86,14 @@ + +{{#show_cache_times}} +
+
+ Tx details construction time: {{construction_time_total}} s +
+ includes {{construction_time_cached}} s from block cache ({{cache_hits}} hits) + and {{construction_time_non_cached}} s from non cache ({{cache_misses}} misses) +
+
+{{/show_cache_times}} \ No newline at end of file diff --git a/src/templates/mempool.html b/src/templates/mempool.html index ecf22d0..1f00920 100644 --- a/src/templates/mempool.html +++ b/src/templates/mempool.html @@ -11,7 +11,6 @@ fee outputs in(nonrct)/out - rct/type mixin tx size [kB] @@ -22,7 +21,6 @@ {{fee}} {{xmr_outputs}} {{no_inputs}}({{no_nonrct_inputs}})/{{no_outputs}} - {{is_ringct}}{{rct_type}} {{mixin}} {{txsize}} @@ -31,7 +29,7 @@ {{^mempool_fits_on_front_page}} {{#partial_mempool_shown}} -
+ {{/partial_mempool_shown}} @@ -39,4 +37,17 @@ {{/mempool_fits_on_front_page}} + + {{#show_cache_times}} +
+
+ Mempoool tx details construction time: {{construction_time_total}} s +
+ includes {{construction_time_cached}} s from mempool cache ({{cache_hits}} hits) + and {{construction_time_non_cached}} s from non cache ({{cache_misses}} misses) +
+
+ {{/show_cache_times}} + +
diff --git a/src/templates/partials/tx_details.html b/src/templates/partials/tx_details.html index 40362a7..91deb2d 100644 --- a/src/templates/partials/tx_details.html +++ b/src/templates/partials/tx_details.html @@ -2,12 +2,10 @@

Tx hash: {{tx_hash}}

-
Tx prefix hash: {{tx_prefix_hash}}
+ {{#enable_mixins_details}} +
Tx prefix hash: {{tx_prefix_hash}}
+ {{/enable_mixins_details}}
Tx public key: {{tx_pub_key}}
- {{#have_raw_tx}} - - {{/have_raw_tx}} - {{#has_payment_id}}
Payment id: {{payment_id}}
@@ -19,11 +17,11 @@ {{#have_prev_hash}} -
Previous tx: {{prev_hash}}
+
Previous tx: {{prev_hash}}
{{/have_prev_hash}} {{#have_next_hash}} -
Next tx: {{next_hash}}
+
Next tx: {{next_hash}}
{{/have_next_hash}} @@ -126,19 +124,21 @@ {{#has_inputs}} -

Inputs' mixins time scale (from {{min_mix_time}} till {{max_mix_time}}; - resolution: {{timescales_scale}} days{{#have_raw_tx}}; R - real mixin {{/have_raw_tx}})

-
-
    - {{#timescales}} -
  • |{{timescale}}|
  • - {{/timescales}} -
-
- + {{#enable_mixins_details}} +

Inputs' mixins time scale (from {{min_mix_time}} till {{max_mix_time}}; + resolution: {{timescales_scale}} days{{#have_raw_tx}}; R - real mixin {{/have_raw_tx}}) +

+
+
    + {{#timescales}} +
  • |{{timescale}}|
  • + {{/timescales}} +
+
+ {{/enable_mixins_details}} {{^inputs_xmr_sum_not_zero}} -

{{inputs_no}} inputs(s) for total of {{inputs_xmr_sum}} xmr

+

{{inputs_no}} input(s) for total of {{inputs_xmr_sum}} xmr

{{/inputs_xmr_sum_not_zero}} {{#inputs_xmr_sum_not_zero}} {{^have_any_unknown_amount}} @@ -149,6 +149,12 @@ {{/have_any_unknown_amount}} {{/inputs_xmr_sum_not_zero}} + {{#show_part_of_inputs}} +
+ Only {{max_no_of_inputs_to_show}} are inputs shown. To see all, + click "more details" +
+ {{/show_part_of_inputs}}
@@ -171,39 +177,65 @@ + + {{#have_raw_tx}} + + {{/have_raw_tx}} + + + {{#mixins}} + + + {{#have_raw_tx}} + {{#mix_is_it_real}} + + {{/mix_is_it_real}} + {{^mix_is_it_real}} + + {{/mix_is_it_real}} + {{/have_raw_tx}} + + + {{/mixins}} +
+ {{#enable_mixins_details}} + + + + {{#have_raw_tx}} + + {{/have_raw_tx}} + + + + + + + + {{#mixins}} + + + {{#have_raw_tx}} + {{#mix_is_it_real}} + + {{/mix_is_it_real}} + {{^mix_is_it_real}} + + {{/mix_is_it_real}} + {{/have_raw_tx}} + + + + + + + {{/mixins}} +
Mixin stealth addressIs it real?blkmixinin/outtimestampage [y:d:h:m:s]
- {{mix_idx}}: {{mix_pub_key}}{{mix_is_it_real}}{{mix_is_it_real}}{{mix_blk}}{{mix_mixin_no}}{{mix_inputs_no}}/{{mix_outputs_no}}{{mix_timestamp}}{{mix_age}}
+ {{/enable_mixins_details}} + {{^enable_mixins_details}} - - - {{#have_raw_tx}} - - {{/have_raw_tx}} - - - - - - - - {{#mixins}} - - - {{#have_raw_tx}} - {{#mix_is_it_real}} - - {{/mix_is_it_real}} - {{^mix_is_it_real}} - - {{/mix_is_it_real}} - {{/have_raw_tx}} - - - - - - - - {{/mixins}} -
Mixin stealth addressIs it real?blkmixinin/outtimestampage [y:d:h:m:s]
- {{mix_idx}}: {{mix_pub_key}}{{mix_is_it_real}}{{mix_is_it_real}}{{mix_blk}}{{mix_mixin_no}}{{mix_inputs_no}}/{{mix_outputs_no}}{{mix_timestamp}}{{mix_age}}
+
Mixin stealth addressIs it real?blk
- {{mix_idx}}: {{mix_pub_key}}{{mix_is_it_real}}{{mix_is_it_real}}{{mix_blk}}
+ {{/enable_mixins_details}} @@ -234,6 +266,7 @@
+ {{/has_inputs}} {{^have_raw_tx}} @@ -243,14 +276,32 @@ {{/show_more_details_link}} {{/with_ring_signatures}} {{#with_ring_signatures}} -

JSON representation of tx

-
- - {{tx_json}} - + + +
+
+ + {{tx_json}} + +
+

Less details
{{/with_ring_signatures}} {{/have_raw_tx}} + +{{#show_cache_times}} +
+ {{#construction_time}} +
+ Tx details construction time: {{construction_time}} s + {{#from_cache}} +
Tx read from the tx cache + {{/from_cache}} +
+ {{/construction_time}} +
+{{/show_cache_times}} +
diff --git a/src/tools.cpp b/src/tools.cpp index f641dd5..626248a 100644 --- a/src/tools.cpp +++ b/src/tools.cpp @@ -148,53 +148,32 @@ remove_trailing_path_separator(const bf::path& in_path) return bf::path(remove_trailing_path_separator(path_str)); } -string -timestamp_to_str(time_t timestamp, const char* format) -{ - auto a_time_point = chrono::system_clock::from_time_t(timestamp); - - try - { - auto utc = date::to_utc_time(chrono::system_clock::from_time_t(timestamp)); - auto sys_time = date::to_sys_time(utc); - - return date::format(format, date::floor(sys_time)); - } - catch (std::runtime_error& e) - { - cerr << "xmreg::timestamp_to_str: " << e.what() << endl; - cerr << "Seems cant convert to UTC timezone using date library. " - "So just use local timezone." < +summary_of_in_out_rct( + const transaction& tx, + vector>& output_pub_keys, + vector& input_key_imgs) +{ + + uint64_t xmr_outputs {0}; + uint64_t xmr_inputs {0}; + uint64_t mixin_no {0}; + uint64_t num_nonrct_inputs {0}; + + + for (const tx_out& txout: tx.vout) + { + if (txout.target.type() != typeid(txout_to_key)) + { + // push empty pair. + output_pub_keys.push_back(pair{}); + continue; + } + + // get tx input key + const txout_to_key& txout_key + = boost::get(txout.target); + + output_pub_keys.push_back(make_pair(txout_key, txout.amount)); + + xmr_outputs += txout.amount; + } + + size_t input_no = tx.vin.size(); + + for (size_t i = 0; i < input_no; ++i) + { + + if(tx.vin[i].type() != typeid(cryptonote::txin_to_key)) + { + continue; + } + + // get tx input key + const cryptonote::txin_to_key& tx_in_to_key + = boost::get(tx.vin[i]); + + xmr_inputs += tx_in_to_key.amount; + + if (tx_in_to_key.amount != 0) + { + ++num_nonrct_inputs; + } + + if (mixin_no == 0) + { + mixin_no = tx_in_to_key.key_offsets.size(); + } + + input_key_imgs.push_back(tx_in_to_key); + + } // for (size_t i = 0; i < input_no; ++i) + + + return {xmr_outputs, xmr_inputs, mixin_no, num_nonrct_inputs}; +}; + + +// this version for mempool txs from json +array +summary_of_in_out_rct(const json& _json) +{ + uint64_t xmr_outputs {0}; + uint64_t xmr_inputs {0}; + uint64_t no_outputs {0}; + uint64_t no_inputs {0}; + uint64_t mixin_no {0}; + uint64_t num_nonrct_inputs {0}; + + for (const json& vout: _json["vout"]) + { + xmr_outputs += vout["amount"].get(); + } + + no_outputs = _json["vout"].size(); + + for (const json& vin: _json["vin"]) + { + uint64_t amount = vin["key"]["amount"].get(); + + xmr_inputs += amount; + + if (amount != 0) + ++num_nonrct_inputs; + } + + no_inputs = _json["vin"].size(); + + mixin_no = _json["vin"].at(0)["key"]["key_offsets"].size() - 1; + + return {xmr_outputs, xmr_inputs, no_outputs, no_inputs, mixin_no, num_nonrct_inputs}; +}; + + uint64_t sum_money_in_inputs(const transaction& tx) { @@ -1035,21 +1117,6 @@ get_tx_pub_key_from_received_outs(const transaction &tx) return null_pkey; } -date::sys_seconds -parse(const std::string& str, string format) -{ - std::istringstream in(str); - date::sys_seconds tp; - in >> date::parse(format, tp); - if (in.fail()) - { - in.clear(); - in.str(str); - in >> date::parse(format, tp); - } - return tp; -} - /** * Check if given output (specified by output_index) * belongs is ours based diff --git a/src/tools.h b/src/tools.h index 5fa3715..66ff1de 100644 --- a/src/tools.h +++ b/src/tools.h @@ -16,7 +16,6 @@ #include "monero_headers.h" #include "../ext/infix_iterator.h" -#include "../ext/date/tz.h" #include "../ext/fmt/ostream.h" #include "../ext/fmt/format.h" #include "../ext/json.hpp" @@ -104,10 +103,7 @@ bf::path remove_trailing_path_separator(const bf::path& in_path); string -timestamp_to_str(time_t timestamp, const char* format = "%F %T"); - -string -timestamp_to_str_local(time_t timestamp, const char* format = "%F %T"); +timestamp_to_str_gm(time_t timestamp, const char* format = "%F %T"); ostream& operator<< (ostream& os, const account_public_address& addr); @@ -136,6 +132,15 @@ sum_money_in_outputs(const string& json_str); pair sum_money_in_outputs(const json& _json); +array +summary_of_in_out_rct( + const transaction& tx, + vector>& output_pub_keys, + vector& input_key_imgs); + +// this version for mempool txs from json +array +summary_of_in_out_rct(const json& _json); uint64_t sum_money_in_inputs(const transaction& tx);