diff --git a/.circleci/config.yml b/.circleci/config.yml index 46d78cb7..283e7421 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ jobs: steps: - checkout - run: - name: Make scripts executable + name: Make scripts executable command: sudo chmod -R +x ./.circleci/*.sh - run: name: Install @@ -13,10 +13,8 @@ jobs: - run: name: Build command: ./.circleci/script_arduino.sh - workflows: version: 2 build: jobs: - build-arduino-default - \ No newline at end of file diff --git a/.circleci/script_arduino.sh b/.circleci/script_arduino.sh index ca5e3769..e70996d4 100644 --- a/.circleci/script_arduino.sh +++ b/.circleci/script_arduino.sh @@ -1,10 +1,10 @@ #!/usr/bin/env bash -bash ./extras/ARDUINO_IDE.sh --auto - mkdir -p ~/Arduino/libraries/cpp-crypto/ mv ~/project/* ~/Arduino/libraries/cpp-crypto -arduino-cli lib install "ArduinoJson@5.13.4" +arduino-cli lib install "ArduinoJson@6.10.0" +arduino-cli lib install "BIP66" +arduino-cli lib install "micro-ecc" arduino-cli compile --output temp.bin -b esp32:esp32:esp32 ~/Arduino/libraries/cpp-crypto/examples/ESP32/ESP32.ino --debug diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md deleted file mode 100644 index b6b28dab..00000000 --- a/.github/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,71 +0,0 @@ -# Contributor Covenant Code of Conduct - -## Our Pledge - -In the interest of fostering an open and welcoming environment, we as -contributors and maintainers pledge to making participation in our project and -our community a harassment-free experience for everyone, regardless of age, body -size, disability, ethnicity, gender identity and expression, level of experience, -education, socio-economic status, nationality, personal appearance, race, -religion, or sexual identity and orientation. - -## Our Standards - -Examples of behavior that contributes to creating a positive environment -include: - -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Our Responsibilities - -Project maintainers are responsible for clarifying the standards of acceptable -behavior and are expected to take appropriate and fair corrective action in -response to any instances of unacceptable behavior. - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -## Scope - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. Examples of -representing a project or community include using an official project e-mail -address, posting via an official social media account, or acting as an appointed -representative at an online or offline event. Representation of a project may be -further defined and clarified by project maintainers. - -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at info@ark.io. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. The project team is -obligated to maintain confidentiality with regard to the reporter of an incident. -Further details of specific enforcement policies may be posted separately. - -Project maintainers who do not follow or enforce the Code of Conduct in good -faith may face temporary or permanent repercussions as determined by other -members of the project's leadership. - -## Attribution - -This Code of Conduct is adapted from the [Contributor Covenant][https://www.contributor-covenant.org], version 1.4, -available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md deleted file mode 100644 index 825605e1..00000000 --- a/.github/CONTRIBUTING.md +++ /dev/null @@ -1 +0,0 @@ -Please see [CONTRIBUTING](https://docs.ark.io/guidebook/contribution-guidelines/contributing.html) for details before opening your pull request. diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md deleted file mode 100644 index bfa4acc9..00000000 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve ---- - -**Describe the bug** -A clear and concise description of what the bug is. - -**To Reproduce** -Steps to reproduce the behavior: -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots to help explain your problem. - -**Server (please complete the following information):** - - OS: [e.g. Ubuntu] - - Version [e.g. 16.04] - -**Additional context** -Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md deleted file mode 100644 index a09db44f..00000000 --- a/.github/ISSUE_TEMPLATE/Feature_request.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for this project ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] - -**Describe the solution you'd like** -A clear and concise description of what you want to happen. - -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 7837d925..00000000 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,34 +0,0 @@ -## Proposed changes - - -## Types of changes - - -- [ ] Bugfix (non-breaking change which fixes an issue) -- [ ] New feature (non-breaking change which adds functionality) -- [ ] Refactoring (improve a current implementation without adding a new feature or fixing a bug) -- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) -- [ ] Build (changes that affect the build system) -- [ ] Docs (documentation only changes) -- [ ] Test (adding missing tests or fixing existing tests) -- [ ] Other... Please describe: - -## Checklist - - -- [ ] I have read the [CONTRIBUTING](https://docs.ark.io/guidebook/contribution-guidelines/contributing.html) documentation -- [ ] Lint and unit tests pass locally with my changes -- [ ] I have added tests that prove my fix is effective or that my feature works -- [ ] I have added necessary documentation (if appropriate) - -## Further comments - diff --git a/CHANGELOG.md b/CHANGELOG.md index 7051d501..93122b21 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,31 +5,77 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). -## Unreleased +## [0.6.0-arduino] - 2019-07-01 + +## [0.6.0] - 2019-07-01 + +### Added + +- added Bridgechain support ([#105]) + +### Changed + +- improved PlatformIO configuration ([#101]) +- improved formatting and maintainability ([#98]) +- improved Slots implementations ([#92]) + +### Fixed + +- fixed Transaction Json numeric serialization ([#103]) + +## [0.5.0] - 2019-02-20 + +### Changed + +- removed bip39 and mnemonic feature ([#86]) + +## [0.4.0] - 2019-05-20 + +### Changed + +- changed to BIP66 lib for DER ser/des. ([#88]) +- updated vendorField to support 255 bytes in Core v2.4 ([#84]) +- updated ArduinoJson package to version v.6.10.0 ([#76]) +- updated tests to use Core fixtures ([#74]) +- improved Windows support ([#83]) + +### Fixed + +- properly handle 0 ARKtoshi Transaction amounts. ([#85]) + +## [0.3.1] - 2019-02-19 + +### Fixed + +- fixed PIO submodule ignore paths in `./platformio.ini` ([#70]) +- added `./src/lib` to build flags for PIO in `./library.json` ([#69]) ## [0.3.0] - 2019-02-16 + ## [0.3.0-arduino] - 2019-02-16 ### Added -- Arduino CircleCI config + +- Arduino CircleCI config ([#61]) ### Changed -- updated `keywords.txt`. -- updated `./library.json` package export settings. -- removed unnecessary files: + +- updated `keywords.txt` ([#64]) +- updated `./library.json` package export settings ([#64]) +- removed unnecessary files ([#64]): - `./appveyor.yml`. - `./CMakeSettings.json`. - `./test/travis.yml`. - `uECC_README.md`. - - submodule from `cmake_example` -- moved external packages to `./src/lib/`: + - submodule from `cmake_example`. +- moved external packages to `./src/lib/` ([#64]): - `./src/bcl`. - `./src/rfc6979`. - `./src/stl`. - `./date`. -- moved `./docs` to `./extras` in arduino builds. -- automated `ARDUINO_IDE.sh` script. -- updated `ARDUINO_IDE.sh` script to reflect `lib/` changes. +- moved `./docs` to `./extras` in arduino builds ([#64]) +- updated `ARDUINO_IDE.sh` script to reflect `lib/` changes ([#64]) +- automated `ARDUINO_IDE.sh` script ([#60]) ## [0.2.0] - 2019-02-07 @@ -58,3 +104,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. [#49]: https://github.com/ArkEcosystem/cpp-crypto/pull/49 [#52]: https://github.com/ArkEcosystem/cpp-crypto/pull/52 [#53]: https://github.com/ArkEcosystem/cpp-crypto/pull/53 +[#60]: https://github.com/ArkEcosystem/cpp-crypto/pull/60 +[#61]: https://github.com/ArkEcosystem/cpp-crypto/pull/61 +[#64]: https://github.com/ArkEcosystem/cpp-crypto/pull/64 +[#69]: https://github.com/ArkEcosystem/cpp-crypto/pull/69 +[#70]: https://github.com/ArkEcosystem/cpp-crypto/pull/70 diff --git a/examples/ESP32/ESP32.ino b/examples/ESP32/ESP32.ino index 14fe4530..8b514ab7 100644 --- a/examples/ESP32/ESP32.ino +++ b/examples/ESP32/ESP32.ino @@ -31,13 +31,40 @@ /****************************************/ void checkCrypto() { + + /** + * Create a BridgeChain transaction, tailored for your custom network. + */ + static const Network MyBridgechainNetwork = { + "16c891512149d6d3ff1b70e65900936140bf853a4ae79b5515157981dcc706df", + 1, 0x53, 0xaa, + "2019-04-12T13:00:00.000Z" + }; + + const Configuration MyBridgechainConfiguration(MyBridgechainNetwork); + + auto myBridgechainTransaction = Builder::buildTransfer( + "D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib", + 100000000ULL, + "this is a custom bridgechain transaction", + "this is a top secret passphrase", + "this is a top secret passphrase too", + MyBridgechainConfiguration); + + Serial.print("\nBridgechain Transaction: "); + Serial.println(myBridgechainTransaction.toJson().c_str()); + + /**/ + + /********************/ + /** * This is how you can check the default 'Network' "Transaction 'Fees' by type. * In this example, it should return a 'uint64_t' integer of '10000000' as the default 'Fee' for a 'Transaction' of 'Type' '0'. */ - Ark::Crypto::Configuration::Fee fee; - unsigned long typeZeroTransactionFee = fee.get(0); - Serial.print("\n Type 0 default Transaction Fee: "); + Configuration config; + unsigned long typeZeroTransactionFee = config.getFee(0); + Serial.print("\nType 0 default Transaction Fee: "); Serial.println(typeZeroTransactionFee); // The response is a 'uint64_t' integer. /**/ @@ -49,10 +76,10 @@ void checkCrypto() { * This is done by passing a 12-word 'Passphrase' and the 'Network' 'Version' "byte". * The 'Version" "byte" is a BASE58 P2PKH byte. Ark Devnet is '0x1E'; Ark Mainnet is '0x17'. * - * Given the passphrase ""bullet parade snow bacon mutual deposit brass floor staff list concert ask", - * and the 'Devnet' 'Version' byte (0x1E); the ARK Address should be "DStZXkgpEjxbG355nQ26vnkp95p24U9tsV" + * Given the passphrase "this is a top secret passphrase", + * and the 'Devnet' 'Version' byte (0x1E); the ARK Address should be "D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib" */ - const auto passphrase = "bullet parade snow bacon mutual deposit brass floor staff list concert ask"; + const auto passphrase = "this is a top secret passphrase"; const uint8_t networkVersion = 0x1E; Address arkAddress = Address::fromPassphrase(passphrase, networkVersion); @@ -67,11 +94,11 @@ void checkCrypto() { * The following methods allows create a 'PrivateKey'. * This is done by passing a 12-word 'Passphrase'. * - * Given the passphrase ""bullet parade snow bacon mutual deposit brass floor staff list concert ask", - * the 'PrivateKey" should be "950981ce17df662dbc1d25305f8597a71309fb8f7232203a0944477e2534b021". + * Given the passphrase "this is a top secret passphrase", + * the 'PrivateKey" should be "d8839c2432bfd0a67ef10a804ba991eabba19f154a3d707917681d45822a5712". * This is a 'SHA256' of your "Passphrase". */ - const auto passphrase2 = "bullet parade snow bacon mutual deposit brass floor staff list concert ask"; + const auto passphrase2 = "this is a top secret passphrase"; PrivateKey privateKeyFromPassphrase = PrivateKey::fromPassphrase(passphrase2); Serial.print("\nPrivateKey from Passphrase: "); Serial.println(privateKeyFromPassphrase.toString().c_str()); // The 'PrivateKey' object is a type. Use 'toString()' to view the output. Arduino requires a 'c_str()' to 'print'. @@ -83,10 +110,10 @@ void checkCrypto() { * The following methods allows create a 'PublicKey'. * This is done by passing a 12-word 'Passphrase'. * - * Given the passphrase ""bullet parade snow bacon mutual deposit brass floor staff list concert ask", - * the 'PublicKey" should be "029fdf41a7d69d8efc7b236c21b9509a23d862ea4ed8b13a56e31eee58dbfd97b4". + * Given the passphrase "this is a top secret passphrase", + * the 'PublicKey" should be "034151a3ec46b5670a682b0a63394f863587d1bc97483b1b6c70eb58e7f0aed192". */ - const auto passphrase3 = "bullet parade snow bacon mutual deposit brass floor staff list concert ask"; + const auto passphrase3 = "this is a top secret passphrase"; PublicKey publicKeyFromPassphrase = PublicKey::fromPassphrase(passphrase3); Serial.print("\nPublicKey from Passphrase: "); Serial.println(publicKeyFromPassphrase.toString().c_str()); // the 'PublicKey' object is a type. Use 'toString()' to view the output. Arduino requires a 'c_str()' to 'print'. @@ -101,11 +128,11 @@ void checkCrypto() { * The 'WIF" "byte" is a BASE58 WIF byte. Ark Devnet is '0xaa'; Ark Mainnet is also '0xaa'. * - * Given the passphrase ""bullet parade snow bacon mutual deposit brass floor staff list concert ask", + * Given the passphrase "this is a top secret passphrase", * and the 'Devnet' 'WIF' byte (0xaa); - * The 'WIF" should be "SEZuJZouNK8GLXNApjciH4QnSKiNr971exVcL2Y6XfrDF5o977zB". + * The 'WIF" should be "SGq4xLgZKCGxs7bjmwnBrWcT4C1ADFEermj846KC97FSv1WFD1dA". */ - const auto passphrase4 = "bullet parade snow bacon mutual deposit brass floor staff list concert ask"; + const auto passphrase4 = "this is a top secret passphrase"; const uint8_t wifByte = 0xaa; WIF wifFromPassphrase = WIF::fromPassphrase(passphrase4, wifByte); Serial.print("\nWIF from Passphrase: "); @@ -118,12 +145,12 @@ void checkCrypto() { * The following methods allows you to 'Sign' a text 'Message'. * This is done by passing the text to be signed, and a 12-word 'Passphrase'. * - * Given the text "Computer science is no more about computers than astronomy is about telescopes.", - * and the passphrase "bullet parade snow bacon mutual deposit brass floor staff list concert ask", - * The 'Signature" should be "3044022021704f2adb2e4a10a3ddc1d7d64552b8061c05f6d12a168c69091c75581d611402200edf37689d2786fc690af9f0f6fa1f629c95695039f648a6d455484302402e93". + * Given the text "Hello World", + * and the passphrase "this is a top secret passphrase", + * The 'Signature" should be "304402200fb4adddd1f1d652b544ea6ab62828a0a65b712ed447e2538db0caebfa68929e02205ecb2e1c63b29879c2ecf1255db506d671c8b3fa6017f67cfd1bf07e6edd1cc8". */ - const auto text = "Computer science is no more about computers than astronomy is about telescopes."; - const auto passphrase5 = "viable weasel wage promote praise inflict jaguar tackle color unusual exclude direct"; + const auto text = "Hello World"; + const auto passphrase5 = "this is a top secret passphrase"; Ark::Crypto::Utils::Message message; message.sign(text, passphrase5); Serial.print("\nSignature from Signed Message: "); diff --git a/examples/ESP8266/ESP8266.ino b/examples/ESP8266/ESP8266.ino index 66d4f891..5cd91181 100644 --- a/examples/ESP8266/ESP8266.ino +++ b/examples/ESP8266/ESP8266.ino @@ -31,13 +31,39 @@ /****************************************/ void checkCrypto() { + /** + * Create a BridgeChain transaction, tailored for your custom network. + */ + static const Network MyBridgechainNetwork = { + "16c891512149d6d3ff1b70e65900936140bf853a4ae79b5515157981dcc706df", + 1, 0x53, 0xaa, + "2019-04-12T13:00:00.000Z" + }; + + const Configuration MyBridgechainConfiguration(MyBridgechainNetwork); + + auto myBridgechainTransaction = Builder::buildTransfer( + "D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib", + 100000000ULL, + "this is a custom bridgechain transaction", + "this is a top secret passphrase", + "this is a top secret passphrase too", + MyBridgechainConfiguration); + + Serial.print("\nBridgechain Transaction: "); + Serial.println(myBridgechainTransaction.toJson().c_str()); + + /**/ + + /********************/ + /** * This is how you can check the default 'Network' "Transaction 'Fees' by type. * In this example, it should return a 'uint64_t' integer of '10000000' as the default 'Fee' for a 'Transaction' of 'Type' '0'. */ - Ark::Crypto::Configuration::Fee fee; - unsigned long typeZeroTransactionFee = fee.get(0); - Serial.print("\n Type 0 default Transaction Fee: "); + Configuration config; + unsigned long typeZeroTransactionFee = config.getFee(0); + Serial.print("\nType 0 default Transaction Fee: "); Serial.println(typeZeroTransactionFee); // The response is a 'uint64_t' integer. /**/ @@ -49,10 +75,10 @@ void checkCrypto() { * This is done by passing a 12-word 'Passphrase' and the 'Network' 'Version' "byte". * The 'Version" "byte" is a BASE58 P2PKH byte. Ark Devnet is '0x1E'; Ark Mainnet is '0x17'. * - * Given the passphrase ""bullet parade snow bacon mutual deposit brass floor staff list concert ask", - * and the 'Devnet' 'Version' byte (0x1E); the ARK Address should be "DStZXkgpEjxbG355nQ26vnkp95p24U9tsV" + * Given the passphrase "this is a top secret passphrase", + * and the 'Devnet' 'Version' byte (0x1E); the ARK Address should be "D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib" */ - const auto passphrase = "bullet parade snow bacon mutual deposit brass floor staff list concert ask"; + const auto passphrase = "this is a top secret passphrase"; const uint8_t networkVersion = 0x1E; Address arkAddress = Address::fromPassphrase(passphrase, networkVersion); @@ -67,11 +93,11 @@ void checkCrypto() { * The following methods allows create a 'PrivateKey'. * This is done by passing a 12-word 'Passphrase'. * - * Given the passphrase ""bullet parade snow bacon mutual deposit brass floor staff list concert ask", - * the 'PrivateKey" should be "950981ce17df662dbc1d25305f8597a71309fb8f7232203a0944477e2534b021". + * Given the passphrase "this is a top secret passphrase", + * the 'PrivateKey" should be "d8839c2432bfd0a67ef10a804ba991eabba19f154a3d707917681d45822a5712". * This is a 'SHA256' of your "Passphrase". */ - const auto passphrase2 = "bullet parade snow bacon mutual deposit brass floor staff list concert ask"; + const auto passphrase2 = "this is a top secret passphrase"; PrivateKey privateKeyFromPassphrase = PrivateKey::fromPassphrase(passphrase2); Serial.print("\nPrivateKey from Passphrase: "); Serial.println(privateKeyFromPassphrase.toString().c_str()); // The 'PrivateKey' object is a type. Use 'toString()' to view the output. Arduino requires a 'c_str()' to 'print'. @@ -83,10 +109,10 @@ void checkCrypto() { * The following methods allows create a 'PublicKey'. * This is done by passing a 12-word 'Passphrase'. * - * Given the passphrase ""bullet parade snow bacon mutual deposit brass floor staff list concert ask", - * the 'PublicKey" should be "029fdf41a7d69d8efc7b236c21b9509a23d862ea4ed8b13a56e31eee58dbfd97b4". + * Given the passphrase "this is a top secret passphrase", + * the 'PublicKey" should be "034151a3ec46b5670a682b0a63394f863587d1bc97483b1b6c70eb58e7f0aed192". */ - const auto passphrase3 = "bullet parade snow bacon mutual deposit brass floor staff list concert ask"; + const auto passphrase3 = "this is a top secret passphrase"; PublicKey publicKeyFromPassphrase = PublicKey::fromPassphrase(passphrase3); Serial.print("\nPublicKey from Passphrase: "); Serial.println(publicKeyFromPassphrase.toString().c_str()); // the 'PublicKey' object is a type. Use 'toString()' to view the output. Arduino requires a 'c_str()' to 'print'. @@ -101,11 +127,11 @@ void checkCrypto() { * The 'WIF" "byte" is a BASE58 WIF byte. Ark Devnet is '0xaa'; Ark Mainnet is also '0xaa'. * - * Given the passphrase ""bullet parade snow bacon mutual deposit brass floor staff list concert ask", + * Given the passphrase "this is a top secret passphrase", * and the 'Devnet' 'WIF' byte (0xaa); - * The 'WIF" should be "SEZuJZouNK8GLXNApjciH4QnSKiNr971exVcL2Y6XfrDF5o977zB". + * The 'WIF" should be "SGq4xLgZKCGxs7bjmwnBrWcT4C1ADFEermj846KC97FSv1WFD1dA". */ - const auto passphrase4 = "bullet parade snow bacon mutual deposit brass floor staff list concert ask"; + const auto passphrase4 = "this is a top secret passphrase"; const uint8_t wifByte = 0xaa; WIF wifFromPassphrase = WIF::fromPassphrase(passphrase4, wifByte); Serial.print("\nWIF from Passphrase: "); diff --git a/extras/ARDUINO_IDE.sh b/extras/ARDUINO_IDE.sh new file mode 100644 index 00000000..1fdc3a8a --- /dev/null +++ b/extras/ARDUINO_IDE.sh @@ -0,0 +1,226 @@ +#!/usr/bin/env bash +# This file is part of Ark Cpp Crypto. +# +# (c) Ark Ecosystem +# +# For the full copyright and license information, please view the LICENSE +# file that was distributed with this source code. + +# ######### +# This script extends support to the Arduino IDE. +# +# The Arduino IDE doesn't support extending its search path outside of the 'src' folder. +# The Ark Cpp-Crypto SDK exposes its public interface via the 'include' folder. +# +# This script moves the headers from 'include' into their relative directories in the 'src' folder; +# it then delete the 'include' folder. +# +# Additionally, once this script has been ran, it can be executed again to undo these changes. +# (i.e. recreates the directory tree and moves headers back to 'include'.) +# ######### + +# Flags +# You can skip the interface by passing '--auto'; eg 'bash ARDUINO_IDE.sh -auto' +AUTO='0' +if [ "$1" == "--auto" ]; then + AUTO='1' +fi + +# Directories +EXTRAS_DIR=$(dirname $0) +PROJECT_ROOT=${EXTRAS_DIR}/../ +INCLUDE_DIR=${EXTRAS_DIR}/../src/include +INCLUDE_CRYPTO_DIR=${INCLUDE_DIR}/cpp-crypto +SRC_DIR=${EXTRAS_DIR}/../src + +EXTRAS_BACKUP_DIR=${EXTRAS_DIR}/BACKUP + +SRC_LIB_DIR=${SRC_DIR}/lib +EXTRAS_LIB_DIR=${EXTRAS_BACKUP_DIR}/lib + +SRC_COMMON_DIR=${SRC_DIR}/common +INCLUDE_COMMON_DIR=${INCLUDE_CRYPTO_DIR}/common + +SRC_DEFAULTS_DIR=${SRC_DIR}/defaults +INCLUDE_DEFAULTS_DIR=${INCLUDE_CRYPTO_DIR}/defaults + +SRC_HELPERS_DIR=${SRC_DIR}/helpers +INCLUDE_HELPERS_DIR=${INCLUDE_CRYPTO_DIR}/helpers + +SRC_ENCODING_DIR=${SRC_HELPERS_DIR}/encoding +INCLUDE_ENCODING_DIR=${INCLUDE_HELPERS_DIR}/encoding + +SRC_IDENTITIES_DIR=${SRC_DIR}/identities +INCLUDE_IDENTITIES_DIR=${INCLUDE_CRYPTO_DIR}/identities + +INCLUDE_NETWORKS_DIR=${INCLUDE_CRYPTO_DIR}/networks +SRC_NETWORKS_DIR=${SRC_DIR}/networks + +INCLUDE_TRANSACTIONS_DIR=${INCLUDE_CRYPTO_DIR}/transactions +SRC_TRANSACTIONS_DIR=${SRC_DIR}/transactions + +if [[ $AUTO == '0' ]]; then + +# Interface +echo -e "\n\nπŸ‘‹ Welcome Aboard 🚒\n\n" +sleep 1 + +if [[ -d ${INCLUDE_DIR} ]]; then + echo -e "πŸ€– This script extends compatibility to the Arduino IDE πŸ€–\n" + sleep 1 + echo -e "πŸ’ͺ All header files will be moved to their 'src' folders πŸ’ͺ\n" + sleep 1 +else + echo -e "πŸ€– Looks like this library was already converted to support the Arduino IDE πŸ€–\n" + sleep 1 + echo -e "πŸ’ͺ All header files will be moved back to the 'include' folder πŸ’ͺ\n" + sleep 1 +fi + +echo -e "\nπŸ›‘ These changes are permanent, any unsaved changes will be lost πŸ›‘\n" +sleep 2 + +# Prompts for continuation +read -p "⚠️ Are you sure you want to continue? (Y/n):" -n 1 -r +echo +if [[ ${REPLY} =~ ^[Nn]$ ]]; then + echo -e "\n\nπŸ‘Œ Exiting script...\nNo Changes were made πŸ‘\n\n"; + exit 0; +else + echo -e "\n\nπŸ‘Œ Let's go!\n"; +fi + +fi # /if [[ ${AUTO} ]]; then + +if [[ -d ${INCLUDE_DIR} ]]; then + # This will run if headers are in the 'include' directory tree. + echo -e "****************************************\n" + echo -e "Moving 'arkCrypto.h' to 'src' directory.\n" + mv ${INCLUDE_CRYPTO_DIR}/arkCrypto.h ${SRC_DIR} + + echo -e "Moving 'common' headers.\n" + mv ${INCLUDE_COMMON_DIR}/configuration.hpp ${SRC_COMMON_DIR} + mv ${INCLUDE_COMMON_DIR}/fee_policy.hpp ${SRC_COMMON_DIR} + mv ${INCLUDE_COMMON_DIR}/network.hpp ${SRC_COMMON_DIR} + + echo -e "Moving 'defaults' headers.\n" + mv ${INCLUDE_DEFAULTS_DIR}/fee_policies.hpp ${SRC_DEFAULTS_DIR} + mv ${INCLUDE_DEFAULTS_DIR}/static_fees.hpp ${SRC_DEFAULTS_DIR} + mv ${INCLUDE_DEFAULTS_DIR}/transaction_types.hpp ${SRC_DEFAULTS_DIR} + + echo -e "Moving 'helpers' headers.\n" + mkdir ${SRC_ENCODING_DIR} + mv ${INCLUDE_HELPERS_DIR}/encoding/hex.h ${SRC_ENCODING_DIR} + + echo -e "Moving 'identites' headers.\n" + mv ${INCLUDE_IDENTITIES_DIR}/address.h ${SRC_IDENTITIES_DIR} + mv ${INCLUDE_IDENTITIES_DIR}/privatekey.h ${SRC_IDENTITIES_DIR} + mv ${INCLUDE_IDENTITIES_DIR}/publickey.h ${SRC_IDENTITIES_DIR} + mv ${INCLUDE_IDENTITIES_DIR}/wif.h ${SRC_IDENTITIES_DIR} + + echo -e "Moving 'networks' headers.\n" + mv ${INCLUDE_NETWORKS_DIR}/networks.hpp ${SRC_NETWORKS_DIR} + mv ${INCLUDE_NETWORKS_DIR}/devnet.hpp ${SRC_NETWORKS_DIR} + mv ${INCLUDE_NETWORKS_DIR}/mainnet.hpp ${SRC_NETWORKS_DIR} + mv ${INCLUDE_NETWORKS_DIR}/testnet.hpp ${SRC_NETWORKS_DIR} + + echo -e "Moving 'transactions' headers.\n" + mv ${INCLUDE_TRANSACTIONS_DIR}/builder.h ${SRC_TRANSACTIONS_DIR} + mv ${INCLUDE_TRANSACTIONS_DIR}/deserializer.h ${SRC_TRANSACTIONS_DIR} + mv ${INCLUDE_TRANSACTIONS_DIR}/serializer.h ${SRC_TRANSACTIONS_DIR} + mv ${INCLUDE_TRANSACTIONS_DIR}/transaction.h ${SRC_TRANSACTIONS_DIR} + + echo -e "Backing up, moving, and removing dependencies from the 'src/lib' directory.\n" + mkdir ${EXTRAS_BACKUP_DIR} + mv ${SRC_LIB_DIR}/ArduinoJson ${EXTRAS_BACKUP_DIR} + mv ${SRC_LIB_DIR}/BIP66 ${EXTRAS_BACKUP_DIR} + mv ${SRC_LIB_DIR}/uECC ${EXTRAS_BACKUP_DIR} + mv ${SRC_LIB_DIR}/bcl ${SRC_DIR} + mv ${SRC_LIB_DIR}/date ${SRC_DIR} + mv ${SRC_LIB_DIR}/rfc6979 ${SRC_DIR} + + echo -e "Moving Docs to the './extras' directory.\n" + mv ${PROJECT_ROOT}/docs ${EXTRAS_DIR} + + echo -e "Removing old directories πŸ—‘\n" + rm -rf ${INCLUDE_DIR} + rm -rf ${SRC_LIB_DIR} + + echo -e "****************************************\n" + + echo -e "\nAll Done!\nπŸ‘πŸ‘πŸ‘πŸ‘πŸ‘\n" + echo -e "\nYou can now use Cpp-Crypto with the Arduino IDE πŸ‘\n\n" + exit 0 + +else + # This will run if headers are already in the 'src' directory tree. + echo -e "****************************************\n" + + echo -e "Creating the 'include' directory tree πŸ—‚\n" + mkdir ${INCLUDE_DIR} + mkdir ${INCLUDE_CRYPTO_DIR} + mkdir ${INCLUDE_COMMON_DIR} + mkdir ${INCLUDE_DEFAULTS_DIR} + mkdir ${INCLUDE_HELPERS_DIR} + mkdir ${INCLUDE_ENCODING_DIR} + mkdir ${INCLUDE_IDENTITIES_DIR} + mkdir ${INCLUDE_NETWORKS_DIR} + mkdir ${INCLUDE_TRANSACTIONS_DIR} + + echo -e "Moving 'arkCrypto.h' back to the 'include/cpp-crypto/' directory.\n" + mv ${SRC_DIR}/arkCrypto.h ${INCLUDE_CRYPTO_DIR} + + echo -e "Moving 'common' headers.\n" + mv ${SRC_COMMON_DIR}/configuration.hpp ${INCLUDE_COMMON_DIR} + mv ${SRC_COMMON_DIR}/fee_policy.hpp ${INCLUDE_COMMON_DIR} + mv ${SRC_COMMON_DIR}/network.hpp ${INCLUDE_COMMON_DIR} + + echo -e "Moving 'defaults' headers.\n" + mv ${SRC_DEFAULTS_DIR}/fee_policies.hpp ${INCLUDE_DEFAULTS_DIR} + mv ${SRC_DEFAULTS_DIR}/static_fees.hpp ${INCLUDE_DEFAULTS_DIR} + mv ${SRC_DEFAULTS_DIR}/transaction_types.hpp ${INCLUDE_DEFAULTS_DIR} + + echo -e "Moving 'helpers/encoding' headers.\n" + mv ${SRC_ENCODING_DIR}/hex.h ${INCLUDE_ENCODING_DIR} + rm ${SRC_ENCODING_DIR} + + echo -e "Moving 'identities' headers.\n" + mv ${SRC_IDENTITIES_DIR}/address.h ${INCLUDE_IDENTITIES_DIR} + mv ${SRC_IDENTITIES_DIR}/privatekey.h ${INCLUDE_IDENTITIES_DIR} + mv ${SRC_IDENTITIES_DIR}/publickey.h ${INCLUDE_IDENTITIES_DIR} + mv ${SRC_IDENTITIES_DIR}/wif.h ${INCLUDE_IDENTITIES_DIR} + + echo -e "Moving 'networks' headers.\n" + mv ${SRC_NETWORKS_DIR}/networks.hpp ${INCLUDE_NETWORKS_DIR} + mv ${SRC_NETWORKS_DIR}/devnet.hpp ${INCLUDE_NETWORKS_DIR} + mv ${SRC_NETWORKS_DIR}/mainnet.hpp ${INCLUDE_NETWORKS_DIR} + mv ${SRC_NETWORKS_DIR}/testnet.hpp ${INCLUDE_NETWORKS_DIR} + + echo -e "Moving 'transactions' headers.\n" + mv ${SRC_TRANSACTIONS_DIR}/builder.h ${INCLUDE_TRANSACTIONS_DIR} + mv ${SRC_TRANSACTIONS_DIR}/deserializer.h ${INCLUDE_TRANSACTIONS_DIR} + mv ${SRC_TRANSACTIONS_DIR}/serializer.h ${INCLUDE_TRANSACTIONS_DIR} + mv ${SRC_TRANSACTIONS_DIR}/transaction.h ${INCLUDE_TRANSACTIONS_DIR} + + echo -e "Restoring the 'lib' directory.\n" + mkdir ${SRC_LIB_DIR} + mv ${EXTRAS_BACKUP_DIR}/ArduinoJson ${SRC_LIB_DIR} + mv ${EXTRAS_BACKUP_DIR}/BIP66 ${SRC_LIB_DIR} + mv ${EXTRAS_BACKUP_DIR}/uECC ${SRC_LIB_DIR} + mv ${SRC_DIR}/bcl ${SRC_LIB_DIR} + mv ${SRC_DIR}/date ${SRC_LIB_DIR} + mv ${SRC_DIR}/rfc6979 ${SRC_LIB_DIR} + + echo -e "Moving Docs back to the project root directory.\n" + mv ${EXTRAS_DIR}/docs ${PROJECT_ROOT} + + echo -e "Removing old directories πŸ—‘\n" + rm -rf ${EXTRAS_BACKUP_DIR} + + echo -e "****************************************\n" + + echo -e "\nAll Done!\nπŸ‘πŸ‘πŸ‘πŸ‘πŸ‘\n" + echo -e "\nArduino IDE compatibility has been reverted πŸ‘\n\n" + exit 0 + +fi diff --git a/extras/docs/INSTALL_ARDUINO.MD b/extras/docs/INSTALL_ARDUINO.md similarity index 100% rename from extras/docs/INSTALL_ARDUINO.MD rename to extras/docs/INSTALL_ARDUINO.md diff --git a/extras/docs/INSTALL_OS.md b/extras/docs/INSTALL_OS.md new file mode 100644 index 00000000..12105191 --- /dev/null +++ b/extras/docs/INSTALL_OS.md @@ -0,0 +1,33 @@ + + +# OS Builds + +### dependencies + +**CMake:** +> Use an installer package from the following link: +> ```https://www.cmake.org/download/``` + +or +**Homebrew:** +> `brew install cmake` + +# + +> note: all other dependencies will be automatically installed via CMake and Hunter Package Manager. + +# + +### make and build +**`cd`** into **`.../cpp-crypto/`** +then run the following commands: +> init & update micro-ecc submodule +>`git submodule init && git submodule update` + +> make and build +> `cmake . && cmake --build .` + +# + +### run tests +> `./bin/Ark-Cpp-Crypto-tests` diff --git a/extras/docs/INSTALL_PLATFORMIO.md b/extras/docs/INSTALL_PLATFORMIO.md new file mode 100644 index 00000000..f1eab693 --- /dev/null +++ b/extras/docs/INSTALL_PLATFORMIO.md @@ -0,0 +1,39 @@ + + +# PlatformIO + +### dependencies + +**Python:** +Use an installer package from the following link: +> ```https://www.python.org/downloads/``` + +# + +**PlatformIO:** +install PlatformIO if not already installed +> ```pip install -U platformio``` +or +> ```python -c "$(curl -fsSL > https://raw.githubusercontent.com/platformio/platformio/develop/scripts/get-platformio.py)"``` + + +also install platformio dependencies: +> install AUnit (2778), micro-ecc (1665) ArduinoJson@6.10.0 libraries +>```platformio lib -g install 2778 1665 ArduinoJson@6.10.0``` + +# + +### running the tests on an Arduino board using PlatformIO + +**`cd` into this directory "*.../Cpp-Crypto/test*"** +> ```cd test``` + +**execute the following command to upload test to your board** + +>| board | command | +>|:-- |:-- | +>| ESP8266 | ```pio run -e esp8266 -t upload``` | +>| ESP32 | ```pio run -e esp32 -t upload``` | + +> ^ the above runs the tests rooted in the following file: +> "*.../cpp-crypto/test/IoT/test_main.cpp*" diff --git a/extras/docs/cpp.md b/extras/docs/cpp.md index cdf32d5f..2d5b0d6a 100644 --- a/extras/docs/cpp.md +++ b/extras/docs/cpp.md @@ -6,8 +6,84 @@ title: "Cpp" [[toc]] -## Installation -* [Arduino](#Arduino) +## Installation +* [Arduino](#Arduino) +* [Linux >= 16.04](#OS) +* [macOS >= 10.10](#OS) +* [Windows >= 7](#OS) + +### ARK Transactions + +#### Devnet + +```cpp +const auto DevnetTransaction = Builder::buildTransfer( + "D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib", + 100000000ULL, + "this is a devnet transaction", + "this is a top secret passphrase", + "this is a top secret passphrase too"); +``` + +#### Mainnet + +```cpp +const Configuration MainnetConfiguration(Networks::Mainnet()); + +const auto MainnetTransaction = Builder::buildTransfer( + "D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib", + 100000000ULL, + "this is a mainnet transaction", + "this is a top secret passphrase", + "this is a top secret passphrase too", + MainnetConfiguration); +``` + +#### BridgeChain Transaction + +```cpp +static const Network MyBridgechainNetwork = { + "16c891512149d6d3ff1b70e65900936140bf853a4ae79b5515157981dcc706df", + 1, 0x53, 0xaa, + "2019-04-12T13:00:00.000Z" +}; + +const Configuration MyBridgechainConfiguration(MyBridgechainNetwork); + +const auto MyBridgechainTransaction = Builder::buildTransfer( + "D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib", + 100000000ULL, + "this is a custom bridgechain transaction", + "this is a top secret passphrase", + "this is a top secret passphrase too", + MyBridgechainConfiguration); +``` + +#### With custom Fees + +```cpp +static const Network MyBridgechainNetwork = { + "16c891512149d6d3ff1b70e65900936140bf853a4ae79b5515157981dcc706df", + 1, 0x53, 0xaa, + "2019-04-12T13:00:00.000Z" +}; + +const FeePolicy MyCustomFees = { + 900000000ULL, 800000000ULL, 700000000ULL, 600000000ULL, 500000000ULL, + 400000000ULL, 300000000ULL, 200000000ULL, 100000000ULL, 0ULL +}; + +ßconst Configuration MyBridgechainConfiguration(MyBridgechainNetwork, + MyCustomFees); + +const auto MyBridgechainTransaction = Builder::buildTransfer( + "D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib", + 100000000ULL, + "", + "this is a top secret passphrase", + "", + MyBridgechainConfiguration); +``` ### Sign diff --git a/keywords.txt b/keywords.txt index 98cd5e48..5ef6954f 100644 --- a/keywords.txt +++ b/keywords.txt @@ -6,33 +6,33 @@ # Datatypes (KEYWORD1) ####################################### -Ark KEYWORD1 -Crypto KEYWORD1 -Configuration KEYWORD1 -Enums KEYWORD1 -Identities KEYWORD1 -Networks KEYWORD1 -Transactions KEYWORD1 -Utils KEYWORD1 - -Fee KEYWORD1 -Network KEYWORD1 - -Fees KEYWORD1 -Types KEYWORD1 - -Address KEYWORD1 -PrivateKey KEYWORD1 -PublicKey KEYWORD1 -WIF KEYWORD1 - -Builder KEYWORD1 -Deserializer KEYWORD1 -Serializer KEYWORD1 -Transaction KEYWORD1 - -Message KEYWORD1 -Slot KEYWORD1 +Ark KEYWORD1 +Crypto KEYWORD1 +common KEYWORD1 +defaults KEYWORD1 +Identities KEYWORD1 +managers KEYWORD1 +Transactions KEYWORD1 +Utils KEYWORD1 + +Configuration KEYWORD1 +FeePolicy KEYWORD1 +Network KEYWORD1 + +Address KEYWORD1 +PrivateKey KEYWORD1 +PublicKey KEYWORD1 +WIF KEYWORD1 + +Networks KEYWORD1 + +Builder KEYWORD1 +Deserializer KEYWORD1 +Serializer KEYWORD1 +Transaction KEYWORD1 + +Message KEYWORD1 +Slot KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) @@ -42,6 +42,10 @@ Slot KEYWORD1 # Constants (LITERAL1) ####################################### -Devnet LITERAL1 -Mainnet LITERAL1 -Testnet LITERAL1 +Fees KEYWORD1 +StaticFeePolicy KEYWORD1 +TransactionTypes KEYWORD1 + +Devnet LITERAL1 +Mainnet LITERAL1 +Testnet LITERAL1 diff --git a/library.json b/library.json index 305e1aac..70a2d616 100644 --- a/library.json +++ b/library.json @@ -7,7 +7,7 @@ "type": "git", "url": "https://github.com/ArkEcosystem/Cpp-Crypto.git" }, - "version": "0.3.0-arduino", + "version": "0.6.0-arduino", "authors": [ { "name": "Ark Ecosystem", @@ -23,20 +23,9 @@ }, { "name": "ArduinoJson" + }, + { + "name": "BIP66" } - ], - "export": { - "include": [ - "src/*", - "examples/*", - "docs/*", - "extras/*", - "*.md", - "*.json", - "*.properties", - "LICENSE", - "*.ini", - "keywords.txt" - ] - } -} + ] +} \ No newline at end of file diff --git a/library.properties b/library.properties index 600bff5d..e1937afe 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Ark-Cpp-Crypto -version=0.3.0-arduino +version=0.6.0-arduino author=Ark Ecosystem maintainer=Ark Ecosystem sentence=A simple Cryptography Implementation in C++ for the ARK Blockchain. diff --git a/src/arkCrypto.h b/src/arkCrypto.h index 17f23742..ec069466 100644 --- a/src/arkCrypto.h +++ b/src/arkCrypto.h @@ -10,26 +10,22 @@ #ifndef ARKCRYPTO_H #define ARKCRYPTO_H -#define HAS_CRYPTO +#include "common/configuration.hpp" +#include "common/fee_policy.hpp" +#include "common/network.hpp" -#if (defined ARDUINO || defined ESP8266 || defined ESP32) -#define USE_IOT -#endif - -#include "configuration/fee.h" -#include "configuration/network.h" -#include "enums/fees.h" -#include "enums/types.h" +#include "defaults/fee_policies.hpp" +#include "defaults/static_fees.hpp" +#include "defaults/transaction_types.hpp" #include "identities/address.h" #include "identities/privatekey.h" #include "identities/publickey.h" #include "identities/wif.h" -#include "networks/abstractnetwork.h" -#include "networks/devnet.h" -#include "networks/mainnet.h" -#include "networks/testnet.h" +#include "networks/devnet.hpp" +#include "networks/mainnet.hpp" +#include "networks/testnet.hpp" #include "transactions/builder.h" #include "transactions/deserializer.h" @@ -39,10 +35,9 @@ #include "utils/message.h" #include "utils/slot.h" -using namespace Ark::Crypto::Configuration; -using namespace Ark::Crypto::Enums; +using namespace Ark::Crypto; using namespace Ark::Crypto::Identities; -using namespace Ark::Crypto::Networks; using namespace Ark::Crypto::Transactions; +using namespace Ark::Crypto::Utils; #endif diff --git a/src/common/configuration.cpp b/src/common/configuration.cpp new file mode 100644 index 00000000..fcd79095 --- /dev/null +++ b/src/common/configuration.cpp @@ -0,0 +1,27 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#include "common/configuration.hpp" + +namespace Ark { +namespace Crypto { + +bool Configuration::operator==(const Configuration& rhs) const { + return this->getNetwork() == rhs.getNetwork() + && this->getPolicy() == rhs.getPolicy(); +} + +/**/ + +bool Configuration::operator!=(const Configuration& rhs) const { + return this->getNetwork() != rhs.getNetwork() + || this->getPolicy() != rhs.getPolicy();} + +} // namespace Crypto +} // namespace Ark diff --git a/src/common/configuration.hpp b/src/common/configuration.hpp new file mode 100644 index 00000000..abc7eaf0 --- /dev/null +++ b/src/common/configuration.hpp @@ -0,0 +1,45 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#ifndef COMMON_CONFIGURATION_HPP +#define COMMON_CONFIGURATION_HPP + +#include "common/network.hpp" +#include "managers/network_manager.hpp" +#include "common/fee_policy.hpp" +#include "managers/fee_manager.hpp" + +namespace Ark { +namespace Crypto { +/**/ +class Configuration : public managers::NetworkManager, + public managers::FeeManager { + public: + // Default initialization: using ARK Devnet & StaticFees + Configuration() = default; + ~Configuration() = default; + + // Network initialization: Custom Network & StaticFees + explicit Configuration(const Network& network) : NetworkManager(network) {} + + // FeePolicy initialization: ARK Devnet & Custom Fees + explicit Configuration(const FeePolicy& policy) : FeeManager(policy) {} + + // Network & Fee initialization: Custom Network & Custom Fees + Configuration(const Network& network, const FeePolicy& policy) + : NetworkManager(network), FeeManager(policy) {} + + bool operator==(const Configuration& rhs) const; + bool operator!=(const Configuration& rhs) const; +}; +/**/ +} // namespace Crypto +} // namespace Ark + +#endif diff --git a/src/common/fee_policy.hpp b/src/common/fee_policy.hpp new file mode 100644 index 00000000..bede2c6a --- /dev/null +++ b/src/common/fee_policy.hpp @@ -0,0 +1,24 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#ifndef COMMON_TRANSACTION_FEE_POLICY_HPP +#define COMMON_TRANSACTION_FEE_POLICY_HPP + +#include +#include + +namespace Ark { +namespace Crypto { +/**/ +typedef std::vector FeePolicy; +/**/ +} // namespace Crypto +} // namespace Ark + +#endif diff --git a/src/common/network.cpp b/src/common/network.cpp new file mode 100644 index 00000000..53664322 --- /dev/null +++ b/src/common/network.cpp @@ -0,0 +1,49 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#include "common/network.hpp" +#include "networks/devnet.hpp" + +namespace Ark { +namespace Crypto { + +Network::Network() { *this = Networks::Devnet(); } + +/**/ + +std::string Network::nethash() const { return this->nethash_; } +uint8_t Network::slip44() const { return this->slip44_; } +uint8_t Network::wif() const { return this->wif_; } +uint8_t Network::version() const { return this->version_; } +std::string Network::epoch() const { return this->epoch_; } + +/**/ + +bool Network::operator==(const Network& rhs) const { + bool numericsMatch = (this->slip44_ == rhs.slip44_) + && (this->wif_ == rhs.wif_) + && (this->version_ == rhs.version_); + bool stringsMatch = (this->nethash_ == rhs.nethash_) + && (this->epoch_ == rhs.epoch_); + return numericsMatch && stringsMatch; +} + +/**/ + +bool Network::operator!=(const Network& rhs) const { + bool numericsMatch = (this->slip44_ != rhs.slip44_) + || (this->wif_ != rhs.wif_) + || (this->version_ != rhs.version_); + bool stringsMatch = (this->nethash_ != rhs.nethash_) + || (this->epoch_ != rhs.epoch_); + return numericsMatch || stringsMatch; +} + +} // namespace Crypto +} // namespace Ark diff --git a/src/common/network.hpp b/src/common/network.hpp new file mode 100644 index 00000000..d93a19bd --- /dev/null +++ b/src/common/network.hpp @@ -0,0 +1,56 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#ifndef COMMON_NETWORK_H +#define COMMON_NETWORK_H + +#include +#include + +namespace Ark { +namespace Crypto { +/**/ +// Abstract Network class +// +// Default initialization is ARK Devnet +class Network final { + public: + Network(); + Network(std::string nethash, + uint8_t slip44, + uint8_t wif, + uint8_t version, + std::string epoch) + : nethash_(nethash), + slip44_(slip44), + wif_(wif), + version_(version), + epoch_(epoch) {} + + std::string nethash() const; + uint8_t slip44() const; + uint8_t wif() const; + uint8_t version() const; + std::string epoch() const; + + bool operator==(const Network& rhs) const; + bool operator!=(const Network& rhs) const; + + private: + std::string nethash_; + uint8_t slip44_; + uint8_t wif_; + uint8_t version_; + std::string epoch_; +}; +/**/ +} // namespace Crypto +} // namespace Ark + +#endif diff --git a/src/configuration/fee.cpp b/src/configuration/fee.cpp deleted file mode 100644 index 6f6fe63d..00000000 --- a/src/configuration/fee.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ - -#include "configuration/fee.h" - -/** - * @brief Get the transaction fee for the given type. - * - * @param const int type - * @return uint64_t - **/ -uint64_t Ark::Crypto::Configuration::Fee::get(int type) { - return this->fees_[type]; -}; -/**/ - -/** - * @brief Set the transaction fee for the given type. - * - * @param const int type - * @param const uint64_t fee - **/ -void Ark::Crypto::Configuration::Fee::set(int type, uint64_t fee) { - this->fees_[type] = fee; -}; -/**/ diff --git a/src/configuration/fee.h b/src/configuration/fee.h deleted file mode 100644 index 986c5634..00000000 --- a/src/configuration/fee.h +++ /dev/null @@ -1,53 +0,0 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ - -#ifndef FEE_H -#define FEE_H - -#include "enums/fees.h" -#include "enums/types.h" -using namespace Ark::Crypto::Enums; - -#include - -namespace Ark { -namespace Crypto { -namespace Configuration { -/** - * This is the fee configuration class. - * - * @author Simon Downey - **/ -class Fee { - private: - /** - * @brief The default transaction fees array. - **/ - uint64_t fees_[9] = {Fees::TRANSFER, - Fees::SECOND_SIGNATURE_REGISTRATION, - Fees::DELEGATE_REGISTRATION, - Fees::VOTE, - Fees::MULTI_SIGNATURE_REGISTRATION, - Fees::IPFS, - Fees::TIMELOCK_TRANSFER, - Fees::MULTI_PAYMENT, - Fees::DELEGATE_RESIGNATION}; - /**/ - public: - Fee() = default; - uint64_t get(int type); - void set(int type, uint64_t fee); -}; -/**/ - -}; // namespace Configuration -}; // namespace Crypto -}; // namespace Ark - -#endif diff --git a/src/configuration/network.cpp b/src/configuration/network.cpp deleted file mode 100644 index b3355091..00000000 --- a/src/configuration/network.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ - -#include "configuration/network.h" - -/** - * @brief Get the network used for crypto operations. - * - * @return AbstractNetwork - **/ -Ark::Crypto::Networks::AbstractNetwork Ark::Crypto::Configuration::Network::get() { - return (this->network_.getBase58Prefix(BASE58_ADDRESS_P2PKH) == 0x00) ? (Devnet) : (this->network_); -} -/**/ - -/** - * @brief Set the network used for crypto operations. - * - * @param AbstractNetwork network - **/ -void Ark::Crypto::Configuration::Network::set(const Ark::Crypto::Networks::AbstractNetwork& network) { - this->network_ = network; -}; -/**/ diff --git a/src/configuration/network.h b/src/configuration/network.h deleted file mode 100644 index a6bb4d4e..00000000 --- a/src/configuration/network.h +++ /dev/null @@ -1,44 +0,0 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ - -#ifndef NETWORK_H -#define NETWORK_H - -#include "networks/abstractnetwork.h" -#include "networks/devnet.h" -#include "networks/mainnet.h" -#include "networks/testnet.h" - -#include - -namespace Ark { -namespace Crypto { -namespace Configuration { - -using namespace Ark::Crypto::Networks; - -/** - * @brief This is the network configuration class. - * - * @author Simon Downey - **/ -class Network { - private: - AbstractNetwork network_; - - public: - AbstractNetwork get(); - void set(const AbstractNetwork& network); -}; -/**/ -}; // namespace Configuration -}; // namespace Crypto -}; // namespace Ark - -#endif diff --git a/src/date/date.h b/src/date/date.h deleted file mode 100644 index b67d14b3..00000000 --- a/src/date/date.h +++ /dev/null @@ -1,8344 +0,0 @@ -#ifndef DATE_H -#define DATE_H - -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016, 2017 Howard Hinnant -// Copyright (c) 2016 Adrian Colomitchi -// Copyright (c) 2017 Florian Dang -// Copyright (c) 2017 Paul Thompson -// Copyright (c) 2018 Tomasz KamiΕ„ski -// -// 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 would involve another several millennia of evolution). -// We did not mean to shout. - -#ifndef HAS_STRING_VIEW -# if __cplusplus >= 201703 -# define HAS_STRING_VIEW 1 -# else -# define HAS_STRING_VIEW 0 -# endif -#endif // HAS_STRING_VIEW - -#include -#include -#include -#include -#include -#if !(__cplusplus >= 201402) -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if HAS_STRING_VIEW -# include -#endif -#include -#include - -#ifdef __GNUC__ -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wpedantic" -# if __GNUC__ < 5 - // GCC 4.9 Bug 61489 Wrong warning with -Wmissing-field-initializers -# pragma GCC diagnostic ignored "-Wmissing-field-initializers" -# endif -#endif - -namespace date -{ - -//---------------+ -// Configuration | -//---------------+ - -// Always use C locale to ensure maximum support for different compilers -// https ://github.com/HowardHinnant/date/issues/264 -#define ONLY_C_LOCALE 1 - -#if defined(_MSC_VER) && (!defined(__clang__) || (_MSC_VER < 1910)) -// MSVC -# define _SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING -# if _MSC_VER < 1910 -// before VS2017 -# define CONSTDATA const -# define CONSTCD11 -# define CONSTCD14 -# define NOEXCEPT _NOEXCEPT -# else -// VS2017 and later -# define CONSTDATA constexpr const -# define CONSTCD11 constexpr -# define CONSTCD14 constexpr -# define NOEXCEPT noexcept -# endif - -#elif defined(__SUNPRO_CC) && __SUNPRO_CC <= 0x5150 -// Oracle Developer Studio 12.6 and earlier -# define CONSTDATA constexpr const -# define CONSTCD11 constexpr -# define CONSTCD14 -# define NOEXCEPT noexcept - -#elif __cplusplus >= 201402 -// C++14 -# define CONSTDATA constexpr const -# define CONSTCD11 constexpr -# define CONSTCD14 constexpr -# define NOEXCEPT noexcept -#else -// C++11 -# define CONSTDATA constexpr const -# define CONSTCD11 constexpr -# define CONSTCD14 -# define NOEXCEPT noexcept -#endif - -#ifndef HAS_VOID_T -# if __cplusplus >= 201703 -# define HAS_VOID_T 1 -# else -# define HAS_VOID_T 0 -# endif -#endif // HAS_VOID_T - -// Protect from Oracle sun macro -#ifdef sun -# undef sun -#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; - 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 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; - - friend CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT; - friend CONSTCD14 days operator-(const weekday& x, const weekday& y) NOEXCEPT; - friend CONSTCD14 weekday operator+(const weekday& x, const days& y) NOEXCEPT; - template - friend std::basic_ostream& - operator<<(std::basic_ostream& os, const weekday& wd); - friend class weekday_indexed; -}; - -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: - weekday_indexed() = default; - 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); - -namespace detail -{ - -struct unspecified_month_disambiguator {}; - -} // namespace detail - -// 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; - - template - CONSTCD14 year_month& operator+=(const months& dm) NOEXCEPT; - template - 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; - -template -CONSTCD14 year_month operator+(const year_month& ym, const months& dm) NOEXCEPT; -template -CONSTCD14 year_month operator+(const months& dm, const year_month& ym) NOEXCEPT; -template -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; - - template - CONSTCD14 year_month_day& operator+=(const months& m) NOEXCEPT; - template - 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; - -template -CONSTCD14 year_month_day operator+(const year_month_day& ymd, const months& dm) NOEXCEPT; -template -CONSTCD14 year_month_day operator+(const months& dm, const year_month_day& ymd) NOEXCEPT; -template -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; - - template - CONSTCD14 year_month_day_last& operator+=(const months& m) NOEXCEPT; - template - 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; - -template -CONSTCD14 -year_month_day_last -operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT; - -template -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; - -template -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; - - template - CONSTCD14 year_month_weekday& operator+=(const months& m) NOEXCEPT; - template - 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; - -template -CONSTCD14 -year_month_weekday -operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT; - -template -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; - -template -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; - - template - CONSTCD14 year_month_weekday_last& operator+=(const months& m) NOEXCEPT; - template - 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; - -template -CONSTCD14 -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT; - -template -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; - -template -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; - -} // inline namespace literals -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - -// CONSTDATA date::month January{1}; -// CONSTDATA date::month February{2}; -// CONSTDATA date::month March{3}; -// CONSTDATA date::month April{4}; -// CONSTDATA date::month May{5}; -// CONSTDATA date::month June{6}; -// CONSTDATA date::month July{7}; -// CONSTDATA date::month August{8}; -// CONSTDATA date::month September{9}; -// CONSTDATA date::month October{10}; -// CONSTDATA date::month November{11}; -// CONSTDATA date::month December{12}; -// -// CONSTDATA date::weekday Sunday{0u}; -// CONSTDATA date::weekday Monday{1u}; -// CONSTDATA date::weekday Tuesday{2u}; -// CONSTDATA date::weekday Wednesday{3u}; -// CONSTDATA date::weekday Thursday{4u}; -// CONSTDATA date::weekday Friday{5u}; -// CONSTDATA date::weekday Saturday{6u}; - -#if HAS_VOID_T - -template > -struct is_clock - : std::false_type -{}; - -template -struct is_clock> - : std::true_type -{}; - -#endif // HAS_VOID_T - -//----------------+ -// Implementation | -//----------------+ - -// utilities -namespace detail { - -template> -class save_istream -{ -protected: - std::basic_ios& is_; - CharT fill_; - std::ios::fmtflags flags_; - std::streamsize width_; - std::basic_ostream* tie_; - std::locale loc_; - -public: - ~save_istream() - { - is_.fill(fill_); - is_.flags(flags_); - is_.width(width_); - is_.imbue(loc_); - is_.tie(tie_); - } - - save_istream(const save_istream&) = delete; - save_istream& operator=(const save_istream&) = delete; - - explicit save_istream(std::basic_ios& is) - : is_(is) - , fill_(is.fill()) - , flags_(is.flags()) - , width_(is.width(0)) - , tie_(is.tie(nullptr)) - , loc_(is.getloc()) - { - if (tie_ != nullptr) - tie_->flush(); - } -}; - -template> -class save_ostream - : private save_istream -{ -public: - ~save_ostream() - { - if ((this->flags_ & std::ios::unitbuf) && -#if __cplusplus >= 201703 - std::uncaught_exceptions() == 0 && -#else - !std::uncaught_exception() && -#endif - this->is_.good()) - this->is_.rdbuf()->pubsync(); - } - - save_ostream(const save_ostream&) = delete; - save_ostream& operator=(const save_ostream&) = delete; - - explicit save_ostream(std::basic_ios& os) - : save_istream(os) - { - } -}; - -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; -}; - -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; -} - -template -struct static_gcd -{ - static const std::intmax_t value = static_gcd::value; -}; - -template -struct static_gcd -{ - static const std::intmax_t value = Xp; -}; - -template <> -struct static_gcd<0, 0> -{ - static const std::intmax_t value = 1; -}; - -template -struct no_overflow -{ -private: - static const std::intmax_t gcd_n1_n2 = static_gcd::value; - static const std::intmax_t gcd_d1_d2 = static_gcd::value; - static const std::intmax_t n1 = R1::num / gcd_n1_n2; - static const std::intmax_t d1 = R1::den / gcd_d1_d2; - static const std::intmax_t n2 = R2::num / gcd_n1_n2; - static const std::intmax_t d2 = R2::den / gcd_d1_d2; - static const std::intmax_t max = -((std::intmax_t(1) << - (sizeof(std::intmax_t) * CHAR_BIT - 1)) + 1); - - template - struct mul // overflow == false - { - static const std::intmax_t value = Xp * Yp; - }; - - template - struct mul - { - static const std::intmax_t value = 1; - }; - -public: - static const bool value = (n1 <= max / d2) && (n2 <= max / d1); - typedef std::ratio::value, - mul::value> type; -}; - -} // detail - -// trunc towards zero -template -CONSTCD11 -inline -typename std::enable_if -< - detail::no_overflow::value, - To ->::type -trunc(const std::chrono::duration& d) -{ - return To{detail::trunc(std::chrono::duration_cast(d).count())}; -} - -template -CONSTCD11 -inline -typename std::enable_if -< - !detail::no_overflow::value, - To ->::type -trunc(const std::chrono::duration& d) -{ - using namespace std::chrono; - using rep = typename std::common_type::type; - return To{detail::trunc(duration_cast(duration_cast>(d)).count())}; -} - -#ifndef HAS_CHRONO_ROUNDING -# if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 190023918 || (_MSC_FULL_VER >= 190000000 && defined (__clang__))) -# 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 -typename std::enable_if -< - detail::no_overflow::value, - To ->::type -floor(const std::chrono::duration& d) -{ - auto t = trunc(d); - if (t > d) - return t - To{1}; - return t; -} - -template -CONSTCD14 -inline -typename std::enable_if -< - !detail::no_overflow::value, - To ->::type -floor(const std::chrono::duration& d) -{ - using namespace std::chrono; - using rep = typename std::common_type::type; - return floor(floor>(d)); -} - -// 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{date::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_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << static_cast(d); - if (!d.ok()) - os << " is not a valid day"; - return os; -} - -// month - -CONSTCD11 inline month::month(unsigned m) NOEXCEPT : m_(static_cast(m)) {} -CONSTCD14 inline month& month::operator++() NOEXCEPT {*this += months{1}; return *this;} -CONSTCD14 inline month month::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline month& month::operator--() NOEXCEPT {*this -= months{1}; 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)) + (y.count() - 1); - 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) -{ - if (m.ok()) - { - CharT fmt[] = {'%', 'b', 0}; - os << format(os.getloc(), fmt, m); - } - else - os << static_cast(m) << " is not a valid month"; - 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 y_ != std::numeric_limits::min(); -} - -CONSTCD11 -inline -year -year::min() NOEXCEPT -{ - return year{-32767}; -} - -CONSTCD11 -inline -year -year::max() NOEXCEPT -{ - return year{32767}; -} - -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_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::internal); - os.width(4 + (y < year{0})); - os << static_cast(y); - if (!y.ok()) - os << " is not a valid year"; - 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 != 7 ? wd : 0)) - {} - -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 {*this += days{1}; return *this;} -CONSTCD14 inline weekday weekday::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline weekday& weekday::operator--() NOEXCEPT {*this -= days{1}; 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 bool weekday::ok() const NOEXCEPT {return wd_ <= 6;} - -CONSTCD11 -inline -bool -operator==(const weekday& x, const weekday& y) NOEXCEPT -{ - return x.wd_ == y.wd_; -} - -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 wdu = x.wd_ - y.wd_; - auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7; - return days{wdu - wk * 7}; -} - -CONSTCD14 -inline -weekday -operator+(const weekday& x, const days& y) NOEXCEPT -{ - auto const wdu = static_cast(static_cast(x.wd_)) + 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) -{ - if (wd.ok()) - { - CharT fmt[] = {'%', 'a', 0}; - os << format(fmt, wd); - } - else - os << static_cast(wd.wd_) << " is not a valid weekday"; - 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 - -CONSTDATA date::month January{1}; -CONSTDATA date::month February{2}; -CONSTDATA date::month March{3}; -CONSTDATA date::month April{4}; -CONSTDATA date::month May{5}; -CONSTDATA date::month June{6}; -CONSTDATA date::month July{7}; -CONSTDATA date::month August{8}; -CONSTDATA date::month September{9}; -CONSTDATA date::month October{10}; -CONSTDATA date::month November{11}; -CONSTDATA date::month December{12}; - -CONSTDATA date::weekday Monday{1}; -CONSTDATA date::weekday Tuesday{2}; -CONSTDATA date::weekday Wednesday{3}; -CONSTDATA date::weekday Thursday{4}; -CONSTDATA date::weekday Friday{5}; -CONSTDATA date::weekday Saturday{6}; -CONSTDATA date::weekday Sunday{7}; - -// 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; -} - -#ifdef __GNUC__ -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wconversion" -#endif // __GNUC__ - -CONSTCD11 -inline -weekday_indexed::weekday_indexed(const date::weekday& wd, unsigned index) NOEXCEPT - : wd_(static_cast(static_cast(wd.wd_))) - , index_(static_cast(index)) - {} - -#ifdef __GNUC__ -# pragma GCC diagnostic pop -#endif // __GNUC__ - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_indexed& wdi) -{ - os << wdi.weekday() << '[' << wdi.index(); - if (!(1 <= wdi.index() && wdi.index() <= 5)) - os << " is not a valid index"; - os << ']'; - return os; -} - -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();} - -template -CONSTCD14 -inline -year_month& -year_month::operator+=(const months& dm) NOEXCEPT -{ - *this = *this + dm; - return *this; -} - -template -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); -} - -template -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)); -} - -template -CONSTCD14 -inline -year_month -operator+(const months& dm, const year_month& ym) NOEXCEPT -{ - return ym + dm; -} - -template -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) - {} - -template -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -template -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() != February || !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(); -} - -template -CONSTCD14 -inline -year_month_day_last -operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT -{ - return (ymdl.year() / ymdl.month() + dm) / last; -} - -template -CONSTCD14 -inline -year_month_day_last -operator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT -{ - return ymdl + dm; -} - -template -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_;} - -template -CONSTCD14 -inline -year_month_day& -year_month_day::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -template -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_ <= February); - 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_ostream _(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(); - if (!ymd.ok()) - os << " is not a valid date"; - 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)}; -} - -template -CONSTCD14 -inline -year_month_day -operator+(const year_month_day& ymd, const months& dm) NOEXCEPT -{ - return (ymd.year() / ymd.month() + dm) / ymd.day(); -} - -template -CONSTCD14 -inline -year_month_day -operator+(const months& dm, const year_month_day& ymd) NOEXCEPT -{ - return ymd + dm; -} - -template -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())) - {} - -template -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -template -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(); -} - -template -CONSTCD14 -inline -year_month_weekday -operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT -{ - return (ymwd.year() / ymwd.month() + dm) / ymwd.weekday_indexed(); -} - -template -CONSTCD14 -inline -year_month_weekday -operator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT -{ - return ymwd + dm; -} - -template -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) - {} - -template -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -template -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(); -} - -template -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(); -} - -template -CONSTCD14 -inline -year_month_weekday_last -operator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT -{ - return ymwdl + dm; -} - -template -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; -} - -template -struct fields; - -template -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, - const fields& fds, const std::string* abbrev = nullptr, - const std::chrono::seconds* offset_sec = nullptr); - -template -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, - fields& fds, std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr); - -// time_of_day - -enum {am = 1, pm}; - -namespace detail -{ - -// width::value is the number of fractional decimal digits in 1/n -// width<0>::value and width<1>::value are defined to be 0 -// If 1/n takes more than 18 fractional decimal digits, -// the result is truncated to 19. -// Example: width<2>::value == 1 -// Example: width<3>::value == 19 -// Example: width<4>::value == 2 -// Example: width<10>::value == 1 -// Example: width<1000>::value == 3 -template -struct width -{ - static CONSTDATA unsigned value = 1 + width::value; -}; - -template -struct width -{ - static CONSTDATA unsigned value = 0; -}; - -template -struct static_pow10 -{ -private: - static CONSTDATA std::uint64_t h = static_pow10::value; -public: - static CONSTDATA std::uint64_t value = h * h * (exp % 2 ? 10 : 1); -}; - -template <> -struct static_pow10<0> -{ - static CONSTDATA std::uint64_t value = 1; -}; - -template -struct make_precision -{ - using type = std::chrono::duration::value>>; - static CONSTDATA unsigned width = w; -}; - -template -struct make_precision -{ - using type = std::chrono::duration; - static CONSTDATA unsigned width = 6; -}; - -template ::type::period::den>::value> -class decimal_format_seconds -{ -public: - using rep = typename std::common_type::type::rep; - using precision = typename make_precision::type; - static auto CONSTDATA width = make_precision::width; - -private: - std::chrono::seconds s_; - precision sub_s_; - -public: - CONSTCD11 decimal_format_seconds() - : s_() - , sub_s_() - {} - - CONSTCD11 explicit decimal_format_seconds(const Duration& d) NOEXCEPT - : s_(std::chrono::duration_cast(d)) - , sub_s_(std::chrono::duration_cast(d - s_)) - {} - - 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_;} - - CONSTCD14 precision to_duration() const NOEXCEPT - { - return s_ + sub_s_; - } - - CONSTCD11 bool in_conventional_range() const NOEXCEPT - { - using namespace std::chrono; - return sub_s_ < std::chrono::seconds{1} && s_ < minutes{1}; - } - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const decimal_format_seconds& x) - { - date::detail::save_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << x.s_.count() << - std::use_facet>(os.getloc()).decimal_point(); - os.width(width); - os << static_cast(x.sub_s_.count()); - return os; - } -}; - -template -class decimal_format_seconds -{ - static CONSTDATA unsigned w = 0; -public: - using rep = typename std::common_type::type::rep; - using precision = std::chrono::duration; - static auto CONSTDATA width = make_precision::width; -private: - - std::chrono::seconds s_; - -public: - CONSTCD11 decimal_format_seconds() : s_() {} - CONSTCD11 explicit decimal_format_seconds(const precision& s) NOEXCEPT - : s_(s) - {} - - CONSTCD14 std::chrono::seconds& seconds() NOEXCEPT {return s_;} - CONSTCD11 std::chrono::seconds seconds() const NOEXCEPT {return s_;} - CONSTCD14 precision to_duration() const NOEXCEPT {return s_;} - - CONSTCD11 bool in_conventional_range() const NOEXCEPT - { - using namespace std::chrono; - return s_ < minutes{1}; - } - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const decimal_format_seconds& x) - { - date::detail::save_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << x.s_.count(); - return os; - } -}; - -enum class classify -{ - not_valid, - hour, - minute, - second, - subsecond -}; - -template -struct classify_duration -{ - static CONSTDATA classify value = - std::is_convertible::value - ? classify::hour : - std::is_convertible::value - ? classify::minute : - std::is_convertible::value - ? classify::second : - std::chrono::treat_as_floating_point::value - ? classify::not_valid : - classify::subsecond; -}; - -template -inline -CONSTCD11 -typename std::enable_if - < - std::numeric_limits::is_signed, - std::chrono::duration - >::type -abs(std::chrono::duration d) -{ - return d >= d.zero() ? +d : -d; -} - -template -inline -CONSTCD11 -typename std::enable_if - < - !std::numeric_limits::is_signed, - std::chrono::duration - >::type -abs(std::chrono::duration d) -{ - return d; -} - -class time_of_day_base -{ -protected: - std::chrono::hours h_; - unsigned char mode_; - bool neg_; - - enum {is24hr}; - - CONSTCD11 time_of_day_base() NOEXCEPT - : h_(0) - , mode_(static_cast(is24hr)) - , neg_(false) - {} - - - CONSTCD11 time_of_day_base(std::chrono::hours h, bool neg, unsigned m) NOEXCEPT - : h_(detail::abs(h)) - , mode_(static_cast(m)) - , neg_(neg) - {} - - CONSTCD14 void make24() NOEXCEPT; - CONSTCD14 void make12() NOEXCEPT; - - CONSTCD14 std::chrono::hours to24hr() const; - - CONSTCD11 bool in_conventional_range() const NOEXCEPT - { - return !neg_ && h_ < days{1}; - } -}; - -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; - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 - CONSTCD11 time_of_day_storage() NOEXCEPT = default; -#else - CONSTCD11 time_of_day_storage() = default; -#endif /* !defined(_MSC_VER) || _MSC_VER >= 1900 */ - - CONSTCD11 explicit time_of_day_storage(std::chrono::hours since_midnight) NOEXCEPT - : base(since_midnight, since_midnight < std::chrono::hours{0}, is24hr) - {} - - CONSTCD11 explicit time_of_day_storage(std::chrono::hours h, unsigned md) NOEXCEPT - : base(h, h < std::chrono::hours{0}, md) - {} - - CONSTCD11 std::chrono::hours hours() const NOEXCEPT {return h_;} - CONSTCD11 unsigned mode() const NOEXCEPT {return mode_;} - - CONSTCD14 explicit operator precision() const NOEXCEPT - { - auto p = to24hr(); - if (neg_) - p = -p; - return p; - } - - 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;} - - CONSTCD11 bool in_conventional_range() const NOEXCEPT - { - return base::in_conventional_range(); - } - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const time_of_day_storage& t) - { - using namespace std; - detail::save_ostream _(os); - if (t.neg_) - 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 time_of_day_storage() NOEXCEPT - : base() - , m_(0) - {} - - CONSTCD11 explicit time_of_day_storage(std::chrono::minutes since_midnight) NOEXCEPT - : base(std::chrono::duration_cast(since_midnight), - since_midnight < std::chrono::minutes{0}, is24hr) - , m_(detail::abs(since_midnight) - h_) - {} - - CONSTCD11 explicit time_of_day_storage(std::chrono::hours h, std::chrono::minutes m, - unsigned md) NOEXCEPT - : base(h, false, 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 - { - auto p = to24hr() + m_; - if (neg_) - p = -p; - return p; - } - - 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;} - - CONSTCD11 bool in_conventional_range() const NOEXCEPT - { - return base::in_conventional_range() && m_ < std::chrono::hours{1}; - } - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const time_of_day_storage& t) - { - using namespace std; - detail::save_ostream _(os); - if (t.neg_) - 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() << ':'; - os.width(2); - os << 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; - using dfs = decimal_format_seconds; - - std::chrono::minutes m_; - dfs s_; - -public: - using precision = std::chrono::seconds; - - CONSTCD11 time_of_day_storage() NOEXCEPT - : base() - , m_(0) - , s_() - {} - - CONSTCD11 explicit time_of_day_storage(std::chrono::seconds since_midnight) NOEXCEPT - : base(std::chrono::duration_cast(since_midnight), - since_midnight < std::chrono::seconds{0}, is24hr) - , m_(std::chrono::duration_cast(detail::abs(since_midnight) - h_)) - , s_(detail::abs(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, false, 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_.seconds();} - CONSTCD11 std::chrono::seconds seconds() const NOEXCEPT {return s_.seconds();} - CONSTCD11 unsigned mode() const NOEXCEPT {return mode_;} - - CONSTCD14 explicit operator precision() const NOEXCEPT - { - auto p = to24hr() + s_.to_duration() + m_; - if (neg_) - p = -p; - return p; - } - - 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;} - - CONSTCD11 bool in_conventional_range() const NOEXCEPT - { - return base::in_conventional_range() && m_ < std::chrono::hours{1} && - s_.in_conventional_range(); - } - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const time_of_day_storage& t) - { - using namespace std; - detail::save_ostream _(os); - if (t.neg_) - 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() << ':'; - os.width(2); - os << t.m_.count() << ':' << t.s_; - switch (t.mode_) - { - case am: - os << "am"; - break; - case pm: - os << "pm"; - break; - } - return os; - } - - template - friend - std::basic_ostream& - date::to_stream(std::basic_ostream& os, const CharT* fmt, - const fields& fds, const std::string* abbrev, - const std::chrono::seconds* offset_sec); - - template - friend - std::basic_istream& - date::from_stream(std::basic_istream& is, const CharT* fmt, - fields& fds, - std::basic_string* abbrev, std::chrono::minutes* offset); -}; - -template -class time_of_day_storage, detail::classify::subsecond> - : private detail::time_of_day_base -{ -public: - using Duration = std::chrono::duration; - using dfs = decimal_format_seconds::type>; - using precision = typename dfs::precision; - -private: - using base = detail::time_of_day_base; - - std::chrono::minutes m_; - dfs s_; - -public: - CONSTCD11 time_of_day_storage() NOEXCEPT - : base() - , m_(0) - , s_() - {} - - CONSTCD11 explicit time_of_day_storage(Duration since_midnight) NOEXCEPT - : base(date::trunc(since_midnight), - since_midnight < Duration{0}, is24hr) - , m_(date::trunc(detail::abs(since_midnight) - h_)) - , s_(detail::abs(since_midnight) - h_ - m_) - {} - - 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, false, md) - , m_(m) - , s_(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_.seconds();} - CONSTCD11 std::chrono::seconds seconds() const NOEXCEPT {return s_.seconds();} - CONSTCD11 precision subseconds() const NOEXCEPT {return s_.subseconds();} - CONSTCD11 unsigned mode() const NOEXCEPT {return mode_;} - - CONSTCD14 explicit operator precision() const NOEXCEPT - { - auto p = to24hr() + s_.to_duration() + m_; - if (neg_) - p = -p; - return p; - } - - 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;} - - CONSTCD11 bool in_conventional_range() const NOEXCEPT - { - return base::in_conventional_range() && m_ < std::chrono::hours{1} && - s_.in_conventional_range(); - } - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const time_of_day_storage& t) - { - using namespace std; - detail::save_ostream _(os); - if (t.neg_) - 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() << ':'; - os.width(2); - os << t.m_.count() << ':' << t.s_; - switch (t.mode_) - { - case am: - os << "am"; - break; - case pm: - os << "pm"; - break; - } - return os; - } - - template - friend - std::basic_ostream& - date::to_stream(std::basic_ostream& os, const CharT* fmt, - const fields& fds, const std::string* abbrev, - const std::chrono::seconds* offset_sec); - - template - friend - std::basic_istream& - date::from_stream(std::basic_istream& is, const CharT* fmt, - fields& fds, - std::basic_string* abbrev, std::chrono::minutes* offset); -}; - -} // 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) || _MSC_VER >= 1900 - CONSTCD11 time_of_day() NOEXCEPT = default; -#else - CONSTCD11 time_of_day() = default; -#endif /* !defined(_MSC_VER) || _MSC_VER >= 1900 */ - - CONSTCD11 explicit time_of_day(Duration since_midnight) NOEXCEPT - : base(since_midnight) - {} - - template - CONSTCD11 - explicit time_of_day(Arg0&& arg0, Arg1&& arg1, Args&& ...args) NOEXCEPT - : base(std::forward(arg0), std::forward(arg1), std::forward(args)...) - {} -}; - -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 = date::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()}); -} - -// to_stream - -CONSTDATA year nanyear{-32768}; - -template -struct fields -{ - year_month_day ymd{nanyear/0/0}; - weekday wd{8u}; - time_of_day tod{}; - bool has_tod = false; - -// https ://github.com/HowardHinnant/date/issues/264 -#ifdef USE_IOT - fields() : ymd{ year{0} / 0 / 0 }, wd{ 7u } {} -#else - fields() = default; -#endif - - fields(year_month_day ymd_) : ymd(ymd_) {} - fields(weekday wd_) : wd(wd_) {} - fields(time_of_day tod_) : tod(tod_), has_tod(true) {} - - fields(year_month_day ymd_, weekday wd_) : ymd(ymd_), wd(wd_) {} - fields(year_month_day ymd_, time_of_day tod_) : ymd(ymd_), tod(tod_), - has_tod(true) {} - - fields(weekday wd_, time_of_day tod_) : wd(wd_), tod(tod_), has_tod(true) {} - - fields(year_month_day ymd_, weekday wd_, time_of_day tod_) - : ymd(ymd_) - , wd(wd_) - , tod(tod_) - , has_tod(true) - {} -}; - -namespace detail -{ - -template -unsigned -extract_weekday(std::basic_ostream& os, const fields& fds) -{ - if (!fds.ymd.ok() && !fds.wd.ok()) - { - // fds does not contain a valid weekday - os.setstate(std::ios::failbit); - return 8; - } - weekday wd; - if (fds.ymd.ok()) - { - wd = weekday{sys_days(fds.ymd)}; - if (fds.wd.ok() && wd != fds.wd) - { - // fds.ymd and fds.wd are inconsistent - os.setstate(std::ios::failbit); - return 8; - } - } - else - wd = fds.wd; - return static_cast((wd - Sunday).count()); -} - -template -unsigned -extract_month(std::basic_ostream& os, const fields& fds) -{ - if (!fds.ymd.month().ok()) - { - // fds does not contain a valid month - os.setstate(std::ios::failbit); - return 0; - } - return static_cast(fds.ymd.month()); -} - -} // namespace detail - -#if ONLY_C_LOCALE - -namespace detail -{ - -inline -std::pair -weekday_names() -{ - static const std::string nm[] = - { - "Sunday", - "Monday", - "Tuesday", - "Wednesday", - "Thursday", - "Friday", - "Saturday", - "Sun", - "Mon", - "Tue", - "Wed", - "Thu", - "Fri", - "Sat" - }; - return std::make_pair(nm, nm+sizeof(nm)/sizeof(nm[0])); -} - -inline -std::pair -month_names() -{ - static const std::string nm[] = - { - "January", - "February", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December", - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec" - }; - return std::make_pair(nm, nm+sizeof(nm)/sizeof(nm[0])); -} - -inline -std::pair -ampm_names() -{ - static const std::string nm[] = - { - "AM", - "PM" - }; - return std::make_pair(nm, nm+sizeof(nm)/sizeof(nm[0])); -} - -template -FwdIter -scan_keyword(std::basic_istream& is, FwdIter kb, FwdIter ke) -{ - using namespace std; - size_t nkw = static_cast(std::distance(kb, ke)); - const unsigned char doesnt_match = '\0'; - const unsigned char might_match = '\1'; - const unsigned char does_match = '\2'; - unsigned char statbuf[100]; - unsigned char* status = statbuf; - unique_ptr stat_hold(0, free); - if (nkw > sizeof(statbuf)) - { - status = (unsigned char*)malloc(nkw); - if (status == nullptr) -# ifdef USE_IOT - return FwdIter(); -# else - throw bad_alloc(); -# endif - stat_hold.reset(status); - } - size_t n_might_match = nkw; // At this point, any keyword might match - size_t n_does_match = 0; // but none of them definitely do - // Initialize all statuses to might_match, except for "" keywords are does_match - unsigned char* st = status; - for (auto ky = kb; ky != ke; ++ky, ++st) - { - if (!ky->empty()) - *st = might_match; - else - { - *st = does_match; - --n_might_match; - ++n_does_match; - } - } - // While there might be a match, test keywords against the next CharT - for (size_t indx = 0; is && n_might_match > 0; ++indx) - { - // Peek at the next CharT but don't consume it - auto ic = is.peek(); - if (ic == EOF) - { - is.setstate(ios::eofbit); - break; - } - auto c = static_cast(toupper(ic)); - bool consume = false; - // For each keyword which might match, see if the indx character is c - // If a match if found, consume c - // If a match is found, and that is the last character in the keyword, - // then that keyword matches. - // If the keyword doesn't match this character, then change the keyword - // to doesn't match - st = status; - for (auto ky = kb; ky != ke; ++ky, ++st) - { - if (*st == might_match) - { - if (c == static_cast(toupper((*ky)[indx]))) - { - consume = true; - if (ky->size() == indx+1) - { - *st = does_match; - --n_might_match; - ++n_does_match; - } - } - else - { - *st = doesnt_match; - --n_might_match; - } - } - } - // consume if we matched a character - if (consume) - { - (void)is.get(); - // If we consumed a character and there might be a matched keyword that - // was marked matched on a previous iteration, then such keywords - // are now marked as not matching. - if (n_might_match + n_does_match > 1) - { - st = status; - for (auto ky = kb; ky != ke; ++ky, ++st) - { - if (*st == does_match && ky->size() != indx+1) - { - *st = doesnt_match; - --n_does_match; - } - } - } - } - } - // We've exited the loop because we hit eof and/or we have no more "might matches". - // Return the first matching result - for (st = status; kb != ke; ++kb, ++st) - if (*st == does_match) - break; - if (kb == ke) - is.setstate(ios_base::failbit); - return kb; -} - -} // namespace detail - -#endif // ONLY_C_LOCALE - -template -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, - const fields& fds, const std::string* abbrev, - const std::chrono::seconds* offset_sec) -{ - using namespace std; - using namespace std::chrono; - using namespace detail; - date::detail::save_ostream ss(os); - os.fill(' '); - os.flags(std::ios::skipws | std::ios::dec); - os.width(0); - tm tm{}; - bool insert_negative = fds.has_tod && fds.tod.to_duration() < Duration::zero(); -#if !ONLY_C_LOCALE - auto& facet = use_facet>(os.getloc()); -#endif - const CharT* command = nullptr; - CharT modified = CharT{}; - for (; *fmt; ++fmt) - { - switch (*fmt) - { - case 'a': - case 'A': - if (command) - { - if (modified == CharT{}) - { - tm.tm_wday = static_cast(extract_weekday(os, fds)); - if (os.fail()) - return os; -#if !ONLY_C_LOCALE - const CharT f[] = {'%', *fmt}; - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); -#else // ONLY_C_LOCALE - os << weekday_names().first[tm.tm_wday+7*(*fmt == 'a')]; -#endif // ONLY_C_LOCALE - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'b': - case 'B': - case 'h': - if (command) - { - if (modified == CharT{}) - { - tm.tm_mon = static_cast(extract_month(os, fds)) - 1; -#if !ONLY_C_LOCALE - const CharT f[] = {'%', *fmt}; - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); -#else // ONLY_C_LOCALE - os << month_names().first[tm.tm_mon+12*(*fmt != 'B')]; -#endif // ONLY_C_LOCALE - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'c': - case 'x': - if (command) - { - if (modified == CharT{'O'}) - os << CharT{'%'} << modified << *fmt; - else - { - if (!fds.ymd.ok()) - os.setstate(std::ios::failbit); - if (*fmt == 'c' && !fds.has_tod) - os.setstate(std::ios::failbit); -#if !ONLY_C_LOCALE - tm = std::tm{}; - auto const& ymd = fds.ymd; - auto ld = local_days(ymd); - if (*fmt == 'c') - { - tm.tm_sec = static_cast(fds.tod.seconds().count()); - tm.tm_min = static_cast(fds.tod.minutes().count()); - tm.tm_hour = static_cast(fds.tod.hours().count()); - } - tm.tm_mday = static_cast(static_cast(ymd.day())); - tm.tm_mon = static_cast(extract_month(os, fds) - 1); - tm.tm_year = static_cast(ymd.year()) - 1900; - tm.tm_wday = static_cast(extract_weekday(os, fds)); - if (os.fail()) - return os; - tm.tm_yday = static_cast((ld - local_days(ymd.year()/1/1)).count()); - CharT f[3] = {'%'}; - auto fe = begin(f) + 1; - if (modified == CharT{'E'}) - *fe++ = modified; - *fe++ = *fmt; - facet.put(os, os, os.fill(), &tm, begin(f), fe); -#else // ONLY_C_LOCALE - if (*fmt == 'c') - { - auto wd = static_cast(extract_weekday(os, fds)); - os << weekday_names().first[static_cast(wd)+7] - << ' '; - os << month_names().first[extract_month(os, fds)-1+12] << ' '; - auto d = static_cast(static_cast(fds.ymd.day())); - if (d < 10) - os << ' '; - os << d << ' ' - << make_time(duration_cast(fds.tod.to_duration())) - << ' ' << fds.ymd.year(); - - } - else // *fmt == 'x' - { - auto const& ymd = fds.ymd; - save_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << static_cast(ymd.month()) << CharT{'/'}; - os.width(2); - os << static_cast(ymd.day()) << CharT{'/'}; - os.width(2); - os << static_cast(ymd.year()) % 100; - } -#endif // ONLY_C_LOCALE - } - command = nullptr; - modified = CharT{}; - } - else - os << *fmt; - break; - case 'C': - if (command) - { - if (modified == CharT{'O'}) - os << CharT{'%'} << modified << *fmt; - else - { - if (!fds.ymd.year().ok()) - os.setstate(std::ios::failbit); - auto y = static_cast(fds.ymd.year()); -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - save_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - if (y >= 0) - { - os.width(2); - os << y/100; - } - else - { - os << CharT{'-'}; - os.width(2); - os << -(y-99)/100; - } - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'E'}) - { - tm.tm_year = y - 1900; - CharT f[3] = {'%', 'E', 'C'}; - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } -#endif - } - command = nullptr; - modified = CharT{}; - } - else - os << *fmt; - break; - case 'd': - case 'e': - if (command) - { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else - { - if (!fds.ymd.day().ok()) - os.setstate(std::ios::failbit); - auto d = static_cast(static_cast(fds.ymd.day())); -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - save_ostream _(os); - if (*fmt == CharT{'d'}) - os.fill('0'); - else - os.fill(' '); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << d; - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - tm.tm_mday = d; - CharT f[3] = {'%', 'O', *fmt}; - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } -#endif - } - command = nullptr; - modified = CharT{}; - } - else - os << *fmt; - break; - case 'D': - if (command) - { - if (modified == CharT{}) - { - if (!fds.ymd.ok()) - os.setstate(std::ios::failbit); - auto const& ymd = fds.ymd; - save_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << static_cast(ymd.month()) << CharT{'/'}; - os.width(2); - os << static_cast(ymd.day()) << CharT{'/'}; - os.width(2); - os << static_cast(ymd.year()) % 100; - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'F': - if (command) - { - if (modified == CharT{}) - { - if (!fds.ymd.ok()) - os.setstate(std::ios::failbit); - auto const& ymd = fds.ymd; - save_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(4); - os << static_cast(ymd.year()) << CharT{'-'}; - os.width(2); - os << static_cast(ymd.month()) << CharT{'-'}; - os.width(2); - os << static_cast(ymd.day()); - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'g': - case 'G': - if (command) - { - if (modified == CharT{}) - { - if (!fds.ymd.ok()) - os.setstate(std::ios::failbit); - auto ld = local_days(fds.ymd); - auto y = year_month_day{ld + days{3}}.year(); - auto start = local_days((y-years{1})/December/Thursday[last]) + - (Monday-Thursday); - if (ld < start) - --y; - if (*fmt == CharT{'G'}) - os << y; - else - { - save_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << std::abs(static_cast(y)) % 100; - } - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'H': - case 'I': - if (command) - { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else - { - if (!fds.has_tod) - os.setstate(std::ios::failbit); - if (insert_negative) - { - os << '-'; - insert_negative = false; - } - auto hms = fds.tod; -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - if (*fmt == CharT{'I'}) - hms.make12(); - if (hms.hours() < hours{10}) - os << CharT{'0'}; - os << hms.hours().count(); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_hour = static_cast(hms.hours().count()); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'j': - if (command) - { - if (modified == CharT{}) - { - if (fds.ymd.ok() || fds.has_tod) - { - days doy; - if (fds.ymd.ok()) - { - auto ld = local_days(fds.ymd); - auto y = fds.ymd.year(); - doy = ld - local_days(y/January/1) + days{1}; - } - else - { - doy = duration_cast(fds.tod.to_duration()); - } - save_ostream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(3); - os << doy.count(); - } - else - { - os.setstate(std::ios::failbit); - } - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'm': - if (command) - { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else - { - if (!fds.ymd.month().ok()) - os.setstate(std::ios::failbit); - auto m = static_cast(fds.ymd.month()); -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - if (m < 10) - os << CharT{'0'}; - os << m; - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_mon = static_cast(m-1); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'M': - if (command) - { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else - { - if (!fds.has_tod) - os.setstate(std::ios::failbit); - if (insert_negative) - { - os << '-'; - insert_negative = false; - } -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - if (fds.tod.minutes() < minutes{10}) - os << CharT{'0'}; - os << fds.tod.minutes().count(); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_min = static_cast(fds.tod.minutes().count()); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'n': - if (command) - { - if (modified == CharT{}) - os << CharT{'\n'}; - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'p': - if (command) - { - if (modified == CharT{}) - { - if (!fds.has_tod) - os.setstate(std::ios::failbit); -#if !ONLY_C_LOCALE - const CharT f[] = {'%', *fmt}; - tm.tm_hour = static_cast(fds.tod.hours().count()); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); -#else - if (fds.tod.hours() < hours{12}) - os << ampm_names().first[0]; - else - os << ampm_names().first[1]; -#endif - } - else - { - os << CharT{'%'} << modified << *fmt; - } - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'r': - if (command) - { - if (modified == CharT{}) - { - if (!fds.has_tod) - os.setstate(std::ios::failbit); -#if !ONLY_C_LOCALE - const CharT f[] = {'%', *fmt}; - tm.tm_hour = static_cast(fds.tod.hours().count()); - tm.tm_min = static_cast(fds.tod.minutes().count()); - tm.tm_sec = static_cast(fds.tod.seconds().count()); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); -#else - time_of_day tod(duration_cast(fds.tod.to_duration())); - tod.make12(); - save_ostream _(os); - os.fill('0'); - os.width(2); - os << tod.hours().count() << CharT{':'}; - os.width(2); - os << tod.minutes().count() << CharT{':'}; - os.width(2); - os << tod.seconds().count() << CharT{' '}; - tod.make24(); - if (tod.hours() < hours{12}) - os << ampm_names().first[0]; - else - os << ampm_names().first[1]; -#endif - } - else - { - os << CharT{'%'} << modified << *fmt; - } - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'R': - if (command) - { - if (modified == CharT{}) - { - if (!fds.has_tod) - os.setstate(std::ios::failbit); - if (fds.tod.hours() < hours{10}) - os << CharT{'0'}; - os << fds.tod.hours().count() << CharT{':'}; - if (fds.tod.minutes() < minutes{10}) - os << CharT{'0'}; - os << fds.tod.minutes().count(); - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'S': - if (command) - { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else - { - if (!fds.has_tod) - os.setstate(std::ios::failbit); - if (insert_negative) - { - os << '-'; - insert_negative = false; - } -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - os << fds.tod.s_; - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_sec = static_cast(fds.tod.s_.seconds().count()); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 't': - if (command) - { - if (modified == CharT{}) - os << CharT{'\t'}; - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'T': - if (command) - { - if (modified == CharT{}) - { - if (!fds.has_tod) - os.setstate(std::ios::failbit); - os << fds.tod; - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'u': - if (command) - { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else - { - auto wd = extract_weekday(os, fds); -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - os << (wd != 0 ? wd : 7u); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_wday = static_cast(wd); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'U': - if (command) - { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else - { - auto const& ymd = fds.ymd; - if (!ymd.ok()) - os.setstate(std::ios::failbit); - auto ld = local_days(ymd); -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - auto st = local_days(Sunday[1]/January/ymd.year()); - if (ld < st) - os << CharT{'0'} << CharT{'0'}; - else - { - auto wn = duration_cast(ld - st).count() + 1; - if (wn < 10) - os << CharT{'0'}; - os << wn; - } - } - #if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_year = static_cast(ymd.year()) - 1900; - tm.tm_wday = static_cast(extract_weekday(os, fds)); - if (os.fail()) - return os; - tm.tm_yday = static_cast((ld - local_days(ymd.year()/1/1)).count()); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'V': - if (command) - { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else - { - if (!fds.ymd.ok()) - os.setstate(std::ios::failbit); - auto ld = local_days(fds.ymd); -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - auto y = year_month_day{ld + days{3}}.year(); - auto st = local_days((y-years{1})/12/Thursday[last]) + - (Monday-Thursday); - if (ld < st) - { - --y; - st = local_days((y - years{1})/12/Thursday[last]) + - (Monday-Thursday); - } - auto wn = duration_cast(ld - st).count() + 1; - if (wn < 10) - os << CharT{'0'}; - os << wn; - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - auto const& ymd = fds.ymd; - tm.tm_year = static_cast(ymd.year()) - 1900; - tm.tm_wday = static_cast(extract_weekday(os, fds)); - if (os.fail()) - return os; - tm.tm_yday = static_cast((ld - local_days(ymd.year()/1/1)).count()); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'w': - if (command) - { - auto wd = extract_weekday(os, fds); - if (os.fail()) - return os; -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#else - if (modified != CharT{'E'}) -#endif - { - os << wd; - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_wday = static_cast(wd); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } -#endif - else - { - os << CharT{'%'} << modified << *fmt; - } - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'W': - if (command) - { - if (modified == CharT{'E'}) - os << CharT{'%'} << modified << *fmt; - else - { - auto const& ymd = fds.ymd; - if (!ymd.ok()) - os.setstate(std::ios::failbit); - auto ld = local_days(ymd); -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - auto st = local_days(Monday[1]/January/ymd.year()); - if (ld < st) - os << CharT{'0'} << CharT{'0'}; - else - { - auto wn = duration_cast(ld - st).count() + 1; - if (wn < 10) - os << CharT{'0'}; - os << wn; - } - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_year = static_cast(ymd.year()) - 1900; - tm.tm_wday = static_cast(extract_weekday(os, fds)); - if (os.fail()) - return os; - tm.tm_yday = static_cast((ld - local_days(ymd.year()/1/1)).count()); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'X': - if (command) - { - if (modified == CharT{'O'}) - os << CharT{'%'} << modified << *fmt; - else - { - if (!fds.has_tod) - os.setstate(std::ios::failbit); -#if !ONLY_C_LOCALE - tm = std::tm{}; - tm.tm_sec = static_cast(fds.tod.seconds().count()); - tm.tm_min = static_cast(fds.tod.minutes().count()); - tm.tm_hour = static_cast(fds.tod.hours().count()); - CharT f[3] = {'%'}; - auto fe = begin(f) + 1; - if (modified == CharT{'E'}) - *fe++ = modified; - *fe++ = *fmt; - facet.put(os, os, os.fill(), &tm, begin(f), fe); -#else - os << fds.tod; -#endif - } - command = nullptr; - modified = CharT{}; - } - else - os << *fmt; - break; - case 'y': - if (command) - { - if (!fds.ymd.year().ok()) - os.setstate(std::ios::failbit); - auto y = static_cast(fds.ymd.year()); -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - y = std::abs(y) % 100; - if (y < 10) - os << CharT{'0'}; - os << y; -#if !ONLY_C_LOCALE - } - else - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_year = y - 1900; - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } -#endif - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'Y': - if (command) - { - if (modified == CharT{'O'}) - os << CharT{'%'} << modified << *fmt; - else - { - if (!fds.ymd.year().ok()) - os.setstate(std::ios::failbit); - auto y = fds.ymd.year(); -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - os << y; - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'E'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_year = static_cast(y) - 1900; - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } -#endif - } - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'z': - if (command) - { - if (offset_sec == nullptr) - { - // Can not format %z with unknown offset - os.setstate(ios::failbit); - return os; - } - auto m = duration_cast(*offset_sec); - auto neg = m < minutes{0}; - m = date::abs(m); - auto h = duration_cast(m); - m -= h; - if (neg) - os << CharT{'-'}; - else - os << CharT{'+'}; - if (h < hours{10}) - os << CharT{'0'}; - os << h.count(); - if (modified != CharT{}) - os << CharT{':'}; - if (m < minutes{10}) - os << CharT{'0'}; - os << m.count(); - command = nullptr; - modified = CharT{}; - } - else - os << *fmt; - break; - case 'Z': - if (command) - { - if (modified == CharT{}) - { - if (abbrev == nullptr) - { - // Can not format %Z with unknown time_zone - os.setstate(ios::failbit); - return os; - } - for (auto c : *abbrev) - os << CharT(c); - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'E': - case 'O': - if (command) - { - if (modified == CharT{}) - { - modified = *fmt; - } - else - { - os << CharT{'%'} << modified << *fmt; - command = nullptr; - modified = CharT{}; - } - } - else - os << *fmt; - break; - case '%': - if (command) - { - if (modified == CharT{}) - { - os << CharT{'%'}; - command = nullptr; - } - else - { - os << CharT{'%'} << modified << CharT{'%'}; - command = nullptr; - modified = CharT{}; - } - } - else - command = fmt; - break; - default: - if (command) - { - os << CharT{'%'}; - command = nullptr; - } - if (modified != CharT{}) - { - os << modified; - modified = CharT{}; - } - os << *fmt; - break; - } - } - if (command) - os << CharT{'%'}; - if (modified != CharT{}) - os << modified; - return os; -} - -template -inline -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, const year& y) -{ - using CT = std::chrono::seconds; - fields fds{y/0/0}; - return to_stream(os, fmt, fds); -} - -template -inline -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, const month& m) -{ - using CT = std::chrono::seconds; - fields fds{m/0/nanyear}; - return to_stream(os, fmt, fds); -} - -template -inline -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, const day& d) -{ - using CT = std::chrono::seconds; - fields fds{d/0/nanyear}; - return to_stream(os, fmt, fds); -} - -template -inline -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, const weekday& wd) -{ - using CT = std::chrono::seconds; - fields fds{wd}; - return to_stream(os, fmt, fds); -} - -template -inline -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, const year_month& ym) -{ - using CT = std::chrono::seconds; - fields fds{ym/0}; - return to_stream(os, fmt, fds); -} - -template -inline -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, const month_day& md) -{ - using CT = std::chrono::seconds; - fields fds{md/nanyear}; - return to_stream(os, fmt, fds); -} - -template -inline -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, - const year_month_day& ymd) -{ - using CT = std::chrono::seconds; - fields fds{ymd}; - return to_stream(os, fmt, fds); -} - -template -inline -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, - const std::chrono::duration& d) -{ - using Duration = std::chrono::duration; - using CT = typename std::common_type::type; - fields fds{time_of_day{d}}; - return to_stream(os, fmt, fds); -} - -template -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, - const local_time& tp, const std::string* abbrev = nullptr, - const std::chrono::seconds* offset_sec = nullptr) -{ - using CT = typename std::common_type::type; - auto ld = floor(tp); - fields fds{year_month_day{ld}, time_of_day{tp-local_seconds{ld}}}; - return to_stream(os, fmt, fds, abbrev, offset_sec); -} - -template -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, - const sys_time& tp) -{ - using namespace std::chrono; - using CT = typename std::common_type::type; - const std::string abbrev("UTC"); - CONSTDATA seconds offset{0}; - auto sd = floor(tp); - fields fds{year_month_day{sd}, time_of_day{tp-sys_seconds{sd}}}; - return to_stream(os, fmt, fds, &abbrev, &offset); -} - -// format - -template -auto -format(const std::locale& loc, const CharT* fmt, const Streamable& tp) - -> decltype(to_stream(std::declval&>(), fmt, tp), - std::basic_string{}) -{ - std::basic_ostringstream os; - os.exceptions(std::ios::failbit | std::ios::badbit); - os.imbue(loc); - to_stream(os, fmt, tp); - return os.str(); -} - -template -auto -format(const CharT* fmt, const Streamable& tp) - -> decltype(to_stream(std::declval&>(), fmt, tp), - std::basic_string{}) -{ - std::basic_ostringstream os; - os.exceptions(std::ios::failbit | std::ios::badbit); - to_stream(os, fmt, tp); - return os.str(); -} - -template -auto -format(const std::locale& loc, const std::basic_string& fmt, - const Streamable& tp) - -> decltype(to_stream(std::declval&>(), fmt.c_str(), tp), - std::basic_string{}) -{ - std::basic_ostringstream os; - os.exceptions(std::ios::failbit | std::ios::badbit); - os.imbue(loc); - to_stream(os, fmt.c_str(), tp); - return os.str(); -} - -template -auto -format(const std::basic_string& fmt, const Streamable& tp) - -> decltype(to_stream(std::declval&>(), fmt.c_str(), tp), - std::basic_string{}) -{ - std::basic_ostringstream os; - os.exceptions(std::ios::failbit | std::ios::badbit); - to_stream(os, fmt.c_str(), tp); - return os.str(); -} - -// parse - -namespace detail -{ - -template -bool -read_char(std::basic_istream& is, CharT fmt, std::ios::iostate& err) -{ - auto ic = is.get(); - if (Traits::eq_int_type(ic, Traits::eof()) || - !Traits::eq(Traits::to_char_type(ic), fmt)) - { - err |= std::ios::failbit; - is.setstate(std::ios::failbit); - return false; - } - return true; -} - -template -unsigned -read_unsigned(std::basic_istream& is, unsigned m = 1, unsigned M = 10) -{ - unsigned x = 0; - unsigned count = 0; - while (true) - { - auto ic = is.peek(); - if (Traits::eq_int_type(ic, Traits::eof())) - break; - auto c = static_cast(Traits::to_char_type(ic)); - if (!('0' <= c && c <= '9')) - break; - (void)is.get(); - ++count; - x = 10*x + static_cast(c - '0'); - if (count == M) - break; - } - if (count < m) - is.setstate(std::ios::failbit); - return x; -} - -template -int -read_signed(std::basic_istream& is, unsigned m = 1, unsigned M = 10) -{ - auto ic = is.peek(); - if (!Traits::eq_int_type(ic, Traits::eof())) - { - auto c = static_cast(Traits::to_char_type(ic)); - if (('0' <= c && c <= '9') || c == '-' || c == '+') - { - if (c == '-' || c == '+') - (void)is.get(); - auto x = static_cast(read_unsigned(is, std::max(m, 1u), M)); - if (!is.fail()) - { - if (c == '-') - x = -x; - return x; - } - } - } - if (m > 0) - is.setstate(std::ios::failbit); - return 0; -} - -template -long double -read_long_double(std::basic_istream& is, unsigned m = 1, unsigned M = 10) -{ - using namespace std; - unsigned count = 0; - auto decimal_point = Traits::to_int_type( - use_facet>(is.getloc()).decimal_point()); - std::string buf; - while (true) - { - auto ic = is.peek(); - if (Traits::eq_int_type(ic, Traits::eof())) - break; - if (Traits::eq_int_type(ic, decimal_point)) - { - buf += '.'; - decimal_point = Traits::eof(); - is.get(); - } - else - { - auto c = static_cast(Traits::to_char_type(ic)); - if (!('0' <= c && c <= '9')) - break; - buf += c; - (void)is.get(); - } - if (++count == M) - break; - } - if (count < m) - { - is.setstate(std::ios::failbit); - return 0; - } - return std::stold(buf); -} - -struct rs -{ - int& i; - unsigned m; - unsigned M; -}; - -struct ru -{ - int& i; - unsigned m; - unsigned M; -}; - -struct rld -{ - long double& i; - unsigned m; - unsigned M; -}; - -template -void -read(std::basic_istream&) -{ -} - -template -void -read(std::basic_istream& is, CharT a0, Args&& ...args); - -template -void -read(std::basic_istream& is, rs a0, Args&& ...args); - -template -void -read(std::basic_istream& is, ru a0, Args&& ...args); - -template -void -read(std::basic_istream& is, int a0, Args&& ...args); - -template -void -read(std::basic_istream& is, rld a0, Args&& ...args); - -template -void -read(std::basic_istream& is, CharT a0, Args&& ...args) -{ - // No-op if a0 == CharT{} - if (a0 != CharT{}) - { - auto ic = is.peek(); - if (Traits::eq_int_type(ic, Traits::eof())) - { - is.setstate(std::ios::failbit | std::ios::eofbit); - return; - } - if (!Traits::eq(Traits::to_char_type(ic), a0)) - { - is.setstate(std::ios::failbit); - return; - } - (void)is.get(); - } - read(is, std::forward(args)...); -} - -template -void -read(std::basic_istream& is, rs a0, Args&& ...args) -{ - auto x = read_signed(is, a0.m, a0.M); - if (is.fail()) - return; - a0.i = x; - read(is, std::forward(args)...); -} - -template -void -read(std::basic_istream& is, ru a0, Args&& ...args) -{ - auto x = read_unsigned(is, a0.m, a0.M); - if (is.fail()) - return; - a0.i = static_cast(x); - read(is, std::forward(args)...); -} - -template -void -read(std::basic_istream& is, int a0, Args&& ...args) -{ - if (a0 != -1) - { - auto u = static_cast(a0); - CharT buf[std::numeric_limits::digits10+2] = {}; - auto e = buf; - do - { - *e++ = CharT(u % 10) + CharT{'0'}; - u /= 10; - } while (u > 0); - std::reverse(buf, e); - for (auto p = buf; p != e && is.rdstate() == std::ios::goodbit; ++p) - read(is, *p); - } - if (is.rdstate() == std::ios::goodbit) - read(is, std::forward(args)...); -} - -template -void -read(std::basic_istream& is, rld a0, Args&& ...args) -{ - auto x = read_long_double(is, a0.m, a0.M); - if (is.fail()) - return; - a0.i = x; - read(is, std::forward(args)...); -} - -template -inline -void -checked_set(T& value, T from, T not_a_value, std::basic_ios& is) -{ - if (!is.fail()) - { - if (value == not_a_value) - value = std::move(from); - else if (value != from) - is.setstate(std::ios::failbit); - } -} - -} // namespace detail; - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, - fields& fds, std::basic_string* abbrev, - std::chrono::minutes* offset) -{ - using namespace std; - using namespace std::chrono; - typename basic_istream::sentry ok{is, true}; - if (ok) - { - date::detail::save_istream ss(is); - is.fill(' '); - is.flags(std::ios::skipws | std::ios::dec); - is.width(0); -#if !ONLY_C_LOCALE - auto& f = use_facet>(is.getloc()); - std::tm tm{}; -#endif - const CharT* command = nullptr; - auto modified = CharT{}; - auto width = -1; - - CONSTDATA int not_a_year = numeric_limits::min(); - CONSTDATA int not_a_2digit_year = 100; - CONSTDATA int not_a_century = not_a_year / 100; - CONSTDATA int not_a_month = 0; - CONSTDATA int not_a_day = 0; - CONSTDATA int not_a_hour = numeric_limits::min(); - CONSTDATA int not_a_hour_12_value = 0; - CONSTDATA int not_a_minute = not_a_hour; - CONSTDATA Duration not_a_second = Duration::min(); - CONSTDATA int not_a_doy = -1; - CONSTDATA int not_a_weekday = 8; - CONSTDATA int not_a_week_num = 100; - CONSTDATA int not_a_ampm = -1; - CONSTDATA minutes not_a_offset = minutes::min(); - - int Y = not_a_year; // c, F, Y * - int y = not_a_2digit_year; // D, x, y * - int g = not_a_2digit_year; // g * - int G = not_a_year; // G * - int C = not_a_century; // C * - int m = not_a_month; // b, B, h, m, c, D, F, x * - int d = not_a_day; // c, d, D, e, F, x * - int j = not_a_doy; // j * - int wd = not_a_weekday; // a, A, u, w * - int H = not_a_hour; // c, H, R, T, X * - int I = not_a_hour_12_value; // I, r * - int p = not_a_ampm; // p, r * - int M = not_a_minute; // c, M, r, R, T, X * - Duration s = not_a_second; // c, r, S, T, X * - int U = not_a_week_num; // U * - int V = not_a_week_num; // V * - int W = not_a_week_num; // W * - std::basic_string temp_abbrev; // Z * - minutes temp_offset = not_a_offset; // z * - - using detail::read; - using detail::rs; - using detail::ru; - using detail::rld; - using detail::checked_set; - for (; *fmt && is.rdstate() == std::ios::goodbit; ++fmt) - { - switch (*fmt) - { - case 'a': - case 'A': - case 'u': - case 'w': // wd: a, A, u, w - if (command) - { - int trial_wd = not_a_weekday; - if (*fmt == 'a' || *fmt == 'A') - { - if (modified == CharT{}) - { -#if !ONLY_C_LOCALE - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - is.setstate(err); - if (!is.fail()) - trial_wd = tm.tm_wday; -#else - auto nm = detail::weekday_names(); - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - if (!is.fail()) - trial_wd = i % 7; -#endif - } - else - read(is, CharT{'%'}, width, modified, *fmt); - } - else // *fmt == 'u' || *fmt == 'w' - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#else - if (modified != CharT{'E'}) -#endif - { - read(is, ru{trial_wd, 1, width == -1 ? - 1u : static_cast(width)}); - if (!is.fail()) - { - if (*fmt == 'u') - { - if (!(1 <= trial_wd && trial_wd <= 7)) - { - trial_wd = not_a_weekday; - is.setstate(ios_base::failbit); - } - else if (trial_wd == 7) - trial_wd = 0; - } - else // *fmt == 'w' - { - if (!(0 <= trial_wd && trial_wd <= 6)) - { - trial_wd = not_a_weekday; - is.setstate(ios_base::failbit); - } - } - } - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - is.setstate(err); - if (!is.fail()) - trial_wd = tm.tm_wday; - } -#endif - else - read(is, CharT{'%'}, width, modified, *fmt); - } - if (trial_wd != not_a_weekday) - checked_set(wd, trial_wd, not_a_weekday, is); - } - else // !command - read(is, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - break; - case 'b': - case 'B': - case 'h': - if (command) - { - if (modified == CharT{}) - { - int ttm = not_a_month; -#if !ONLY_C_LOCALE - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - ttm = tm.tm_mon + 1; - is.setstate(err); -#else - auto nm = detail::month_names(); - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - if (!is.fail()) - ttm = i % 12 + 1; -#endif - checked_set(m, ttm, not_a_month, is); - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'c': - if (command) - { - if (modified != CharT{'O'}) - { -#if !ONLY_C_LOCALE - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - { - checked_set(Y, tm.tm_year + 1900, not_a_year, is); - checked_set(m, tm.tm_mon + 1, not_a_month, is); - checked_set(d, tm.tm_mday, not_a_day, is); - checked_set(H, tm.tm_hour, not_a_hour, is); - checked_set(M, tm.tm_min, not_a_minute, is); - checked_set(s, duration_cast(seconds{tm.tm_sec}), - not_a_second, is); - } - is.setstate(err); -#else - // "%a %b %e %T %Y" - auto nm = detail::weekday_names(); - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - checked_set(wd, static_cast(i % 7), not_a_weekday, is); - ws(is); - nm = detail::month_names(); - i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - checked_set(m, static_cast(i % 12 + 1), not_a_month, is); - ws(is); - int td = not_a_day; - read(is, rs{td, 1, 2}); - checked_set(d, td, not_a_day, is); - ws(is); - using dfs = detail::decimal_format_seconds; - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; - int tH; - int tM; - long double S; - read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2}, - CharT{':'}, rld{S, 1, w}); - checked_set(H, tH, not_a_hour, is); - checked_set(M, tM, not_a_minute, is); - checked_set(s, round(duration{S}), - not_a_second, is); - ws(is); - int tY = not_a_year; - read(is, rs{tY, 1, 4u}); - checked_set(Y, tY, not_a_year, is); -#endif - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'x': - if (command) - { - if (modified != CharT{'O'}) - { -#if !ONLY_C_LOCALE - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - { - checked_set(Y, tm.tm_year + 1900, not_a_year, is); - checked_set(m, tm.tm_mon + 1, not_a_month, is); - checked_set(d, tm.tm_mday, not_a_day, is); - } - is.setstate(err); -#else - // "%m/%d/%y" - int ty = not_a_2digit_year; - int tm = not_a_month; - int td = not_a_day; - read(is, ru{tm, 1, 2}, CharT{'/'}, ru{td, 1, 2}, CharT{'/'}, - rs{ty, 1, 2}); - checked_set(y, ty, not_a_2digit_year, is); - checked_set(m, tm, not_a_month, is); - checked_set(d, td, not_a_day, is); -#endif - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'X': - if (command) - { - if (modified != CharT{'O'}) - { -#if !ONLY_C_LOCALE - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - { - checked_set(H, tm.tm_hour, not_a_hour, is); - checked_set(M, tm.tm_min, not_a_minute, is); - checked_set(s, duration_cast(seconds{tm.tm_sec}), - not_a_second, is); - } - is.setstate(err); -#else - // "%T" - using dfs = detail::decimal_format_seconds; - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; - int tH = not_a_hour; - int tM = not_a_minute; - long double S; - read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2}, - CharT{':'}, rld{S, 1, w}); - checked_set(H, tH, not_a_hour, is); - checked_set(M, tM, not_a_minute, is); - checked_set(s, round(duration{S}), - not_a_second, is); -#endif - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'C': - if (command) - { - int tC = not_a_century; -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - read(is, rs{tC, 1, width == -1 ? 2u : static_cast(width)}); -#if !ONLY_C_LOCALE - } - else - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - { - auto tY = tm.tm_year + 1900; - tC = (tY >= 0 ? tY : tY-99) / 100; - } - is.setstate(err); - } -#endif - checked_set(C, tC, not_a_century, is); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'D': - if (command) - { - if (modified == CharT{}) - { - int tn = not_a_month; - int td = not_a_day; - int ty = not_a_2digit_year; - read(is, ru{tn, 1, 2}, CharT{'\0'}, CharT{'/'}, CharT{'\0'}, - ru{td, 1, 2}, CharT{'\0'}, CharT{'/'}, CharT{'\0'}, - rs{ty, 1, 2}); - checked_set(y, ty, not_a_2digit_year, is); - checked_set(m, tn, not_a_month, is); - checked_set(d, td, not_a_day, is); - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'F': - if (command) - { - if (modified == CharT{}) - { - int tY = not_a_year; - int tn = not_a_month; - int td = not_a_day; - read(is, rs{tY, 1, width == -1 ? 4u : static_cast(width)}, - CharT{'-'}, ru{tn, 1, 2}, CharT{'-'}, ru{td, 1, 2}); - checked_set(Y, tY, not_a_year, is); - checked_set(m, tn, not_a_month, is); - checked_set(d, td, not_a_day, is); - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'd': - case 'e': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#else - if (modified != CharT{'E'}) -#endif - { - int td = not_a_day; - read(is, rs{td, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(d, td, not_a_day, is); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - command = nullptr; - width = -1; - modified = CharT{}; - if ((err & ios::failbit) == 0) - checked_set(d, tm.tm_mday, not_a_day, is); - is.setstate(err); - } -#endif - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'H': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#else - if (modified != CharT{'E'}) -#endif - { - int tH = not_a_hour; - read(is, ru{tH, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(H, tH, not_a_hour, is); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - checked_set(H, tm.tm_hour, not_a_hour, is); - is.setstate(err); - } -#endif - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'I': - if (command) - { - if (modified == CharT{}) - { - int tI = not_a_hour_12_value; - // reads in an hour into I, but most be in [1, 12] - read(is, rs{tI, 1, width == -1 ? 2u : static_cast(width)}); - if (!(1 <= tI && tI <= 12)) - is.setstate(ios::failbit); - checked_set(I, tI, not_a_hour_12_value, is); - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'j': - if (command) - { - if (modified == CharT{}) - { - int tj = not_a_doy; - read(is, ru{tj, 1, width == -1 ? 3u : static_cast(width)}); - checked_set(j, tj, not_a_doy, is); - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'M': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#else - if (modified != CharT{'E'}) -#endif - { - int tM = not_a_minute; - read(is, ru{tM, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(M, tM, not_a_minute, is); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - checked_set(M, tm.tm_min, not_a_minute, is); - is.setstate(err); - } -#endif - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'm': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#else - if (modified != CharT{'E'}) -#endif - { - int tn = not_a_month; - read(is, rs{tn, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(m, tn, not_a_month, is); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - checked_set(m, tm.tm_mon + 1, not_a_month, is); - is.setstate(err); - } -#endif - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'n': - case 't': - if (command) - { - if (modified == CharT{}) - { - // %n matches a single white space character - // %t matches 0 or 1 white space characters - auto ic = is.peek(); - if (Traits::eq_int_type(ic, Traits::eof())) - { - ios_base::iostate err = ios_base::eofbit; - if (*fmt == 'n') - err |= ios_base::failbit; - is.setstate(err); - break; - } - if (isspace(ic)) - { - (void)is.get(); - } - else if (*fmt == 'n') - is.setstate(ios_base::failbit); - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'p': - if (command) - { - if (modified == CharT{}) - { - int tp = not_a_ampm; -#if !ONLY_C_LOCALE - tm = std::tm{}; - tm.tm_hour = 1; - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - is.setstate(err); - if (tm.tm_hour == 1) - tp = 0; - else if (tm.tm_hour == 13) - tp = 1; - else - is.setstate(err); -#else - auto nm = detail::ampm_names(); - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - tp = i; -#endif - checked_set(p, tp, not_a_ampm, is); - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - - break; - case 'r': - if (command) - { - if (modified == CharT{}) - { -#if !ONLY_C_LOCALE - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - { - checked_set(H, tm.tm_hour, not_a_hour, is); - checked_set(M, tm.tm_min, not_a_hour, is); - checked_set(s, duration_cast(seconds{tm.tm_sec}), - not_a_second, is); - } - is.setstate(err); -#else - // "%I:%M:%S %p" - using dfs = detail::decimal_format_seconds; - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; - long double S; - int tI = not_a_hour_12_value; - int tM = not_a_minute; - read(is, ru{tI, 1, 2}, CharT{':'}, ru{tM, 1, 2}, - CharT{':'}, rld{S, 1, w}); - checked_set(I, tI, not_a_hour_12_value, is); - checked_set(M, tM, not_a_minute, is); - checked_set(s, round(duration{S}), - not_a_second, is); - ws(is); - auto nm = detail::ampm_names(); - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - checked_set(p, static_cast(i), not_a_ampm, is); -#endif - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'R': - if (command) - { - if (modified == CharT{}) - { - int tH = not_a_hour; - int tM = not_a_minute; - read(is, ru{tH, 1, 2}, CharT{'\0'}, CharT{':'}, CharT{'\0'}, - ru{tM, 1, 2}, CharT{'\0'}); - checked_set(H, tH, not_a_hour, is); - checked_set(M, tM, not_a_minute, is); - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'S': - if (command) - { - #if !ONLY_C_LOCALE - if (modified == CharT{}) -#else - if (modified != CharT{'E'}) -#endif - { - using dfs = detail::decimal_format_seconds; - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; - long double S; - read(is, rld{S, 1, width == -1 ? w : static_cast(width)}); - checked_set(s, round(duration{S}), - not_a_second, is); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - checked_set(s, duration_cast(seconds{tm.tm_sec}), - not_a_second, is); - is.setstate(err); - } -#endif - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'T': - if (command) - { - if (modified == CharT{}) - { - using dfs = detail::decimal_format_seconds; - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; - int tH = not_a_hour; - int tM = not_a_minute; - long double S; - read(is, ru{tH, 1, 2}, CharT{':'}, ru{tM, 1, 2}, - CharT{':'}, rld{S, 1, w}); - checked_set(H, tH, not_a_hour, is); - checked_set(M, tM, not_a_minute, is); - checked_set(s, round(duration{S}), - not_a_second, is); - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'Y': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#else - if (modified != CharT{'O'}) -#endif - { - int tY = not_a_year; - read(is, rs{tY, 1, width == -1 ? 4u : static_cast(width)}); - checked_set(Y, tY, not_a_year, is); - } -#if !ONLY_C_LOCALE - else if (modified == CharT{'E'}) - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - checked_set(Y, tm.tm_year + 1900, not_a_year, is); - is.setstate(err); - } -#endif - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'y': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - { - int ty = not_a_2digit_year; - read(is, ru{ty, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(y, ty, not_a_2digit_year, is); - } -#if !ONLY_C_LOCALE - else - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - checked_set(Y, tm.tm_year + 1900, not_a_year, is); - is.setstate(err); - } -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'g': - if (command) - { - if (modified == CharT{}) - { - int tg = not_a_2digit_year; - read(is, ru{tg, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(g, tg, not_a_2digit_year, is); - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'G': - if (command) - { - if (modified == CharT{}) - { - int tG = not_a_year; - read(is, rs{tG, 1, width == -1 ? 4u : static_cast(width)}); - checked_set(G, tG, not_a_year, is); - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'U': - if (command) - { - if (modified == CharT{}) - { - int tU = not_a_week_num; - read(is, ru{tU, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(U, tU, not_a_week_num, is); - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'V': - if (command) - { - if (modified == CharT{}) - { - int tV = not_a_week_num; - read(is, ru{tV, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(V, tV, not_a_week_num, is); - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'W': - if (command) - { - if (modified == CharT{}) - { - int tW = not_a_week_num; - read(is, ru{tW, 1, width == -1 ? 2u : static_cast(width)}); - checked_set(W, tW, not_a_week_num, is); - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'E': - case 'O': - if (command) - { - if (modified == CharT{}) - { - modified = *fmt; - } - else - { - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - } - else - read(is, *fmt); - break; - case '%': - if (command) - { - if (modified == CharT{}) - read(is, *fmt); - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - command = fmt; - break; - case 'z': - if (command) - { - int tH, tM; - minutes toff = not_a_offset; - bool neg = false; - auto ic = is.peek(); - if (!Traits::eq_int_type(ic, Traits::eof())) - { - auto c = static_cast(Traits::to_char_type(ic)); - if (c == '-') - neg = true; - } - if (modified == CharT{}) - { - read(is, rs{tH, 2, 2}); - if (!is.fail()) - toff = hours{std::abs(tH)}; - if (is.good()) - { - ic = is.peek(); - if (!Traits::eq_int_type(ic, Traits::eof())) - { - auto c = static_cast(Traits::to_char_type(ic)); - if ('0' <= c && c <= '9') - { - read(is, ru{tM, 2, 2}); - if (!is.fail()) - toff += minutes{tM}; - } - } - } - } - else - { - read(is, rs{tH, 1, 2}); - if (!is.fail()) - toff = hours{std::abs(tH)}; - if (is.good()) - { - ic = is.peek(); - if (!Traits::eq_int_type(ic, Traits::eof())) - { - auto c = static_cast(Traits::to_char_type(ic)); - if (c == ':') - { - (void)is.get(); - read(is, ru{tM, 2, 2}); - if (!is.fail()) - toff += minutes{tM}; - } - } - } - } - if (neg) - toff = -toff; - checked_set(temp_offset, toff, not_a_offset, is); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'Z': - if (command) - { - if (modified == CharT{}) - { - std::basic_string buf; - while (is.rdstate() == std::ios::goodbit) - { - auto i = is.rdbuf()->sgetc(); - if (Traits::eq_int_type(i, Traits::eof())) - { - is.setstate(ios::eofbit); - break; - } - auto wc = Traits::to_char_type(i); - auto c = static_cast(wc); - // is c a valid time zone name or abbreviation character? - if (!(CharT{1} < wc && wc < CharT{127}) || !(isalnum(c) || - c == '_' || c == '/' || c == '-' || c == '+')) - break; - buf.push_back(c); - is.rdbuf()->sbumpc(); - } - if (buf.empty()) - is.setstate(ios::failbit); - checked_set(temp_abbrev, buf, {}, is); - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - default: - if (command) - { - if (width == -1 && modified == CharT{} && '0' <= *fmt && *fmt <= '9') - { - width = static_cast(*fmt) - '0'; - while ('0' <= fmt[1] && fmt[1] <= '9') - width = 10*width + static_cast(*++fmt) - '0'; - } - else - { - if (modified == CharT{}) - read(is, CharT{'%'}, width, *fmt); - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - } - else // !command - { - if (isspace(static_cast(*fmt))) - ws(is); // space matches 0 or more white space characters - else - read(is, *fmt); - } - break; - } - } - // is.rdstate() != ios::goodbit || *fmt == CharT{} - if (is.rdstate() == ios::goodbit && command) - { - if (modified == CharT{}) - read(is, CharT{'%'}, width); - else - read(is, CharT{'%'}, width, modified); - } - if (is.rdstate() != ios::goodbit && *fmt != CharT{} && !is.fail()) - is.setstate(ios::failbit); - if (!is.fail()) - { - if (y != not_a_2digit_year) - { - // Convert y and an optional C to Y - if (!(0 <= y && y <= 99)) - goto broken; - if (C == not_a_century) - { - if (Y == not_a_year) - { - if (y >= 69) - C = 19; - else - C = 20; - } - else - { - C = (Y >= 0 ? Y : Y-100) / 100; - } - } - int tY; - if (C >= 0) - tY = 100*C + y; - else - tY = 100*(C+1) - (y == 0 ? 100 : y); - if (Y != not_a_year && Y != tY) - goto broken; - Y = tY; - } - if (g != not_a_2digit_year) - { - // Convert g and an optional C to G - if (!(0 <= g && g <= 99)) - goto broken; - if (C == not_a_century) - { - if (G == not_a_year) - { - if (g >= 69) - C = 19; - else - C = 20; - } - else - { - C = (G >= 0 ? G : G-100) / 100; - } - } - int tG; - if (C >= 0) - tG = 100*C + g; - else - tG = 100*(C+1) - (g == 0 ? 100 : g); - if (G != not_a_year && G != tG) - goto broken; - G = tG; - } - if (Y < static_cast(year::min()) || Y > static_cast(year::max())) - Y = not_a_year; - bool computed = false; - if (G != not_a_year && V != not_a_week_num && wd != not_a_weekday) - { - year_month_day ymd_trial = sys_days(year{G-1}/December/Thursday[last]) + - (Monday-Thursday) + weeks{V-1} + - (weekday{static_cast(wd)}-Monday); - if (Y == not_a_year) - Y = static_cast(ymd_trial.year()); - else if (year{Y} != ymd_trial.year()) - goto broken; - if (m == not_a_month) - m = static_cast(static_cast(ymd_trial.month())); - else if (month(static_cast(m)) != ymd_trial.month()) - goto broken; - if (d == not_a_day) - d = static_cast(static_cast(ymd_trial.day())); - else if (day(static_cast(d)) != ymd_trial.day()) - goto broken; - computed = true; - } - if (Y != not_a_year && U != not_a_week_num && wd != not_a_weekday) - { - year_month_day ymd_trial = sys_days(year{Y}/January/Sunday[1]) + - weeks{U-1} + - (weekday{static_cast(wd)} - Sunday); - if (Y == not_a_year) - Y = static_cast(ymd_trial.year()); - else if (year{Y} != ymd_trial.year()) - goto broken; - if (m == not_a_month) - m = static_cast(static_cast(ymd_trial.month())); - else if (month(static_cast(m)) != ymd_trial.month()) - goto broken; - if (d == not_a_day) - d = static_cast(static_cast(ymd_trial.day())); - else if (day(static_cast(d)) != ymd_trial.day()) - goto broken; - computed = true; - } - if (Y != not_a_year && W != not_a_week_num && wd != not_a_weekday) - { - year_month_day ymd_trial = sys_days(year{Y}/January/Monday[1]) + - weeks{W-1} + - (weekday{static_cast(wd)} - Monday); - if (Y == not_a_year) - Y = static_cast(ymd_trial.year()); - else if (year{Y} != ymd_trial.year()) - goto broken; - if (m == not_a_month) - m = static_cast(static_cast(ymd_trial.month())); - else if (month(static_cast(m)) != ymd_trial.month()) - goto broken; - if (d == not_a_day) - d = static_cast(static_cast(ymd_trial.day())); - else if (day(static_cast(d)) != ymd_trial.day()) - goto broken; - computed = true; - } - if (j != not_a_doy && Y != not_a_year) - { - auto ymd_trial = year_month_day{local_days(year{Y}/1/1) + days{j-1}}; - if (m == 0) - m = static_cast(static_cast(ymd_trial.month())); - else if (month(static_cast(m)) != ymd_trial.month()) - goto broken; - if (d == 0) - d = static_cast(static_cast(ymd_trial.day())); - else if (day(static_cast(d)) != ymd_trial.day()) - goto broken; - j = not_a_doy; - } - auto ymd = year{Y}/m/d; - if (ymd.ok()) - { - if (wd == not_a_weekday) - wd = static_cast((weekday(sys_days(ymd)) - Sunday).count()); - else if (wd != static_cast((weekday(sys_days(ymd)) - Sunday).count())) - goto broken; - if (!computed) - { - if (G != not_a_year || V != not_a_week_num) - { - sys_days sd = ymd; - auto G_trial = year_month_day{sd + days{3}}.year(); - auto start = sys_days((G_trial - years{1})/December/Thursday[last]) + - (Monday - Thursday); - if (sd < start) - { - --G_trial; - if (V != not_a_week_num) - start = sys_days((G_trial - years{1})/December/Thursday[last]) - + (Monday - Thursday); - } - if (G != not_a_year && G != static_cast(G_trial)) - goto broken; - if (V != not_a_week_num) - { - auto V_trial = duration_cast(sd - start).count() + 1; - if (V != V_trial) - goto broken; - } - } - if (U != not_a_week_num) - { - auto start = sys_days(Sunday[1]/January/ymd.year()); - auto U_trial = floor(sys_days(ymd) - start).count() + 1; - if (U != U_trial) - goto broken; - } - if (W != not_a_week_num) - { - auto start = sys_days(Monday[1]/January/ymd.year()); - auto W_trial = floor(sys_days(ymd) - start).count() + 1; - if (W != W_trial) - goto broken; - } - } - } - fds.ymd = ymd; - if (I != not_a_hour_12_value) - { - if (!(1 <= I && I <= 12)) - goto broken; - if (p != not_a_ampm) - { - // p is in [0, 1] == [AM, PM] - // Store trial H in I - if (I == 12) - --p; - I += p*12; - // Either set H from I or make sure H and I are consistent - if (H == not_a_hour) - H = I; - else if (I != H) - goto broken; - } - else // p == not_a_ampm - { - // if H, make sure H and I could be consistent - if (H != not_a_hour) - { - if (I == 12) - { - if (H != 0 && H != 12) - goto broken; - } - else if (!(I == H || I == H+12)) - { - goto broken; - } - } - } - } - if (H != not_a_hour) - { - fds.has_tod = true; - fds.tod = time_of_day{hours{H}}; - } - if (M != not_a_minute) - { - fds.has_tod = true; - fds.tod.m_ = minutes{M}; - } - if (s != not_a_second) - { - fds.has_tod = true; - fds.tod.s_ = detail::decimal_format_seconds{s}; - } - if (j != not_a_doy) - { - fds.has_tod = true; - fds.tod.h_ += hours{days{j}}; - } - if (wd != not_a_weekday) - fds.wd = weekday{static_cast(wd)}; - if (abbrev != nullptr) - *abbrev = std::move(temp_abbrev); - if (offset != nullptr && temp_offset != not_a_offset) - *offset = temp_offset; - } - return is; - } -broken: - is.setstate(ios_base::failbit); - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, year& y, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.year().ok()) - is.setstate(ios::failbit); - if (!is.fail()) - y = fds.ymd.year(); - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, month& m, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.month().ok()) - is.setstate(ios::failbit); - if (!is.fail()) - m = fds.ymd.month(); - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, day& d, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.day().ok()) - is.setstate(ios::failbit); - if (!is.fail()) - d = fds.ymd.day(); - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, weekday& wd, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.wd.ok()) - is.setstate(ios::failbit); - if (!is.fail()) - wd = fds.wd; - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, year_month& ym, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.month().ok()) - is.setstate(ios::failbit); - if (!is.fail()) - ym = fds.ymd.year()/fds.ymd.month(); - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, month_day& md, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.month().ok() || !fds.ymd.day().ok()) - is.setstate(ios::failbit); - if (!is.fail()) - md = fds.ymd.month()/fds.ymd.day(); - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, - year_month_day& ymd, std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.ok()) - is.setstate(ios::failbit); - if (!is.fail()) - ymd = fds.ymd; - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, - sys_time& tp, std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = typename common_type::type; - minutes offset_local{}; - auto offptr = offset ? offset : &offset_local; - fields fds{}; - fds.has_tod = true; - from_stream(is, fmt, fds, abbrev, offptr); - if (!fds.ymd.ok() || !fds.tod.in_conventional_range()) - is.setstate(ios::failbit); - if (!is.fail()) - tp = round(sys_days(fds.ymd) - *offptr + fds.tod.to_duration()); - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, - local_time& tp, std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = typename common_type::type; - fields fds{}; - fds.has_tod = true; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.ok() || !fds.tod.in_conventional_range()) - is.setstate(ios::failbit); - if (!is.fail()) - tp = round(local_seconds{local_days(fds.ymd)} + fds.tod.to_duration()); - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, - std::chrono::duration& d, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using Duration = std::chrono::duration; - using CT = typename common_type::type; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.has_tod) - is.setstate(ios::failbit); - if (!is.fail()) - d = duration_cast(fds.tod.to_duration()); - return is; -} - -template , - class Alloc = std::allocator> -struct parse_manip -{ - const std::basic_string format_; - Parsable& tp_; - std::basic_string* abbrev_; - std::chrono::minutes* offset_; - -public: - parse_manip(std::basic_string format, Parsable& 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_manip& x) -{ - return from_stream(is, x.format_.c_str(), x.tp_, x.abbrev_, x.offset_); -} - -template -inline -auto -parse(const std::basic_string& format, Parsable& tp) - -> decltype(from_stream(std::declval&>(), - format.c_str(), tp), - parse_manip{format, tp}) -{ - return {format, tp}; -} - -template -inline -auto -parse(const std::basic_string& format, Parsable& tp, - std::basic_string& abbrev) - -> decltype(from_stream(std::declval&>(), - format.c_str(), tp, &abbrev), - parse_manip{format, tp, &abbrev}) -{ - return {format, tp, &abbrev}; -} - -template -inline -auto -parse(const std::basic_string& format, Parsable& tp, - std::chrono::minutes& offset) - -> decltype(from_stream(std::declval&>(), - format.c_str(), tp, - std::declval*>(), - &offset), - parse_manip{format, tp, nullptr, &offset}) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -auto -parse(const std::basic_string& format, Parsable& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) - -> decltype(from_stream(std::declval&>(), - format.c_str(), tp, &abbrev, &offset), - parse_manip{format, tp, &abbrev, &offset}) -{ - return {format, tp, &abbrev, &offset}; -} - -// const CharT* formats - -template -inline -auto -parse(const CharT* format, Parsable& tp) - -> decltype(from_stream(std::declval&>(), format, tp), - parse_manip{format, tp}) -{ - return {format, tp}; -} - -template -inline -auto -parse(const CharT* format, Parsable& tp, std::basic_string& abbrev) - -> decltype(from_stream(std::declval&>(), format, - tp, &abbrev), - parse_manip{format, tp, &abbrev}) -{ - return {format, tp, &abbrev}; -} - -template -inline -auto -parse(const CharT* format, Parsable& tp, std::chrono::minutes& offset) - -> decltype(from_stream(std::declval&>(), format, - tp, std::declval*>(), &offset), - parse_manip{format, tp, nullptr, &offset}) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -auto -parse(const CharT* format, Parsable& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) - -> decltype(from_stream(std::declval&>(), format, - tp, &abbrev, &offset), - parse_manip{format, tp, &abbrev, &offset}) -{ - return {format, tp, &abbrev, &offset}; -} - -// duration streaming - -namespace detail -{ - -template -class string_literal; - -template -inline -CONSTCD14 -string_literal::type, - N1 + N2 - 1> -operator+(const string_literal& x, const string_literal& y) NOEXCEPT; - -template -class string_literal -{ - CharT p_[N]; - - CONSTCD11 string_literal() NOEXCEPT - : p_{} - {} - -public: - using const_iterator = const CharT*; - - string_literal(string_literal const&) = default; - string_literal& operator=(string_literal const&) = delete; - - template ::type> - CONSTCD11 string_literal(CharT c) NOEXCEPT - : p_{c} - { - } - - template ::type> - CONSTCD11 string_literal(CharT c1, CharT c2) NOEXCEPT - : p_{c1, c2} - { - } - - template ::type> - CONSTCD11 string_literal(CharT c1, CharT c2, CharT c3) NOEXCEPT - : p_{c1, c2, c3} - { - } - - CONSTCD14 string_literal(const CharT(&a)[N]) NOEXCEPT - : p_{} - { - for (std::size_t i = 0; i < N; ++i) - p_[i] = a[i]; - } - - template ::type> - CONSTCD14 string_literal(const char(&a)[N]) NOEXCEPT - : p_{} - { - for (std::size_t i = 0; i < N; ++i) - p_[i] = a[i]; - } - - template ::value>::type> - CONSTCD14 string_literal(string_literal const& a) NOEXCEPT - : p_{} - { - for (std::size_t i = 0; i < N; ++i) - p_[i] = a[i]; - } - - CONSTCD11 const CharT* data() const NOEXCEPT {return p_;} - CONSTCD11 std::size_t size() const NOEXCEPT {return N-1;} - - CONSTCD11 const_iterator begin() const NOEXCEPT {return p_;} - CONSTCD11 const_iterator end() const NOEXCEPT {return p_ + N-1;} - - CONSTCD11 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 - friend - CONSTCD14 - string_literal::type, - N1 + N2 - 1> - operator+(const string_literal& x, const string_literal& y) NOEXCEPT; -}; - -template -CONSTCD11 -inline -string_literal -operator+(const string_literal& x, const string_literal& y) NOEXCEPT -{ - return string_literal(x[0], y[0]); -} - -template -CONSTCD11 -inline -string_literal -operator+(const string_literal& x, const string_literal& y) NOEXCEPT -{ - return string_literal(x[0], x[1], y[0]); -} - -template -CONSTCD14 -inline -string_literal::type, - N1 + N2 - 1> -operator+(const string_literal& x, const string_literal& y) NOEXCEPT -{ - using CT = typename std::conditional::type; - - string_literal r; - std::size_t i = 0; - for (; i < N1-1; ++i) - r.p_[i] = CT(x.p_[i]); - for (std::size_t j = 0; j < N2; ++j, ++i) - r.p_[i] = CT(y.p_[j]); - - return r; -} - - -template -inline -std::basic_string -operator+(std::basic_string x, const string_literal& y) -{ - x.append(y.data(), y.size()); - return x; -} - -#if __cplusplus >= 201402 && (!defined(__EDG_VERSION__) || __EDG_VERSION__ > 411) \ - && (!defined(__SUNPRO_CC) || __SUNPRO_CC > 0x5150) - -template {} || - std::is_same{} || - std::is_same{} || - std::is_same{}>> -CONSTCD14 -inline -string_literal -msl(CharT c) NOEXCEPT -{ - return string_literal{c}; -} - -CONSTCD14 -inline -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 -CONSTCD14 -inline -std::enable_if_t -< - N < 10, - string_literal -> -msl() NOEXCEPT -{ - return msl(char(N % 10 + '0')); -} - -template -CONSTCD14 -inline -std::enable_if_t -< - 10 <= N, - string_literal -> -msl() NOEXCEPT -{ - return msl() + msl(char(N % 10 + '0')); -} - -template -CONSTCD14 -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 -CONSTCD14 -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{']'}); -} - - -#else // __cplusplus < 201402 || (defined(__EDG_VERSION__) && __EDG_VERSION__ <= 411) - -inline -std::string -to_string(std::uint64_t x) -{ - return std::to_string(x); -} - -template -inline -std::basic_string -to_string(std::uint64_t x) -{ - auto y = std::to_string(x); - return std::basic_string(y.begin(), y.end()); -} - -template -inline -typename std::enable_if -< - std::ratio::type::den != 1, - std::basic_string ->::type -msl(std::ratio) -{ - using R = typename std::ratio::type; - return std::basic_string(1, '[') + to_string(R::num) + CharT{'/'} + - to_string(R::den) + CharT{']'}; -} - -template -inline -typename std::enable_if -< - std::ratio::type::den == 1, - std::basic_string ->::type -msl(std::ratio) -{ - using R = typename std::ratio::type; - return std::basic_string(1, '[') + to_string(R::num) + CharT{']'}; -} - -#endif // __cplusplus < 201402 || (defined(__EDG_VERSION__) && __EDG_VERSION__ <= 411) - -template -CONSTCD11 -inline -string_literal -msl(std::atto) NOEXCEPT -{ - return string_literal{'a'}; -} - -template -CONSTCD11 -inline -string_literal -msl(std::femto) NOEXCEPT -{ - return string_literal{'f'}; -} - -template -CONSTCD11 -inline -string_literal -msl(std::pico) NOEXCEPT -{ - return string_literal{'p'}; -} - -template -CONSTCD11 -inline -string_literal -msl(std::nano) NOEXCEPT -{ - return string_literal{'n'}; -} - -template -CONSTCD11 -inline -typename std::enable_if -< - std::is_same::value, - string_literal ->::type -msl(std::micro) NOEXCEPT -{ - return string_literal{'\xC2', '\xB5'}; -} - -template -CONSTCD11 -inline -typename std::enable_if -< - !std::is_same::value, - string_literal ->::type -msl(std::micro) NOEXCEPT -{ - return string_literal{CharT{static_cast('\xB5')}}; -} - -template -CONSTCD11 -inline -string_literal -msl(std::milli) NOEXCEPT -{ - return string_literal{'m'}; -} - -template -CONSTCD11 -inline -string_literal -msl(std::centi) NOEXCEPT -{ - return string_literal{'c'}; -} - -template -CONSTCD11 -inline -string_literal -msl(std::deca) NOEXCEPT -{ - return string_literal{'d', 'a'}; -} - -template -CONSTCD11 -inline -string_literal -msl(std::deci) NOEXCEPT -{ - return string_literal{'d'}; -} - -template -CONSTCD11 -inline -string_literal -msl(std::hecto) NOEXCEPT -{ - return string_literal{'h'}; -} - -template -CONSTCD11 -inline -string_literal -msl(std::kilo) NOEXCEPT -{ - return string_literal{'k'}; -} - -template -CONSTCD11 -inline -string_literal -msl(std::mega) NOEXCEPT -{ - return string_literal{'M'}; -} - -template -CONSTCD11 -inline -string_literal -msl(std::giga) NOEXCEPT -{ - return string_literal{'G'}; -} - -template -CONSTCD11 -inline -string_literal -msl(std::tera) NOEXCEPT -{ - return string_literal{'T'}; -} - -template -CONSTCD11 -inline -string_literal -msl(std::peta) NOEXCEPT -{ - return string_literal{'P'}; -} - -template -CONSTCD11 -inline -string_literal -msl(std::exa) NOEXCEPT -{ - return string_literal{'E'}; -} - -template -CONSTCD11 -inline -auto -get_units(Period p) - -> decltype(msl(p) + string_literal{'s'}) -{ - return msl(p) + string_literal{'s'}; -} - -template -CONSTCD11 -inline -string_literal -get_units(std::ratio<1>) -{ - return string_literal{'s'}; -} - -template -CONSTCD11 -inline -string_literal -get_units(std::ratio<3600>) -{ - return string_literal{'h'}; -} - -template -CONSTCD11 -inline -string_literal -get_units(std::ratio<60>) -{ - return string_literal{'m', 'i', 'n'}; -} - -template -CONSTCD11 -inline -string_literal -get_units(std::ratio<86400>) -{ - return string_literal{'d'}; -} - -template > -struct make_string; - -template <> -struct make_string -{ - template - static - std::string - from(Rep n) - { - return std::to_string(n); - } -}; - -template -struct make_string -{ - template - static - std::basic_string - from(Rep n) - { - auto s = std::to_string(n); - return std::basic_string(s.begin(), s.end()); - } -}; - -template <> -struct make_string -{ - template - static - std::wstring - from(Rep n) - { - return std::to_wstring(n); - } -}; - -template -struct make_string -{ - template - static - std::basic_string - from(Rep n) - { - auto s = std::to_wstring(n); - return std::basic_string(s.begin(), s.end()); - } -}; - -} // namespace detail - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, - const std::chrono::duration& d) -{ - using namespace detail; - return os << make_string::from(d.count()) + - get_units(typename Period::type{}); -} - -} // namespace date - -#ifdef __GNUC__ -# pragma GCC diagnostic pop -#endif - -#endif // DATE_H diff --git a/src/defaults/fee_policies.hpp b/src/defaults/fee_policies.hpp new file mode 100644 index 00000000..390f3474 --- /dev/null +++ b/src/defaults/fee_policies.hpp @@ -0,0 +1,30 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#ifndef DEFAULTS_TRANSACTIONS_FEE_POLICIES_HPP +#define DEFAULTS_TRANSACTIONS_FEE_POLICIES_HPP + +#include + +#include "common/fee_policy.hpp" + +namespace Ark { +namespace Crypto { +namespace defaults { +/**/ +class Fees { + public: + static const FeePolicy StaticFeePolicy(); +}; +/**/ +} // namespace defaults +} // namespace Crypto +} // namespace Ark + +#endif diff --git a/src/defaults/static_fees.cpp b/src/defaults/static_fees.cpp new file mode 100644 index 00000000..eace0c83 --- /dev/null +++ b/src/defaults/static_fees.cpp @@ -0,0 +1,37 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#include "defaults/static_fees.hpp" + +#include + +#include "common/fee_policy.hpp" + +namespace Ark { +namespace Crypto { +namespace defaults { + +// Default ARK Static Fees +const FeePolicy Fees::StaticFeePolicy() { + return { + 10000000ULL, // Transfer + 500000000ULL, // SecondSignatureRegistration + 2500000000ULL, // DelegateRegistration + 100000000ULL, // Vote + 500000000ULL, // MultiSignatureRegistration + 0ULL, // Ipfs + 0ULL, // TimelockTransfer + 0ULL, // MultiPayment + 2500000000ULL // DelegateResignation + }; +} + +} // namespace defaults +} // namespace Crypto +} // namespace Ark diff --git a/src/defaults/static_fees.hpp b/src/defaults/static_fees.hpp new file mode 100644 index 00000000..ccddd95c --- /dev/null +++ b/src/defaults/static_fees.hpp @@ -0,0 +1,29 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#ifndef DEFAULTS_TRANSACTIONS_STATIC_FEES_HPP +#define DEFAULTS_TRANSACTIONS_STATIC_FEES_HPP + +#include "defaults/fee_policies.hpp" + +// const FeePolicy Fees::StaticFeePolicy() { +// return { +// 10000000ULL, // Transfer +// 500000000ULL, // SecondSignatureRegistration +// 2500000000ULL, // DelegateRegistration +// 100000000ULL, // Vote +// 500000000ULL, // MultiSignatureRegistration +// 0ULL, // Ipfs +// 0ULL, // TimelockTransfer +// 0ULL, // MultiPayment +// 2500000000ULL // DelegateResignation +// }; +// } + +#endif diff --git a/src/defaults/transaction_types.hpp b/src/defaults/transaction_types.hpp new file mode 100644 index 00000000..09cf5056 --- /dev/null +++ b/src/defaults/transaction_types.hpp @@ -0,0 +1,35 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#ifndef DEFAULTS_TRANSACTIONS_TYPES_HPP +#define DEFAULTS_TRANSACTIONS_TYPES_HPP + +#include + +namespace Ark { +namespace Crypto { +namespace defaults { +/**/ +enum TransactionTypes : uint8_t { + Transfer = 0, + SecondSignatureRegistration = 1, + DelegateRegistration = 2, + Vote = 3, + MultiSignatureRegistration = 4, + Ipfs = 5, + TimelockTransfer = 6, + MultiPayment = 7, + DelegateResignation = 8 +}; +/**/ +} // namespace defaults +} // namespace Crypto +} // namespace Ark + +#endif diff --git a/src/enums/fees.h b/src/enums/fees.h deleted file mode 100644 index 9aa58e22..00000000 --- a/src/enums/fees.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ - -#ifndef FEES_H -#define FEES_H - -#include - -namespace Ark { -namespace Crypto { -namespace Enums { -/** - * This is the transaction fees class. - * - * @author Simon Downey - **/ -struct Fees { - public: - static const uint64_t TRANSFER = 10000000; - static const uint64_t SECOND_SIGNATURE_REGISTRATION = 500000000; - static const uint64_t DELEGATE_REGISTRATION = 2500000000; - static const uint64_t VOTE = 100000000; - static const uint64_t MULTI_SIGNATURE_REGISTRATION = 500000000; - static const uint64_t IPFS = 0; - static const uint64_t TIMELOCK_TRANSFER = 0; - static const uint64_t MULTI_PAYMENT = 0; - static const uint64_t DELEGATE_RESIGNATION = 0; -}; -/**/ -}; // namespace Enums -}; // namespace Crypto -}; // namespace Ark - -#endif diff --git a/src/enums/types.h b/src/enums/types.h deleted file mode 100644 index b7e6a088..00000000 --- a/src/enums/types.h +++ /dev/null @@ -1,37 +0,0 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ - -#ifndef TYPES_H -#define TYPES_H - -namespace Ark { -namespace Crypto { -namespace Enums { -/** - * This is the transaction types class. - * - * @author Simon Downey - **/ -enum Types : int { - TRANSFER = 0, - SECOND_SIGNATURE_REGISTRATION = 1, - DELEGATE_REGISTRATION = 2, - VOTE = 3, - MULTI_SIGNATURE_REGISTRATION = 4, - IPFS = 5, - TIMELOCK_TRANSFER = 6, - MULTI_PAYMENT = 7, - DELEGATE_RESIGNATION = 8 -}; -/**/ -}; // namespace Enums -}; // namespace Crypto -}; // namespace Ark - -#endif diff --git a/src/helpers/crypto.cpp b/src/helpers/crypto.cpp index 508c744d..9d2d9a85 100644 --- a/src/helpers/crypto.cpp +++ b/src/helpers/crypto.cpp @@ -1,44 +1,74 @@ + #include "helpers/crypto.h" -#include #include "bcl/Ecdsa.hpp" #include "bcl/Sha256.hpp" #include "bcl/Uint256.hpp" -#include "helpers/encoding/der.h" #include "helpers/crypto_helpers.h" #include "rfc6979/rfc6979.h" #include "uECC.h" +#include "bip66.h" -void cryptoSign(Sha256Hash hash, Ark::Crypto::Identities::PrivateKey privateKey, std::vector& signature) { +void cryptoSign( + Sha256Hash hash, + Ark::Crypto::Identities::PrivateKey privateKey, + std::vector& signature) { + // create r & s-values Uint256 r; Uint256 s; + // create the nonce uint8_t nonce32[32] = {}; - nonce_function_rfc6979(nonce32, hash.value, privateKey.toBytes(), nullptr, nullptr, 0); + nonce_function_rfc6979( + nonce32, + hash.value, + privateKey.toBytes(), + nullptr, nullptr, 0); - auto ret = Ecdsa::sign(Uint256(privateKey.toBytes()), hash, Uint256(nonce32), r, s); - assert(ret); + // sign the hash using privateKey-bytes and nonce. + // outputs r & s-values. + Ecdsa::sign( + Uint256(privateKey.toBytes()), + hash, + Uint256(nonce32), + r, s); - std::vector r_der(PRIVATEKEY_SIZE); - r.getBigEndianBytes(&r_der[0]); + // create r & s-value uint8_t vector + std::vector rValue(PRIVATEKEY_SIZE); + std::vector sValue(PRIVATEKEY_SIZE); - std::vector s_der(PRIVATEKEY_SIZE); - s.getBigEndianBytes(&s_der[0]); + // plate big-endian bytes into r & s-value buffers + r.getBigEndianBytes(&rValue[0]); + s.getBigEndianBytes(&sValue[0]); - encodeDER(toDER(r_der), toDER(s_der), signature); + // encode r & s-values into a BIP66/DER-encoded signature. + BIP66::encode(rValue, sValue, signature); } -bool cryptoVerify(Ark::Crypto::Identities::PublicKey publicKey, Sha256Hash hash, std::vector& signature) { - /* Get the Uncompressed PublicKey */ - auto publicKeyBytes = publicKey.toBytes(); // compressed publicKey bytes (uint8_t*) - uint8_t uncompressedPublicKey[64] = {}; // create uncompressed publicKey buffer (uint8_t[64]) - const struct uECC_Curve_t* curve = uECC_secp256k1(); // define the curve-type - uECC_decompress(publicKeyBytes, uncompressedPublicKey, curve); // decompress the key +/**/ + +bool cryptoVerify( + Ark::Crypto::Identities::PublicKey publicKey, + Sha256Hash hash, + std::vector& signature) { + // Get the Uncompressed PublicKey + + // compressed publicKey bytes (uint8_t*) + auto publicKeyBytes = publicKey.toBytes(); + + // create uncompressed publicKey buffer (uint8_t[64]) + uint8_t uncompressedPublicKey[64] = {}; + + // define the curve-type + const struct uECC_Curve_t* curve = uECC_secp256k1(); + + // decompress the key + uECC_decompress(publicKeyBytes, uncompressedPublicKey, curve); if (uECC_valid_public_key(uncompressedPublicKey, curve) == 0) { return false; }; // validate the uncompressed publicKey - /* Split uncompressed publicKey into (x,y) coordinate buffers */ + // Split uncompressed publicKey into (x,y) coordinate buffers char xBuffer[65] = "\0"; char yBuffer[65] = "\0"; for (int i = 0; i < 32; i++) { @@ -46,19 +76,21 @@ bool cryptoVerify(Ark::Crypto::Identities::PublicKey publicKey, Sha256Hash hash, snprintf(&yBuffer[i * 2], 64, "%02x", uncompressedPublicKey[i + 32]); } - /* Create curvepoint of uncompressed publicKey(x,y) */ - FieldInt x(xBuffer); // convert xBuffer to FieldInteger - FieldInt y(yBuffer); // convert yBuffer to FieldInteger + // Create curvepoint of uncompressed publicKey(x,y) + // convert xBuffer & yBuffer to FieldInteger + FieldInt x(xBuffer); + FieldInt y(yBuffer); CurvePoint curvePoint(x, y); - /* Decode signature from DER into r & s buffers */ - std::vector r; // create r-value buffer - std::vector s; // create s-value buffer - decodeDER(signature, r, s); + /// Decode signature from DER into r & s buffers + std::vector rValue(PRIVATEKEY_SIZE); + std::vector sValue(PRIVATEKEY_SIZE); + BIP66::decode(signature, rValue, sValue); - Uint256 r256(r.data()); // create Uint256/BigNumber from r-value buffer - Uint256 s256(s.data()); // create Uint256/BigNumber from s-value buffer + // create Uint256/BigNumber from r & s-value buffers + Uint256 r256(rValue.data()); + Uint256 s256(sValue.data()); - /* Verify */ + // Verify return Ecdsa::verify(curvePoint, hash, r256, s256); } diff --git a/src/helpers/crypto.h b/src/helpers/crypto.h index 204adaa4..a1c9629b 100644 --- a/src/helpers/crypto.h +++ b/src/helpers/crypto.h @@ -17,7 +17,16 @@ #ifndef CRYPTO_H #define CRYPTO_H -void cryptoSign(Sha256Hash hash, Ark::Crypto::Identities::PrivateKey privateKey, std::vector& signature); -bool cryptoVerify(Ark::Crypto::Identities::PublicKey publicKey, Sha256Hash hash, std::vector& signature); +void cryptoSign( + Sha256Hash hash, + Ark::Crypto::Identities::PrivateKey privateKey, + std::vector& signature); + +/**/ + +bool cryptoVerify( + Ark::Crypto::Identities::PublicKey publicKey, + Sha256Hash hash, + std::vector& signature); #endif diff --git a/src/helpers/crypto_helpers.h b/src/helpers/crypto_helpers.h index e7881826..2982f712 100644 --- a/src/helpers/crypto_helpers.h +++ b/src/helpers/crypto_helpers.h @@ -1,4 +1,11 @@ - +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ #ifndef CRYPTO_HELPERS_H #define CRYPTO_HELPERS_H @@ -8,25 +15,24 @@ #include #include -const auto ADDRESS_LENGTH = 34u; -const auto COMPRESSED_PUBLICKEY_SIZE = 33u; -const auto PRIVATEKEY_SIZE = 32u; -const auto WIF_SIZE = 52u; +const auto ADDRESS_LENGTH = 34U; +const auto COMPRESSED_PUBLICKEY_SIZE = 33U; +const auto PRIVATEKEY_SIZE = 32U; +const auto WIF_SIZE = 52U; #if (defined ARDUINO || defined ESP8266 || defined ESP32) #define USE_IOT -// Including missing implementations of std::to_string -#include "stl/details/to_string.h" - #include #include -// undef the C macros to allow the C++ STL to take over -// This is to have compatibility with various board implementations of the STL -#undef min -#undef max +#endif + +#ifndef USE_IOT + +#define __STDC_FORMAT_MACROS 1 +#include #endif @@ -45,8 +51,12 @@ inline void unpack(T* dst, uint8_t* src, size_t size = -1) { // Join string vector inline std::string join(const std::vector& strings) { - return std::accumulate(strings.begin(), strings.end(), std::string(), - [](const std::string& a, const std::string& b) -> std::string { return a + b; }); + return std::accumulate( + strings.begin(), + strings.end(), + std::string(), + [](const std::string& a, const std::string& b) + -> std::string { return a + b; }); } #endif diff --git a/src/helpers/encoding/der.cpp b/src/helpers/encoding/der.cpp deleted file mode 100644 index 9265a315..00000000 --- a/src/helpers/encoding/der.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ - -#include "helpers/encoding/der.h" - -#include -#include -#include -#include - -/** - * DER Encode/Decode Helpers - **/ -std::vector& toDER(std::vector& buffer) { - // if the sign bit is set, pad with a 0x00 byte - if (buffer.size() > 1 && (buffer[0] & 0x80) != 0) { - buffer.insert(buffer.begin(), 0x00); - } - return buffer; -} - -/**/ - -void decodeDER(std::vector& signature, std::vector& r, std::vector& s) { - // Adapted from https://github.com/bitcoinjs/bip66/blob/master/index.js - assert(signature.size() > 8); // DER sequence length is too short - assert(signature.size() < 72); // DER sequence length is too long - assert(signature[0] == 0x30); // Expected DER sequence - assert(signature[1] == signature.size() - 2); // DER sequence length is invalid - assert(signature[2] == 0x02); // Expected DER integer - - /* Get the length of the signatures R-value (signature 4th-byte/signature[3]) */ - int lenR = signature[3]; - assert(lenR != 0); // R length is zero - assert(5u + lenR <= signature.size()); // R length is too long - assert(signature[4 + lenR] == 0x02); // Expected DER integer (2) - - /* Get the length of the signatures R-value (signature 6th-byte/signature[5]) */ - int lenS = signature[5 + lenR]; - assert(lenS != 0); // S length is zero - assert((6u + lenR + lenS) == signature.size()); // S length is invalid - - assert(signature[4] != 0x80); // R value is negative - assert((lenR > 1)); // && (signature[4] == 0x00) && !(signature[5] == 0x80)); // R value excessively padded - - assert(signature[lenR + 6] != 0x80); // S value is negative - assert(lenS > - 1); // && (signature[lenR + 6] != 0x00) && !(signature[lenR + 7] == 0x80)); // S value excessively padded - - /* non-BIP66 - extract R, S values */ - r = std::vector(&signature[4], &signature[4] + lenR); - s = std::vector(&signature[6 + lenR], &signature[6 + lenR] + lenS); -} - -/**/ - -void encodeDER(const std::vector& r, const std::vector& s, std::vector& signature) { - /* Adapted from https://github.com/bitcoinjs/bip66/blob/master/index.js */ - auto lenR = r.size(); - auto lenS = s.size(); - assert(lenR != 0); // must be non zero - assert(lenS != 0); - assert(lenR <= 33); // must be less than 34 bytes - assert(lenS <= 33); - assert((r[0] & 0x80) == 0); // must not be negative - assert((s[0] & 0x80) == 0); - assert(lenR == 1 || r[0] != 0x00 || (r[1] & 0x80) != 0); // must have zero pad for negative number - assert(lenS == 1 || s[0] != 0x00 || (s[1] & 0x80) != 0); - - auto it = r.begin(); - while (lenR > 1 && *it == 0 && *(it + 1) < 0x80) { - --lenR; - ++it; - } - it = s.begin(); - while (lenS > 1 && *it == 0 && *(it + 1) < 0x80) { - --lenS; - ++it; - } - - signature.clear(); - signature.reserve(6 + lenR + lenS); - - /* 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] */ - signature.push_back(0x30); // [0] - signature.push_back(static_cast(6 + lenR + lenS - 2)); // [1] - signature.push_back(0x02); // [2] - signature.push_back(static_cast(lenR)); // [3] - signature.insert(signature.end(), r.begin(), r.end()); //[4] - signature.push_back(0x02); // [4 + lenR] - signature.push_back(static_cast(lenS)); // [5 + lenR] - signature.insert(signature.end(), s.begin(), s.end()); //[6 + lenR] -} - -/**/ - -void encodeDER(uint8_t packed_signature[DEFAULT_PRIVATEKEY_SIZE * 2], std::vector& signature) { - std::vector r(DEFAULT_PRIVATEKEY_SIZE); - std::vector s(DEFAULT_PRIVATEKEY_SIZE); - - memcpy(&r[0], packed_signature, DEFAULT_PRIVATEKEY_SIZE); - memcpy(&s[0], packed_signature + DEFAULT_PRIVATEKEY_SIZE, DEFAULT_PRIVATEKEY_SIZE); - - encodeDER(toDER(r), toDER(s), signature); -} diff --git a/src/helpers/encoding/der.h b/src/helpers/encoding/der.h deleted file mode 100644 index 8d3c67b2..00000000 --- a/src/helpers/encoding/der.h +++ /dev/null @@ -1,35 +0,0 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ - -#ifndef DER_H -#define DER_H - -#include -#include - -const auto DEFAULT_PRIVATEKEY_SIZE = 32u; - -/** - * DER Encode/Decode Helpers - **/ -std::vector& toDER(std::vector& buffer); - -/**/ - -void decodeDER(std::vector& signature, std::vector& r, std::vector& s); - -/**/ - -void encodeDER(const std::vector& r, const std::vector& s, std::vector& signature); - -/**/ - -void encodeDER(uint8_t packed_signature[DEFAULT_PRIVATEKEY_SIZE * 2], std::vector& signature); - -#endif diff --git a/src/helpers/encoding/hex.h b/src/helpers/encoding/hex.h index bc14ad19..88954764 100644 --- a/src/helpers/encoding/hex.h +++ b/src/helpers/encoding/hex.h @@ -17,49 +17,58 @@ * Hex Helpers **/ template -inline std::string BytesToHex(const T itbegin, const T itend, bool fSpaces = false) { +inline std::string BytesToHex( + const T itbegin, + const T itend) { + static const char hexmap[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f' + }; + std::string rv; - static const char hexmap[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; rv.reserve((itend - itbegin) * 3); for (T it = itbegin; it < itend; ++it) { const auto val = static_cast(*it); - if (fSpaces && it != itbegin) { - rv.push_back(' '); - } rv.push_back(hexmap[val >> 4]); rv.push_back(hexmap[val & 15]); } return rv; -} +}; /**/ template -inline std::string BytesToHex(const T& vch, bool fSpaces = false) { - return BytesToHex(vch.begin(), vch.end(), fSpaces); -} +inline std::string BytesToHex(const T& vch) { + return BytesToHex(vch.begin(), vch.end()); +}; -/********/ +/****/ const int8_t p_util_hexdigit[256] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, - 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, }; /**/ inline int8_t HexDigit(char c) { return p_util_hexdigit[static_cast(c)]; -} +}; /**/ @@ -67,23 +76,17 @@ inline std::vector HexToBytes(const char* psz) { // convert hex dump to vector std::vector vch; for (;;) { - while (isspace(*psz) != 0) { - psz++; - } + while (isspace(*psz) != 0) { psz++; }; auto c = HexDigit(*psz++); - if (c == static_cast(-1)) { - break; - } + if (c == static_cast(-1)) { break; }; int8_t n = (c << 4); c = HexDigit(*psz++); - if (c == static_cast(-1)) { - break; - } + if (c == static_cast(-1)) { break; }; n |= c; vch.push_back(n); - } + }; return vch; -} +}; /**/ diff --git a/src/helpers/json.h b/src/helpers/json.h index a4b8c984..d28d8234 100644 --- a/src/helpers/json.h +++ b/src/helpers/json.h @@ -2,12 +2,12 @@ #ifndef JSON_H #define JSON_H -/* ArduinoJson Presets */ +// ArduinoJson Presets #define ARDUINOJSON_USE_LONG_LONG 1 #define ARDUINOJSON_ENABLE_STD_STRING 1 // Enable 'std::string' #define ARDUINOJSON_ENABLE_ARDUINO_STRING 0 // disable 'String' -/* ArduinoJson Header */ +// ArduinoJson Header #include "ArduinoJson.h" #endif diff --git a/src/identities/address.cpp b/src/identities/address.cpp index ce1ff11e..5fbfac68 100644 --- a/src/identities/address.cpp +++ b/src/identities/address.cpp @@ -1,147 +1,110 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ #include "identities/address.h" -/** - * @brief: constructor - * - * @param: const char *const newAddressStr - **/ -Ark::Crypto::Identities::Address::Address(const char *const newAddressStr) { +#include "identities/privatekey.h" +#include "identities/publickey.h" + +#include "helpers/encoding/hex.h" + +#include "bcl/Base58Check.hpp" + +#include + +Ark::Crypto::Identities::Address::Address( + const char* newAddressStr) { (strlen(newAddressStr) == ADDRESS_LENGTH) - ? void(memmove(this->bytes_, reinterpret_cast(newAddressStr), ADDRESS_LENGTH)) + ? void(memmove( + this->bytes_, + reinterpret_cast(newAddressStr), + ADDRESS_LENGTH)) : void(this->bytes_[COMPRESSED_PUBLICKEY_SIZE] = {'\0'}); } /**/ -Ark::Crypto::Identities::Address::Address(const uint8_t *newAddressBytes) { +Ark::Crypto::Identities::Address::Address( + const uint8_t* newAddressBytes) { memmove(this->bytes_, newAddressBytes, ADDRESS_LENGTH); } + /**/ -/** - * @brief: returns bytes of Address - * - * @return const uint8_t - **/ const uint8_t *Ark::Crypto::Identities::Address::toBytes() { return this->bytes_; } + /**/ -/** - * @brief: returns std::string representation of stored bytes - **/ std::string Ark::Crypto::Identities::Address::toString() const { return std::string(this->bytes_, this->bytes_ + ADDRESS_LENGTH); } + /**/ -/** - * @brief Derive the address from the given passphrase. - * - * @param const char* const passphrase - * @param uint8_t networkVersion - * - * @return Address - **/ -Ark::Crypto::Identities::Address Ark::Crypto::Identities::Address::fromPassphrase(const char *const passphrase, - uint8_t networkVersion) { +Ark::Crypto::Identities::Address Ark::Crypto::Identities::Address::fromPassphrase( + const char* passphrase, + uint8_t networkVersion) { PublicKey publicKey = PublicKey::fromPassphrase(passphrase); return fromPublicKey(publicKey, networkVersion); } + /**/ -/** - * @brief Derive the address from the given private key. - * - * @param PrivateKey privateKey - * @param uint8_t networkVersion - * - * @return Address - **/ -Ark::Crypto::Identities::Address Ark::Crypto::Identities::Address::fromPrivateKey(PrivateKey privateKey, - uint8_t networkVersion) { +Ark::Crypto::Identities::Address Ark::Crypto::Identities::Address::fromPrivateKey( + PrivateKey privateKey, + uint8_t networkVersion) { PublicKey publicKey = PublicKey::fromPrivateKey(privateKey); return fromPublicKey(publicKey, networkVersion); } + /**/ -/** - * @brief Derive the address from the given public key. - * - * @param PublicKey publicKey - * @param uint8_t networkVersion - * - * @return Address - **/ -Ark::Crypto::Identities::Address Ark::Crypto::Identities::Address::fromPublicKey(PublicKey publicKey, - uint8_t networkVersion) { +Ark::Crypto::Identities::Address Ark::Crypto::Identities::Address::fromPublicKey( + PublicKey publicKey, + uint8_t networkVersion) { std::vector seed(Ripemd160::HASH_LEN); - Ripemd160::getHash(publicKey.toBytes(), COMPRESSED_PUBLICKEY_SIZE, &seed[0]); + Ripemd160::getHash( + publicKey.toBytes(), + COMPRESSED_PUBLICKEY_SIZE, + &seed[0]); std::string s(35, '\0'); Base58Check::pubkeyHashToBase58Check(&seed[0], networkVersion, &s[0]); - return {s.c_str()}; + return { s.c_str() }; } + /**/ -/** - * @brief Validate the given address. - * - * @param Address address - * @param uint8_t networkVersion - * - * @return bool - **/ -bool Ark::Crypto::Identities::Address::validate(Address address, uint8_t networkVersion) { +bool Ark::Crypto::Identities::Address::validate( + Address address, + uint8_t networkVersion) { std::uint8_t pub_key_hash[Ripemd160::HASH_LEN] = {}; uint8_t version = 0; - Base58Check::pubkeyHashFromBase58Check(address.toString().c_str(), pub_key_hash, &version); + Base58Check::pubkeyHashFromBase58Check( + address.toString().c_str(), + pub_key_hash, + &version); return version == networkVersion; } + /**/ -/** - * @brief Validate the given Address string to the network version. - * - * @param const char *const privateKey - * @param uint8_t networkVersion - * - * @return bool - **/ -bool Ark::Crypto::Identities::Address::validate(const char *const addressStr, uint8_t networkVersion) { +bool Ark::Crypto::Identities::Address::validate( + const char* addressStr, + uint8_t networkVersion) { return validate(Address(addressStr), networkVersion); } + /**/ -/** - * @brief Validate the given Address bytes to the network version. - * - * @param const uint8_t *addressBytes - * @param uint8_t networkVersion - * - * @return bool - **/ -bool Ark::Crypto::Identities::Address::validate(const uint8_t *addressBytes, uint8_t networkVersion) { +bool Ark::Crypto::Identities::Address::validate( + const uint8_t* addressBytes, + uint8_t networkVersion) { return validate(Address(addressBytes), networkVersion); } + /**/ -/** - * @brief Reads 21 bytes from source and returns an base58 encoded string - * - * @param uint8_t *source - * - * @return std::string - **/ -std::string Ark::Crypto::Identities::Address::base58encode(const uint8_t *source) { +std::string Ark::Crypto::Identities::Address::base58encode( + const uint8_t* source) { // Magic numbers from Base58Check::pubkeyHashToBase58Check uint8_t temp[21 + 4] = {}; char out[ADDRESS_LENGTH + 1] = {}; @@ -154,18 +117,17 @@ std::string Ark::Crypto::Identities::Address::base58encode(const uint8_t *source return std::string(out); } -/** - * @brief Decodes the base58 encoded address - * - * @param const char* const address - * - * @return std::vector - **/ -std::vector Ark::Crypto::Identities::Address::bytesFromBase58Check(const char *const address) { +/**/ + +std::vector Ark::Crypto::Identities::Address::bytesFromBase58Check( + const char* address) { std::vector recipientIdBytes; recipientIdBytes.resize(Ripemd160::HASH_LEN); uint8_t version = 0; - Base58Check::pubkeyHashFromBase58Check(address, &recipientIdBytes[0], &version); + Base58Check::pubkeyHashFromBase58Check( + address, + &recipientIdBytes[0], + &version); recipientIdBytes.insert(recipientIdBytes.begin(), version); return recipientIdBytes; diff --git a/src/identities/address.h b/src/identities/address.h index 7e71087d..48cb3cdb 100644 --- a/src/identities/address.h +++ b/src/identities/address.h @@ -10,42 +10,39 @@ #ifndef ADDRESS_H #define ADDRESS_H -#include -#include "helpers/encoding/hex.h" #include "helpers/crypto_helpers.h" + #include "identities/privatekey.h" #include "identities/publickey.h" +#include +#include + namespace Ark { namespace Crypto { namespace Identities { - -/** - * This is the address class. - * - * @author Simon Downey - **/ +/**/ class Address { - protected: - uint8_t bytes_[ADDRESS_LENGTH]; +private: + uint8_t bytes_[ADDRESS_LENGTH] {}; - public: - Address() : bytes_(){}; - Address(const char *const newAddressStr); - Address(const uint8_t *newAddressBytes); +public: + Address() : bytes_() {}; + Address(const char* newAddressStr); + Address(const uint8_t* newAddressBytes); const uint8_t *toBytes(); std::string toString() const; - static Address fromPassphrase(const char *const passphrase, uint8_t networkVersion); + static Address fromPassphrase(const char* passphrase, uint8_t networkVersion); static Address fromPrivateKey(PrivateKey privateKey, uint8_t networkVersion); static Address fromPublicKey(PublicKey publicKey, uint8_t networkVersion); static bool validate(Address address, uint8_t networkVersion); - static bool validate(const char *const addressStr, uint8_t networkVersion); - static bool validate(const uint8_t *addressBytes, uint8_t networkVersion); - static std::string base58encode(const uint8_t *source); - static std::vector bytesFromBase58Check(const char *const address); + static bool validate(const char* addressStr, uint8_t networkVersion); + static bool validate(const uint8_t* addressBytes, uint8_t networkVersion); + static std::string base58encode(const uint8_t* source); + static std::vector bytesFromBase58Check(const char* address); }; /**/ }; // namespace Identities diff --git a/src/identities/privatekey.cpp b/src/identities/privatekey.cpp index 2c49d4c9..35c17435 100644 --- a/src/identities/privatekey.cpp +++ b/src/identities/privatekey.cpp @@ -1,125 +1,101 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ #include "identities/privatekey.h" -/** - * - **/ -Ark::Crypto::Identities::PrivateKey::PrivateKey(const char *const newPrivateKeyStr) { - memmove(this->bytes_, &HexToBytes(newPrivateKeyStr).data()[0], PRIVATEKEY_SIZE); +#include "helpers/encoding/hex.h" + +#include "bcl/Base58Check.hpp" +#include "bcl/Sha256.hpp" +#include "bcl/Sha256Hash.hpp" + +#include +#include +#include + +Ark::Crypto::Identities::PrivateKey::PrivateKey( + const char* newPrivateKeyStr) { + memmove( + this->bytes_, + HexToBytes(newPrivateKeyStr).data(), + PRIVATEKEY_SIZE); } + /**/ -/** - * - **/ -Ark::Crypto::Identities::PrivateKey::PrivateKey(const uint8_t *newPrivateKeyBytes) { +Ark::Crypto::Identities::PrivateKey::PrivateKey( + const uint8_t* newPrivateKeyBytes) { memmove(this->bytes_, newPrivateKeyBytes, PRIVATEKEY_SIZE); } + /**/ -/** - * - **/ const uint8_t *Ark::Crypto::Identities::PrivateKey::toBytes() { return this->bytes_; }; + /**/ -/** - * - **/ std::string Ark::Crypto::Identities::PrivateKey::toString() const { return BytesToHex(this->bytes_, this->bytes_ + PRIVATEKEY_SIZE); } + /**/ -/** - * @brief Derive the private key for the given passphrase. - * - * @param const char* const passphrase - * - * @return std::string - **/ -Ark::Crypto::Identities::PrivateKey Ark::Crypto::Identities::PrivateKey::fromPassphrase(const char *const passphrase) { +Ark::Crypto::Identities::PrivateKey Ark::Crypto::Identities::PrivateKey::fromPassphrase( + const char* passphrase) { std::vector privateKey(PRIVATEKEY_SIZE); - auto hash = Sha256::getHash(reinterpret_cast(passphrase), strlen(passphrase)); + auto hash = Sha256::getHash( + reinterpret_cast(passphrase), + strlen(passphrase)); memcpy(&privateKey[0], hash.value, privateKey.size()); - return {BytesToHex(&privateKey[0], &privateKey[0] + PRIVATEKEY_SIZE).c_str()}; + return { + BytesToHex(&privateKey[0], &privateKey[0] + PRIVATEKEY_SIZE).c_str() + }; } + /**/ -/** - * @brief Create a private key instance from a hex string. - * - * @param const char *const privateKey - * - * @return PrivateKey - **/ -Ark::Crypto::Identities::PrivateKey Ark::Crypto::Identities::PrivateKey::fromHex(const char *const privateKey) { - return {privateKey}; +Ark::Crypto::Identities::PrivateKey Ark::Crypto::Identities::PrivateKey::fromHex( + const char* privateKey) { + return { privateKey }; } + /**/ -/** - * @brief Derive the private key for the given WIF. - * - * @param const char* wifStr - * @param uint8_t wifByte - * - * @return PrivateKey - **/ -Ark::Crypto::Identities::PrivateKey Ark::Crypto::Identities::PrivateKey::fromWIFString(const char *wifStr, - uint8_t wifByte) { +Ark::Crypto::Identities::PrivateKey Ark::Crypto::Identities::PrivateKey::fromWIFString( + const char* wifStr, + uint8_t wifByte) { Uint256 bigNum; bool compressed = true; - auto ret = Base58Check::privateKeyFromBase58Check(wifStr, bigNum, &wifByte, &compressed); - assert(ret); + Base58Check::privateKeyFromBase58Check( + wifStr, + bigNum, + &wifByte, + &compressed); std::vector privateKey(PRIVATEKEY_SIZE); bigNum.getBigEndianBytes(&privateKey[0]); - return {BytesToHex(&privateKey[0], &privateKey[0] + PRIVATEKEY_SIZE).c_str()}; + return { + BytesToHex(&privateKey[0], &privateKey[0] + PRIVATEKEY_SIZE).c_str() + }; } + /**/ -/** - * @brief Validate the given private key. - * - * @param PrivateKey privateKey - * - * @return bool - **/ -bool Ark::Crypto::Identities::PrivateKey::validate(PrivateKey privateKey) { +bool Ark::Crypto::Identities::PrivateKey::validate( + PrivateKey privateKey) { return PrivateKey::validate(privateKey.toString().c_str()); -}; +} + /**/ -/** - * @brief Validate the given private key. - * - * @param const char *const privateKey - * - * @return bool - **/ -bool Ark::Crypto::Identities::PrivateKey::validate(const char *privateKeyStr) { - return ((strlen(privateKeyStr) / 2) == PRIVATEKEY_SIZE); // check length +bool Ark::Crypto::Identities::PrivateKey::validate( + const char* privateKeyStr) { + // check length + return ((strlen(privateKeyStr) / 2) == PRIVATEKEY_SIZE); } + /**/ -/** - * @brief Validate the given private key. - * - * @param const uint8_t *privateKeyBytes - * - * @return bool - **/ -bool Ark::Crypto::Identities::PrivateKey::validate(const uint8_t *privateKeyBytes) { +bool Ark::Crypto::Identities::PrivateKey::validate( + const uint8_t* privateKeyBytes) { return validate(PrivateKey(privateKeyBytes)); } -/**/ diff --git a/src/identities/publickey.cpp b/src/identities/publickey.cpp index 3363f879..c33b7129 100644 --- a/src/identities/publickey.cpp +++ b/src/identities/publickey.cpp @@ -1,134 +1,113 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ + #include "identities/publickey.h" + +#include "helpers/encoding/hex.h" + #include "uECC.h" -/** - * - **/ -Ark::Crypto::Identities::PublicKey::PublicKey(const char *const newPublicKeyStr) { - memmove(this->bytes_, &HexToBytes(newPublicKeyStr).data()[0], COMPRESSED_PUBLICKEY_SIZE); + +#include +#include +#include +#include + +Ark::Crypto::Identities::PublicKey::PublicKey( + const char* newPublicKeyStr) { + memmove( + this->bytes_, + HexToBytes(newPublicKeyStr).data(), + COMPRESSED_PUBLICKEY_SIZE); } + /**/ -/** - * - **/ -Ark::Crypto::Identities::PublicKey::PublicKey(const uint8_t *newPublicKeyBytes) { +Ark::Crypto::Identities::PublicKey::PublicKey( + const uint8_t* newPublicKeyBytes) { memmove(this->bytes_, newPublicKeyBytes, COMPRESSED_PUBLICKEY_SIZE); } + /**/ -/** - * - **/ -const uint8_t *Ark::Crypto::Identities::PublicKey::toBytes() { +const uint8_t* Ark::Crypto::Identities::PublicKey::toBytes() { return this->bytes_; } + /**/ -/** - * - **/ bool Ark::Crypto::Identities::PublicKey::isValid() { return PublicKey::validate(*this); } + /**/ -/** - * - **/ std::string Ark::Crypto::Identities::PublicKey::toString() const { return BytesToHex(this->bytes_, this->bytes_ + COMPRESSED_PUBLICKEY_SIZE); } + /**/ -/** - * @brief Derive the public from the given passphrase. - * - * @param const char *const passphrase - * - * @return std::string - **/ -Ark::Crypto::Identities::PublicKey Ark::Crypto::Identities::PublicKey::fromPassphrase(const char *const passphrase) { +Ark::Crypto::Identities::PublicKey Ark::Crypto::Identities::PublicKey::fromPassphrase( + const char* passphrase) { PrivateKey privateKey = PrivateKey::fromPassphrase(passphrase); return PublicKey::fromPrivateKey(privateKey); } + /**/ -/** - * - **/ -Ark::Crypto::Identities::PublicKey Ark::Crypto::Identities::PublicKey::fromPrivateKey(PrivateKey privateKey) { +Ark::Crypto::Identities::PublicKey Ark::Crypto::Identities::PublicKey::fromPrivateKey( + PrivateKey privateKey) { std::vector publicKey(COMPRESSED_PUBLICKEY_SIZE); const struct uECC_Curve_t *curve = uECC_secp256k1(); uint8_t pub[64] = {}; // TODO: using the current uECC implementation, a private key value of "1" will return a false negative. // It appears to be not supported given the following issue: https://github.com/kmackay/micro-ecc/issues/128 const uint8_t *privkeyBytes = privateKey.toBytes(); - auto ret = uECC_compute_public_key( - &privkeyBytes[0], pub, curve); // Don't check the return inline with the assert. MSVC optimizer does bad things. - assert(ret != 0); - assert(publicKey.size() == COMPRESSED_PUBLICKEY_SIZE); + // Don't check the return inline with the assert. MSVC optimizer does bad things. + uECC_compute_public_key( + &privkeyBytes[0], + pub, + curve); uECC_compress(pub, &publicKey[0], curve); - return {BytesToHex(&publicKey[0], &publicKey[0] + COMPRESSED_PUBLICKEY_SIZE).c_str()}; + return { + BytesToHex(&publicKey[0], &publicKey[0] + COMPRESSED_PUBLICKEY_SIZE).c_str() + }; } + /**/ -/** - * @brief Create a public key instance from a hex string. - * - * @param const char *const publicKey - * - * @return PublicKey - **/ -Ark::Crypto::Identities::PublicKey Ark::Crypto::Identities::PublicKey::fromHex(const char *const publicKey) { - return {publicKey}; -}; +Ark::Crypto::Identities::PublicKey Ark::Crypto::Identities::PublicKey::fromHex( + const char* publicKey) { + return { publicKey }; +} + /**/ -/** - * @brief Validate the given public key. - * - * @param PublicKey publicKey - * - * @return bool - **/ -bool Ark::Crypto::Identities::PublicKey::validate(PublicKey publicKey) { - auto publicKeyBytes = publicKey.toBytes(); // compressed publicKey bytes (uint8_t*) - uint8_t uncompressedPublicKey[64] = {}; // create uncompressed publicKey buffer (uint8_t[64]) - const struct uECC_Curve_t *curve = uECC_secp256k1(); // define the curve-type - uECC_decompress(publicKeyBytes, uncompressedPublicKey, curve); // decompress the key - return uECC_valid_public_key(uncompressedPublicKey, curve); // validate the uncompressed publicKey +bool Ark::Crypto::Identities::PublicKey::validate( + PublicKey publicKey) { + // compressed publicKey bytes (uint8_t*) + auto publicKeyBytes = publicKey.toBytes(); + // create uncompressed publicKey buffer (uint8_t[64]) + uint8_t uncompressedPublicKey[64] = {}; + // define the curve-type + const struct uECC_Curve_t *curve = uECC_secp256k1(); + + // decompress the key + uECC_decompress(publicKeyBytes, uncompressedPublicKey, curve); + + // validate the uncompressed publicKey + return (uECC_valid_public_key(uncompressedPublicKey, curve) != 0); } + /**/ -/** - * @brief Validate the given public key. - * - * @param const char *const publicKey - * - * @return bool - **/ -bool Ark::Crypto::Identities::PublicKey::validate(const char *publicKeyStr) { +bool Ark::Crypto::Identities::PublicKey::validate( + const char* publicKeyStr) { return validate(PublicKey(publicKeyStr)); } + /**/ -/** - * @brief Validate the given public key. - * - * @param const uint8_t *publicKeyBytes - * - * @return bool - **/ -bool Ark::Crypto::Identities::PublicKey::validate(const uint8_t *publicKeyBytes) { +bool Ark::Crypto::Identities::PublicKey::validate( + const uint8_t* publicKeyBytes) { return validate(PublicKey(publicKeyBytes)); } -/**/ diff --git a/src/identities/publickey.h b/src/identities/publickey.h index 5dd35642..03cc4d2c 100644 --- a/src/identities/publickey.h +++ b/src/identities/publickey.h @@ -10,40 +10,39 @@ #ifndef PUBLICKEY_H #define PUBLICKEY_H -#include -#include "helpers/encoding/hex.h" -#include "helpers/crypto_helpers.h" #include "identities/privatekey.h" +#include "identities/publickey.h" + +#include "helpers/crypto_helpers.h" + +#include +#include namespace Ark { namespace Crypto { namespace Identities { -/** - * This is the public key class. - * - * @author Simon Downey - **/ +/**/ class PublicKey { - protected: - uint8_t bytes_[COMPRESSED_PUBLICKEY_SIZE]; +private: + uint8_t bytes_[COMPRESSED_PUBLICKEY_SIZE] {}; - public: - PublicKey() : bytes_(){}; - PublicKey(const char *const newPublicKeyStr); - PublicKey(const uint8_t *newPublicKeyBytes); +public: + PublicKey() : bytes_() {}; + PublicKey(const char* newPublicKeyStr); + PublicKey(const uint8_t* newPublicKeyBytes); const uint8_t *toBytes(); bool isValid(); std::string toString() const; - static PublicKey fromPassphrase(const char *const passphrase); + static PublicKey fromPassphrase(const char* passphrase); static PublicKey fromPrivateKey(PrivateKey privateKey); - static PublicKey fromHex(const char *const publicKey); + static PublicKey fromHex(const char* publicKey); static bool validate(PublicKey publicKey); - static bool validate(const char *publicKeyStr); - static bool validate(const uint8_t *publicKeyBytes); + static bool validate(const char* publicKeyStr); + static bool validate(const uint8_t* publicKeyBytes); }; /**/ }; // namespace Identities diff --git a/src/identities/wif.cpp b/src/identities/wif.cpp index f1cbc294..14e71e28 100644 --- a/src/identities/wif.cpp +++ b/src/identities/wif.cpp @@ -1,53 +1,63 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ #include "identities/wif.h" -/**/ -Ark::Crypto::Identities::WIF::WIF(const char *const newWIFStr) { - (std::strlen(newWIFStr) == WIF_SIZE) - ? void(std::memmove(this->bytes_, reinterpret_cast(newWIFStr), WIF_SIZE)) +#include "helpers/encoding/hex.h" + +#include "bcl/Base58Check.hpp" +#include "bcl/Uint256.hpp" + +#include +#include +#include +#include + +Ark::Crypto::Identities::WIF::WIF( + const char* newWIFStr) { + (strlen(newWIFStr) == WIF_SIZE) + ? void(memmove( + this->bytes_, + reinterpret_cast(newWIFStr), + WIF_SIZE)) : void(this->bytes_[WIF_SIZE - 1] = {'\0'}); } -/**/ /**/ -Ark::Crypto::Identities::WIF::WIF(const uint8_t *newWIFBytes) { - std::memmove(this->bytes_, newWIFBytes, WIF_SIZE); + +Ark::Crypto::Identities::WIF::WIF( + const uint8_t* newWIFBytes) { + memmove(this->bytes_, newWIFBytes, WIF_SIZE); } -/**/ /**/ + const uint8_t *Ark::Crypto::Identities::WIF::toBytes() { return this->bytes_; }; -/**/ /**/ + std::string Ark::Crypto::Identities::WIF::toString() const { return std::string(this->bytes_, this->bytes_ + WIF_SIZE); } + +/**/ + +bool Ark::Crypto::Identities::WIF::validate(WIF wif) { + const auto wifString = wif.toString(); + return strrchr(wifString.c_str(), '\0') == nullptr; +} + /**/ -/** - * @brief Derive the WIF from the given passphrase. - * - * @param const char *const passphrase - * @param uint8_t wifByte - * - * @return WIF - **/ -Ark::Crypto::Identities::WIF Ark::Crypto::Identities::WIF::fromPassphrase(const char *const passphrase, - uint8_t wifByte) { +Ark::Crypto::Identities::WIF Ark::Crypto::Identities::WIF::fromPassphrase( + const char* passphrase, + uint8_t wifByte) { PrivateKey privateKey = PrivateKey::fromPassphrase(passphrase); std::string wifStr(53, '\0'); - Base58Check::privateKeyToBase58Check(Uint256(privateKey.toString().c_str()), wifByte, true, &wifStr[0]); - return {wifStr.c_str()}; + Base58Check::privateKeyToBase58Check( + Uint256(privateKey.toString().c_str()), + wifByte, + true, + &wifStr[0]); + return { wifStr.c_str() }; } -/**/ diff --git a/src/identities/wif.h b/src/identities/wif.h index 096eac64..8d00d9ae 100644 --- a/src/identities/wif.h +++ b/src/identities/wif.h @@ -10,32 +10,30 @@ #ifndef WIF_H #define WIF_H -#include -#include "helpers/encoding/hex.h" #include "identities/privatekey.h" +#include +#include + namespace Ark { namespace Crypto { namespace Identities { - -/** - * This is the wif class. - * - * @author Simon Downey - **/ +/**/ class WIF { - protected: - uint8_t bytes_[WIF_SIZE]; +private: + uint8_t bytes_[WIF_SIZE] {}; - public: - WIF() : bytes_(){}; - WIF(const char *const newWIFStr); - WIF(const uint8_t *newWIFBytes); +public: + WIF() : bytes_() {}; + WIF(const char* newWIFStr); + WIF(const uint8_t* newWIFBytes); const uint8_t *toBytes(); std::string toString() const; - static WIF fromPassphrase(const char *const passphrase, uint8_t wifByte); + static WIF fromPassphrase(const char* passphrase, uint8_t wifByte); + + static bool validate(WIF wif); }; /**/ }; // namespace Identities diff --git a/src/managers/fee_manager.cpp b/src/managers/fee_manager.cpp new file mode 100644 index 00000000..8332014f --- /dev/null +++ b/src/managers/fee_manager.cpp @@ -0,0 +1,67 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#include "managers/fee_manager.hpp" + +#include + +namespace Ark { +namespace Crypto { +namespace managers { + +namespace { + static const uint64_t AMOUNT_ZERO = 0ULL; +} // namespace + +/**/ + +uint64_t FeeManager::getFee(uint8_t type) const { + std::size_t slot = type + 1; + return slot <= feePolicy_.size() + ? this->feePolicy_[type] + : AMOUNT_ZERO; +} + +/**/ + +void FeeManager::setFee(uint8_t type, uint64_t amount) { + std::size_t slot = type + 1; + if (slot > this->feePolicy_.size()) { + this->feePolicy_.resize(slot); + }; + this->feePolicy_[type] = amount; +} + +/**/ + +FeePolicy FeeManager::getPolicy() const { + return this->feePolicy_; +} + +/**/ + +void FeeManager::setPolicy(const FeePolicy& policy) { + this->feePolicy_ = policy; +} + +/**/ + +bool FeeManager::operator==(const FeeManager& rhs) const { + return this->getPolicy() == rhs.getPolicy(); +} + +/**/ + +bool FeeManager::operator!=(const FeeManager& rhs) const { + return this->getPolicy() != rhs.getPolicy(); +} + +} // namespace managers +} // namespace Crypto +} // namespace Ark diff --git a/src/managers/fee_manager.hpp b/src/managers/fee_manager.hpp new file mode 100644 index 00000000..05362937 --- /dev/null +++ b/src/managers/fee_manager.hpp @@ -0,0 +1,46 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#ifndef MANAGERS_FEE_MANAGER_HPP +#define MANAGERS_FEE_MANAGER_HPP + +#include "common/fee_policy.hpp" +#include "defaults/fee_policies.hpp" + +namespace Ark { +namespace Crypto { +namespace managers { +/**/ +class FeeManager { + private: + FeePolicy feePolicy_ = defaults::Fees::StaticFeePolicy(); + + public: + // Default initialization: using ARK StaticFees + FeeManager() = default; + virtual ~FeeManager() = default; + + // FeePolicy initialization: Custom FeePolicy + FeeManager(const FeePolicy& policy) : feePolicy_(policy) {} + + uint64_t getFee(uint8_t type) const; + void setFee(uint8_t type, uint64_t amount); + + FeePolicy getPolicy() const; + void setPolicy(const FeePolicy& policy); + + bool operator==(const FeeManager& rhs) const; + bool operator!=(const FeeManager& rhs) const; +}; +/**/ +} // namespace managers +} // namespace Crypto +} // namespace Ark + +#endif diff --git a/src/managers/network_manager.cpp b/src/managers/network_manager.cpp new file mode 100644 index 00000000..723d91ed --- /dev/null +++ b/src/managers/network_manager.cpp @@ -0,0 +1,42 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#include "managers/network_manager.hpp" + +#include "common/network.hpp" + +namespace Ark { +namespace Crypto { +namespace managers { + +Network NetworkManager::getNetwork() const { + return this->network_; +} + +/**/ + +void NetworkManager::setNetwork(const Network& network) { + this->network_ = network; +} + +/**/ + +bool NetworkManager::operator==(const NetworkManager& rhs) const { + return this->getNetwork() == rhs.getNetwork(); +} + +/**/ + +bool NetworkManager::operator!=(const NetworkManager& rhs) const { + return this->getNetwork() != rhs.getNetwork(); +} + +} // namespace managers +} // namespace Crypto +} // namespace Ark diff --git a/src/managers/network_manager.hpp b/src/managers/network_manager.hpp new file mode 100644 index 00000000..ee5d2a5d --- /dev/null +++ b/src/managers/network_manager.hpp @@ -0,0 +1,43 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#ifndef MANAGERS_NETWORK_MANAGER_HPP +#define MANAGERS_NETWORK_MANAGER_HPP + +#include "common/network.hpp" +#include "networks/devnet.hpp" + +namespace Ark { +namespace Crypto { +namespace managers { +/**/ +class NetworkManager { + private: + Network network_ = Networks::Devnet(); + + public: + // Default initialization: using ARK Devnet + NetworkManager() = default; + virtual ~NetworkManager() = default; + + // Network initialization: Custom Network + NetworkManager(const Network& network) : network_(network) {} + + Network getNetwork() const; + void setNetwork(const Network& network); + + bool operator==(const NetworkManager& rhs) const; + bool operator!=(const NetworkManager& rhs) const; +}; +/**/ +} // namespace managers +} // namespace Crypto +} // namespace Ark + +#endif diff --git a/src/networks/abstractnetwork.cpp b/src/networks/abstractnetwork.cpp deleted file mode 100644 index d5499245..00000000 --- a/src/networks/abstractnetwork.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ - -#include "networks/abstractnetwork.h" - -/** - * @brief get the networks Base58 prefix byte given a prefix name - * - * @param Base58PrefixType prefix - * @return uint8_t - **/ -uint8_t Ark::Crypto::Networks::AbstractNetwork::getBase58Prefix(Base58PrefixType prefix) const { - switch (prefix) { - case 0: - return this->base58_.ADDRESS_P2PKH; - case 1: - return this->base58_.ADDRESS_P2SH; - case 2: - return this->base58_.WIF; - default: - return 0; - } -} -/**/ - -/** - * @brief sets the networks Base58 prefix given a prefix name and byte - * - * @param Base58PrefixType prefix - * @param uint8_t newByte - **/ -void Ark::Crypto::Networks::AbstractNetwork::setBase58Prefix(Base58PrefixType prefix, uint8_t newByte) { - if (!isLocked_) { - switch (prefix) { - case 0: - this->base58_.ADDRESS_P2PKH = newByte; - case 1: - this->base58_.ADDRESS_P2SH = newByte; - case 2: - this->base58_.WIF = newByte; - }; - } -} -/**/ - -/** - * @brief get the networks BIP32 prefix byte given a prefix name - * - * @param Base58PrefixType prefix - * @return long - **/ -long Ark::Crypto::Networks::AbstractNetwork::getBIP32Prefix(BIP32PrefixType prefix) const { - return (prefix == 0) ? this->bip32_.PREFIX_XPUB : this->bip32_.PREFIX_XPRV; -} -/**/ - -/** - * @brief sets the networks BIP32 prefix given a prefix name and byte - * - * @param BIP32PrefixType prefix - * @param long newByte - **/ -void Ark::Crypto::Networks::AbstractNetwork::setBIP32Prefix(BIP32PrefixType prefix, long newByte) { - if (!isLocked_) { - switch (prefix) { - case 0: - this->bip32_.PREFIX_XPUB = newByte; - break; - case 1: - this->bip32_.PREFIX_XPRV = newByte; - break; - }; - } -} -/**/ - -/** - * Get the network epoch. - * - * @return const char* - **/ -bool Ark::Crypto::Networks::AbstractNetwork::isLocked() const { - return this->isLocked_; -} -/**/ - -/** - * Get the network epoch. - * - * @return const char* - **/ -const char* Ark::Crypto::Networks::AbstractNetwork::epoch() const { - return this->epoch_; -} -/**/ - -/** - * Get the network version as number. - * - * @return int - **/ -uint8_t Ark::Crypto::Networks::AbstractNetwork::version() const { - return uint8_t(base58_.ADDRESS_P2PKH); -} -/**/ diff --git a/src/networks/abstractnetwork.h b/src/networks/abstractnetwork.h deleted file mode 100644 index 9d49d0ef..00000000 --- a/src/networks/abstractnetwork.h +++ /dev/null @@ -1,98 +0,0 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ - -#ifndef ABSTRACT_NETWORK_H -#define ABSTRACT_NETWORK_H - -#include -#include -#include - -namespace Ark { -namespace Crypto { -namespace Networks { - -/** - * @brief Base58 Prefix Type - **/ -enum Base58PrefixType : int { BASE58_ADDRESS_P2PKH = 0, BASE58_ADDRESS_P2SH, BASE58_WIF }; -/**/ - -/** - * @brief Base58 Prefix Container - **/ -struct base58_t { - uint8_t ADDRESS_P2PKH; - uint8_t ADDRESS_P2SH; - uint8_t WIF; -}; -/**/ - -/** - * @brief BIP32 Prefix Type - **/ -enum BIP32PrefixType : int { BIP32_PREFIX_XPUB = 0, BIP32_PREFIX_XPRV }; -/**/ -/** - * @brief BIP32 Prefix Container - **/ -struct bip32_t { - long PREFIX_XPUB; - long PREFIX_XPRV; -}; -/**/ - -/** - * @brief This is the abstract network class. - * - * @author Simon Downey - **/ -class AbstractNetwork { - protected: - base58_t base58_; - bip32_t bip32_; - char epoch_[34]; - bool isLocked_; - - public: - AbstractNetwork() = default; - - /** - * @brief Abstract Network Parameter Instantiation interface - * - * @param base58_t base58 - * @param bip32_t bip32 - * @param char epoch[34] - * @param bool isEditable // default false - **/ - AbstractNetwork(base58_t base58, bip32_t bip32, const char* epoch, bool locked = true) - : base58_(base58), bip32_(bip32), epoch_(), isLocked_(locked) { - std::strncpy(this->epoch_, epoch, 34); - }; - /**/ - - virtual ~AbstractNetwork() = default; - - uint8_t getBase58Prefix(Base58PrefixType prefix) const; - void setBase58Prefix(Base58PrefixType prefix, uint8_t newByte); - - long getBIP32Prefix(BIP32PrefixType prefix) const; - void setBIP32Prefix(BIP32PrefixType prefix, long newByte); - - bool isLocked() const; - - const char* epoch() const; - uint8_t version() const; -}; -/**/ -}; // namespace Networks -}; // namespace Crypto -}; // namespace Ark - -#endif diff --git a/src/networks/devnet.cpp b/src/networks/devnet.cpp new file mode 100644 index 00000000..39e8e6df --- /dev/null +++ b/src/networks/devnet.cpp @@ -0,0 +1,28 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#include "networks/devnet.hpp" + +namespace Ark { +namespace Crypto { +/**/ +// Devnet +// Default ARK Development Network +const Network Networks::Devnet() { // NOLINT + return Network( + "2a44f340d76ffc3df204c5f38cd355b7496c9065a1ade2ef92071436bd72e867", // nethash + 1, // slip44 + 0xaa, // wif + 0x1e, // version + "2017-03-21T13:00:00.000Z" // epoch + ); +} +/**/ +} // namespace Crypto +} // namespace Ark diff --git a/src/networks/devnet.h b/src/networks/devnet.h deleted file mode 100644 index 3e48f276..00000000 --- a/src/networks/devnet.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ - -#ifndef DEVNET_H -#define DEVNET_H - -#include "networks/abstractnetwork.h" - -namespace Ark { -namespace Crypto { -namespace Networks { -/** - * This is the devnet network class. - * - * @author Simon Downey - **/ -const AbstractNetwork Devnet = { - { - 0x1E, // BASE58_ADDRESS_P2PKH - 0x00, // BASE58_ADDRESS_P2SH - 0xaa // BASE58_WIF - }, - { - 46090600, // BIP32_PREFIX_XPUB - 46089520 // BIP32_PREFIX_XPRV - }, - "2017-03-21T13:00:00.000Z" // Epoch -}; -/**/ -}; // namespace Networks -}; // namespace Crypto -}; // namespace Ark - -#endif diff --git a/src/networks/devnet.hpp b/src/networks/devnet.hpp new file mode 100644 index 00000000..57100d50 --- /dev/null +++ b/src/networks/devnet.hpp @@ -0,0 +1,23 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#ifndef NETWORKS_DEVNET_HPP +#define NETWORKS_DEVNET_HPP + +#include "networks/networks.hpp" + +// const Network Devnet { +// "2a44f340d76ffc3df204c5f38cd355b7496c9065a1ade2ef92071436bd72e867", // nethash +// 1, // slip44 +// 0xaa, // wif +// 0x1E, // version +// "2017-03-21T13:00:00.000Z" // epoch +// }; + +#endif diff --git a/src/networks/mainnet.cpp b/src/networks/mainnet.cpp new file mode 100644 index 00000000..ef3229e3 --- /dev/null +++ b/src/networks/mainnet.cpp @@ -0,0 +1,28 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#include "networks/mainnet.hpp" + +namespace Ark { +namespace Crypto { +/**/ +// Mainnet +// ARK Public Network +const Network Networks::Mainnet() { // NOLINT + return Network( + "6e84d08bd299ed97c212c886c98a57e36545c8f5d645ca7eeae63a8bd62d8988", // nethash + 111, // slip44 + 0xaa, // wif + 0x17, // version + "2017-03-21T13:00:00.000Z" // epoch + ); +} +/**/ +} // namespace Crypto +} // namespace Ark diff --git a/src/networks/mainnet.h b/src/networks/mainnet.h deleted file mode 100644 index 00a6d189..00000000 --- a/src/networks/mainnet.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ - -#ifndef MAINNET_H -#define MAINNET_H - -#include "networks/abstractnetwork.h" - -namespace Ark { -namespace Crypto { -namespace Networks { -/** - * @brief This is the mainnet network class. - * - * @author Simon Downey - **/ -const AbstractNetwork Mainnet = { - { - 0x17, // BASE58_ADDRESS_P2PKH - 0x00, // BASE58_ADDRESS_P2SH - 0xaa // BASE58_WIF - }, - { - 46090600, // BIP32_PREFIX_XPUB - 46089520 // BIP32_PREFIX_XPRV - }, - "2017-03-21T13:00:00.000Z" // Epoch -}; -/**/ -}; // namespace Networks -}; // namespace Crypto -}; // namespace Ark - -#endif diff --git a/src/networks/mainnet.hpp b/src/networks/mainnet.hpp new file mode 100644 index 00000000..624c728c --- /dev/null +++ b/src/networks/mainnet.hpp @@ -0,0 +1,23 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#ifndef NETWORKS_MAINNET_HPP +#define NETWORKS_MAINNET_HPP + +#include "networks/networks.hpp" + +// const Network Mainnet { +// "6e84d08bd299ed97c212c886c98a57e36545c8f5d645ca7eeae63a8bd62d8988", // nethash +// 111, // slip44 +// 0xaa, // wif +// 0x17, // version +// "2017-03-21T13:00:00.000Z" // epoch +// }; + +#endif diff --git a/src/networks/networks.hpp b/src/networks/networks.hpp new file mode 100644 index 00000000..8385ec1e --- /dev/null +++ b/src/networks/networks.hpp @@ -0,0 +1,28 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#ifndef NETWORKS_HPP +#define NETWORKS_HPP + +#include "common/network.hpp" + +namespace Ark { +namespace Crypto { +/**/ +class Networks { + public: + static const Network Devnet(); + static const Network Mainnet(); + static const Network Testnet(); +}; +/**/ +} // namespace Crypto +} // namespace Ark + +#endif diff --git a/src/networks/testnet.cpp b/src/networks/testnet.cpp new file mode 100644 index 00000000..1d2f99b1 --- /dev/null +++ b/src/networks/testnet.cpp @@ -0,0 +1,28 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#include "networks/testnet.hpp" + +namespace Ark { +namespace Crypto { +/**/ +// Testnet +// ARK Test Network +const Network Networks::Testnet() { // NOLINT + return Network( + "d9acd04bde4234a81addb8482333b4ac906bed7be5a9970ce8ada428bd083192", // nethash + 1, // slip44 + 0xba, // wif + 0x17, // version + "2017-03-21T13:00:00.000Z" // epoch + ); +} +/**/ +} // namespace Crypto +} // namespace Ark diff --git a/src/networks/testnet.h b/src/networks/testnet.h deleted file mode 100644 index 97689c78..00000000 --- a/src/networks/testnet.h +++ /dev/null @@ -1,40 +0,0 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ - -#ifndef TESTNET_H -#define TESTNET_H - -#include "networks/abstractnetwork.h" - -namespace Ark { -namespace Crypto { -namespace Networks { -/** - * @brief This is the testnet network class. - * - * @author Simon Downey - **/ -const AbstractNetwork Testnet = { - { - 0x17, // BASE58_ADDRESS_P2PKH - 0x00, // BASE58_ADDRESS_P2SH - 0xba // BASE58_WIF - }, - { - 70617039, // BIP32_PREFIX_XPUB - 70615956 // BIP32_PREFIX_XPRV - }, - "2017-03-21T13:00:00.000Z" // Epoch -}; -/**/ -}; // namespace Networks -}; // namespace Crypto -}; // namespace Ark - -#endif diff --git a/src/networks/testnet.hpp b/src/networks/testnet.hpp new file mode 100644 index 00000000..a83feb93 --- /dev/null +++ b/src/networks/testnet.hpp @@ -0,0 +1,23 @@ +/** + * This file is part of Ark Cpp Crypto. + * + * (c) Ark Ecosystem + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + **/ + +#ifndef NETWORKS_TESTNET_HPP +#define NETWORKS_TESTNET_HPP + +#include "networks/networks.hpp" + +// const Network Testnet { +// "d9acd04bde4234a81addb8482333b4ac906bed7be5a9970ce8ada428bd083192", // nethash +// 1, // slip44 +// 0xba, // wif +// 0x17, // version +// "2017-03-21T13:00:00.000Z" // epoch +// }; + +#endif diff --git a/src/stl/array b/src/stl/array deleted file mode 100644 index 59d741d6..00000000 --- a/src/stl/array +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef __ARRAY__ -#define __ARRAY__ - -namespace std { - -template -class array { - public: - typedef T value_type; - typedef T* pointer; - typedef const T* const_pointer; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef pointer iterator; - typedef const_pointer const_iterator; - typedef size_t size_type; - - private: - value_type _data[N ? N : 1]; - - public: - array() = default; - array& operator=(const array& other) = default; - - reference operator[](size_type i) { return _data[i]; } - const_reference operator[](size_type i) const { return _data[i]; } - reference front() { return _data[0]; } - const_reference front() const { return _data[0]; } - reference back() { return _data[N - 1]; } - const_reference back() const { return _data[N - 1]; } - pointer data() noexcept { return _data; } - const_pointer data() const noexcept { return _data; } - - iterator begin() noexcept { return _data; } - const_iterator begin() const noexcept { return _data; } - const_iterator cbegin() const noexcept { return _data; } - iterator end() noexcept { return _data + N; } - const_iterator end() const noexcept { return _data + N; } - const_iterator cend() const noexcept { return _data + N; } - - bool empty() const noexcept { return begin() == end(); } - size_type size() const noexcept { return N; } - size_type max_size() const noexcept { return N; } - - void fill(const_reference value) { - for (auto i = 0u; i < N; ++i) { - _data[i] = value; - } - } -}; - -} // namespace std - -#endif diff --git a/src/stl/cassert b/src/stl/cassert deleted file mode 100644 index 3e27dc73..00000000 --- a/src/stl/cassert +++ /dev/null @@ -1,4 +0,0 @@ -namespace std { - -#include -} diff --git a/src/stl/cctype b/src/stl/cctype deleted file mode 100644 index 24a602fe..00000000 --- a/src/stl/cctype +++ /dev/null @@ -1,4 +0,0 @@ -namespace std { - -#include -} diff --git a/src/stl/cstddef b/src/stl/cstddef deleted file mode 100644 index 640f294e..00000000 --- a/src/stl/cstddef +++ /dev/null @@ -1,4 +0,0 @@ -namespace std { - -#include -} diff --git a/src/stl/cstdint b/src/stl/cstdint deleted file mode 100644 index e3c1098a..00000000 --- a/src/stl/cstdint +++ /dev/null @@ -1,4 +0,0 @@ -namespace std { - -#include -} diff --git a/src/stl/cstdio b/src/stl/cstdio deleted file mode 100644 index d6da5ec5..00000000 --- a/src/stl/cstdio +++ /dev/null @@ -1,4 +0,0 @@ -namespace std { - -#include -} diff --git a/src/stl/cstring b/src/stl/cstring deleted file mode 100644 index 49ec72cd..00000000 --- a/src/stl/cstring +++ /dev/null @@ -1,4 +0,0 @@ -namespace std { - -#include -} diff --git a/src/stl/details/to_string.h b/src/stl/details/to_string.h deleted file mode 100644 index 2c747bd4..00000000 --- a/src/stl/details/to_string.h +++ /dev/null @@ -1,171 +0,0 @@ -#ifndef ARDUINO_STL_DETAILS_TO_STRING_H -#define ARDUINO_STL_DETAILS_TO_STRING_H - -#include -#include -#include -#include - -namespace std { - -inline std::string to_string(int value) { - char buf[24] = {}; - snprintf(buf, sizeof(buf), "%d", value); - return buf; -} -inline std::string to_string(long value) { - char buf[24] = {}; - snprintf(buf, sizeof(buf), "%ld", value); - return buf; -} -inline std::string to_string(long long value) { - char buf[24] = {}; - snprintf(buf, sizeof(buf), "%lld", value); - return buf; -} -inline std::string to_string(unsigned value) { - char buf[24] = {}; - snprintf(buf, sizeof(buf), "%u", value); - return buf; -} -inline std::string to_string(unsigned long value) { - char buf[24] = {}; - snprintf(buf, sizeof(buf), "%lu", value); - return buf; -} -inline std::string to_string(unsigned long long value) { - char buf[24] = {}; - snprintf(buf, sizeof(buf), "%llu", value); - return buf; -} -inline std::string to_string(float value) { - char buf[24] = {}; - snprintf(buf, sizeof(buf), "%f", value); - return buf; -} -inline std::string to_string(double value) { - char buf[24] = {}; - snprintf(buf, sizeof(buf), "%lf", value); - return buf; -} -inline std::string to_string(long double value) { - char buf[24] = {}; - snprintf(buf, sizeof(buf), "%Lf", value); - return buf; -} - -inline float stof(const std::string& str, std::size_t* pos = 0) { - char* end = nullptr; - auto ret = strtof(str.c_str(), &end); - if (pos != nullptr) { - *pos = end - str.c_str(); - } - return ret; -} -inline double stod(const std::string& str, std::size_t* pos = 0) { - char* end = nullptr; - auto ret = strtod(str.c_str(), &end); - if (pos != nullptr) { - *pos = end - str.c_str(); - } - return ret; -} -inline long double stold(const std::string& str, std::size_t* pos = 0) { - char* end = nullptr; - auto ret = strtold(str.c_str(), &end); - if (pos != nullptr) { - *pos = end - str.c_str(); - } - return ret; -} - -inline int stoi(const std::string& str, std::size_t* pos = 0, int base = 10) { - char* end = nullptr; - auto ret = strtol(str.c_str(), &end, base); - if (pos != nullptr) { - *pos = end - str.c_str(); - } - return static_cast(ret); -} -inline long stol(const std::string& str, std::size_t* pos = 0, int base = 10) { - char* end = nullptr; - auto ret = strtol(str.c_str(), &end, base); - if (pos != nullptr) { - *pos = end - str.c_str(); - } - return ret; -} -inline long long stoll(const std::string& str, std::size_t* pos = 0, int base = 10) { - char* end = nullptr; - auto ret = strtoll(str.c_str(), &end, base); - if (pos != nullptr) { - *pos = end - str.c_str(); - } - return ret; -} - -inline unsigned long stoul(const std::string& str, std::size_t* pos = 0, int base = 10) { - char* end = nullptr; - auto ret = strtoul(str.c_str(), &end, base); - if (pos != nullptr) { - *pos = end - str.c_str(); - } - return ret; -} -inline unsigned long long stoull(const std::string& str, std::size_t* pos = 0, int base = 10) { - char* end = nullptr; - auto ret = strtoull(str.c_str(), &end, base); - if (pos != nullptr) { - *pos = end - str.c_str(); - } - return ret; -} - -inline std::wstring to_wstring(int value) { - wchar_t buf[24] = {}; - swprintf(buf, sizeof(buf), L"%d", value); - return buf; -} -inline std::wstring to_wstring(long value) { - wchar_t buf[24] = {}; - swprintf(buf, sizeof(buf), L"%ld", value); - return buf; -} -inline std::wstring to_wstring(long long value) { - wchar_t buf[24] = {}; - swprintf(buf, sizeof(buf), L"%lld", value); - return buf; -} -inline std::wstring to_wstring(unsigned value) { - wchar_t buf[24] = {}; - swprintf(buf, sizeof(buf), L"%u", value); - return buf; -} -inline std::wstring to_wstring(unsigned long value) { - wchar_t buf[24] = {}; - swprintf(buf, sizeof(buf), L"%lu", value); - return buf; -} -inline std::wstring to_wstring(unsigned long long value) { - wchar_t buf[24] = {}; - swprintf(buf, sizeof(buf), L"%llu", value); - return buf; -} -inline std::wstring to_wstring(float value) { - wchar_t buf[24] = {}; - swprintf(buf, sizeof(buf), L"%f", value); - return buf; -} -inline std::wstring to_wstring(double value) { - wchar_t buf[24] = {}; - swprintf(buf, sizeof(buf), L"%lf", value); - return buf; -} -inline std::wstring to_wstring(long double value) { - wchar_t buf[24] = {}; - swprintf(buf, sizeof(buf), L"%Lf", value); - return buf; -} -} // namespace std - -#endif diff --git a/src/stl/memory b/src/stl/memory deleted file mode 100644 index 8047c6eb..00000000 --- a/src/stl/memory +++ /dev/null @@ -1,128 +0,0 @@ -#ifndef __MEMORY__ -#define __MEMORY__ - -#include - -namespace std { - -template -struct default_delete { - default_delete() {} - - template - default_delete(const default_delete&) {} - - void operator()(T* ptr) const { delete ptr; } -}; - -template -struct default_delete { - void operator()(T* ptr) const { delete[] ptr; } -}; - -template > -class unique_ptr { - typedef T* pointer; - typedef T& reference; - - private: - pointer _p; - bool _own; - - public: - constexpr unique_ptr() noexcept : _p(nullptr), _own(false) {} - - explicit unique_ptr(pointer p) : _p(p), _own(true) {} - - template - explicit unique_ptr(U u) : _p(u), _own(true) {} - - unique_ptr(unique_ptr&& other) : _p(other._p), _own(other._own) { - other._p = nullptr; - other._own = false; - } - - unique_ptr& operator=(unique_ptr&& other) { - if (this != &other) { - _p = other._p; - _own = other._own; - - other._p = nullptr; - other._own = false; - } - return *this; - } - - ~unique_ptr() { reset(); } - - pointer get() const noexcept { return _p; } - pointer release() noexcept { - _own = false; - return _p; - } - void reset(pointer p = pointer()) noexcept { - D d; - d(_p); - _p = p; - _own = true; - } - - explicit operator bool() const noexcept { return _p != nullptr; } - reference operator*() const { return *_p; } - pointer operator->() const noexcept { return _p; } -}; - -template -class unique_ptr { - typedef T* pointer; - typedef T& reference; - - private: - pointer _p; - bool _own; - - public: - constexpr unique_ptr() noexcept : _p(nullptr), _own(false) {} - - explicit unique_ptr(pointer p) : _p(p), _own(true) {} - - template - explicit unique_ptr(U u) : _p(u), _own(true) {} - - unique_ptr(unique_ptr&& other) : _p(other._p), _own(other._own) { - other._p = nullptr; - other._own = false; - } - - unique_ptr& operator=(unique_ptr&& other) { - if (this != &other) { - _p = other._p; - _own = other._own; - - other._p = nullptr; - other._own = false; - } - return *this; - } - - ~unique_ptr() { reset(); } - - pointer get() const noexcept { return _p; } - pointer release() noexcept { - _own = false; - return _p; - } - void reset(pointer p = pointer()) noexcept { - D d; - d(_p); - _p = p; - _own = true; - } - - explicit operator bool() const noexcept { return _p != nullptr; } - reference operator[](size_t i) const { return _p[i]; } -}; - -} // namespace std - -#endif diff --git a/src/transactions/builder.cpp b/src/transactions/builder.cpp index 9f1736d4..0fd24617 100644 --- a/src/transactions/builder.cpp +++ b/src/transactions/builder.cpp @@ -1,84 +1,148 @@ + #include "transactions/builder.h" -#include "configuration/fee.h" -#include "configuration/network.h" -#include "enums/types.h" -#include "helpers/crypto_helpers.h" + +#include +#include +#include +#include + +#include "common/configuration.hpp" +#include "defaults/transaction_types.hpp" #include "identities/address.h" #include "utils/slot.h" +#include "helpers/crypto_helpers.h" namespace Ark { namespace Crypto { namespace Transactions { -Transaction Builder::buildTransfer(std::string recipientId, uint64_t amount, std::string vendorField, - std::string passphrase, std::string secondPassphrase) { +Transaction Builder::buildTransfer( + std::string recipientId, + uint64_t amount, + std::string vendorField, + std::string passphrase, + std::string secondPassphrase, + const Configuration& configuration) { Transaction transaction; - transaction.type = Enums::Types::TRANSFER; - transaction.fee = Configuration::Fee().get(Enums::Types::TRANSFER); + if (amount < 1ULL) { return transaction; } + + transaction.type = defaults::TransactionTypes::Transfer; + transaction.fee = configuration.getFee(defaults::TransactionTypes::Transfer); transaction.recipientId = std::move(recipientId); - transaction.amount = std::move(amount); + transaction.amount = amount; transaction.vendorField = std::move(vendorField); - return sign(transaction, std::move(passphrase), std::move(secondPassphrase)); + return sign( + transaction, + std::move(passphrase), + std::move(secondPassphrase)); } -Transaction Builder::buildSecondSignatureRegistration(std::string passphrase, std::string secondPassphrase) { +/**/ + +Transaction Builder::buildSecondSignatureRegistration( + std::string passphrase, + std::string secondPassphrase, + const Configuration& configuration) { Transaction transaction; - transaction.type = Enums::Types::SECOND_SIGNATURE_REGISTRATION; - transaction.fee = Configuration::Fee().get(Enums::Types::SECOND_SIGNATURE_REGISTRATION); + transaction.type = defaults::TransactionTypes::SecondSignatureRegistration; + transaction.fee = configuration.getFee( + defaults::TransactionTypes::SecondSignatureRegistration); - const auto publicKey = Identities::PublicKey::fromPassphrase(secondPassphrase.c_str()); + const auto publicKey = Identities::PublicKey::fromPassphrase( + secondPassphrase.c_str()); transaction.asset.signature.publicKey = publicKey.toString(); - return sign(transaction, std::move(passphrase), secondPassphrase); + return sign( + transaction, + std::move(passphrase), + std::move(secondPassphrase)); } -Transaction Builder::buildDelegateRegistration(std::string username, std::string passphrase, - std::string secondPassphrase) { +/**/ + +Transaction Builder::buildDelegateRegistration( + std::string username, + std::string passphrase, + std::string secondPassphrase, + const Configuration& configuration) { Transaction transaction; - transaction.type = Enums::Types::DELEGATE_REGISTRATION; - transaction.fee = Configuration::Fee().get(Enums::Types::DELEGATE_REGISTRATION); + transaction.type = defaults::TransactionTypes::DelegateRegistration; + transaction.fee = configuration.getFee( + defaults::TransactionTypes::DelegateRegistration); transaction.asset.delegate.username = std::move(username); - return sign(transaction, std::move(passphrase), std::move(secondPassphrase)); + return sign( + transaction, + std::move(passphrase), + std::move(secondPassphrase)); } -Transaction Builder::buildVote(std::vector votes, std::string passphrase, std::string secondPassphrase) { +/**/ + +Transaction Builder::buildVote( + std::vector votes, + std::string passphrase, + std::string secondPassphrase, + const Configuration& configuration) { Transaction transaction; - transaction.type = Enums::Types::VOTE; - transaction.fee = Configuration::Fee().get(Enums::Types::VOTE); + transaction.type = defaults::TransactionTypes::Vote; + transaction.fee = configuration.getFee(defaults::TransactionTypes::Vote); transaction.asset.votes = std::move(votes); - const auto recipient = - Identities::Address::fromPassphrase(passphrase.c_str(), Configuration::Network().get().version()); + const auto recipient = Identities::Address::fromPassphrase( + passphrase.c_str(), + configuration.getNetwork().version()); transaction.recipientId = recipient.toString(); - return sign(transaction, passphrase, std::move(secondPassphrase)); + return sign(transaction, + std::move(passphrase), + std::move(secondPassphrase)); } -Transaction Builder::buildMultiSignatureRegistration(uint8_t min, uint8_t lifetime, std::vector keysgroup, - std::string passphrase, std::string secondPassphrase) { +/**/ + +Transaction Builder::buildMultiSignatureRegistration( + uint8_t min, + uint8_t lifetime, + std::vector& keysgroup, + std::string passphrase, + std::string secondPassphrase, + const Configuration& configuration) { Transaction transaction; - transaction.type = Enums::Types::MULTI_SIGNATURE_REGISTRATION; - transaction.fee = (keysgroup.size() + 1) * Configuration::Fee().get(Enums::Types::MULTI_SIGNATURE_REGISTRATION); + transaction.type = defaults::TransactionTypes::MultiSignatureRegistration; + transaction.fee = ( + keysgroup.size() + 1) + * configuration.getFee(defaults::TransactionTypes::MultiSignatureRegistration); transaction.asset.multiSignature.min = min; transaction.asset.multiSignature.lifetime = lifetime; transaction.asset.multiSignature.keysgroup = keysgroup; - const auto recipient = - Identities::Address::fromPassphrase(passphrase.c_str(), Configuration::Network().get().version()); + const auto recipient = Identities::Address::fromPassphrase( + passphrase.c_str(), + configuration.getNetwork().version()); transaction.recipientId = recipient.toString(); - return sign(transaction, passphrase, std::move(secondPassphrase)); + return sign( + transaction, + std::move(passphrase), + std::move(secondPassphrase)); } -Transaction Builder::sign(Transaction transaction, std::string passphrase, std::string secondPassphrase) { - transaction.timestamp = static_cast(Utils::Slot::time(Configuration::Network().get())); +/**/ + +Transaction Builder::sign( + Transaction transaction, + std::string passphrase, + std::string secondPassphrase, + const Configuration& configuration) { + transaction.timestamp = static_cast( + Utils::Slot::time(configuration.getNetwork())); transaction.sign(passphrase.c_str()); if (secondPassphrase.length() > 0) { transaction.secondSign(secondPassphrase.c_str()); - } + }; transaction.id = transaction.getId(); diff --git a/src/transactions/builder.h b/src/transactions/builder.h index 665a3469..4f3d02ff 100644 --- a/src/transactions/builder.h +++ b/src/transactions/builder.h @@ -10,32 +10,72 @@ #ifndef BUILDER_H #define BUILDER_H +#include +#include +#include + #include "transactions/transaction.h" +#include "common/configuration.hpp" namespace Ark { namespace Crypto { namespace Transactions { - +/**/ class Builder { - public: - static Transaction buildTransfer(std::string recipientId, uint64_t amount, std::string vendorField, - std::string passphrase, std::string secondPassphrase = ""); - static Transaction buildSecondSignatureRegistration(std::string passphrase, std::string secondPassphrase = ""); - static Transaction buildDelegateRegistration(std::string username, std::string passphrase, - std::string secondPassphrase = ""); - static Transaction buildVote(std::vector votes, std::string passphrase, - std::string secondPassphrase = ""); - static Transaction buildMultiSignatureRegistration(uint8_t min, uint8_t lifetime, std::vector keysgroup, - std::string passphrase, std::string secondPassphrase = ""); - - private: +public: + /** + * Builder::buildTransfer() + * + * note: The 'Type 0'/Transfer amount must be greater than 0 ARKtoshi. + * If amount is not > 0, Builder will return an empty Transaction object and + * validation will fail. + **/ + static Transaction buildTransfer( + std::string recipientId, + uint64_t amount, + std::string vendorField, + std::string passphrase, + std::string secondPassphrase = "", + const Configuration& configuration = {}); + /**/ + + static Transaction buildSecondSignatureRegistration( + std::string passphrase, + std::string secondPassphrase = "", + const Configuration& configuration = {}); + + static Transaction buildDelegateRegistration( + std::string username, + std::string passphrase, + std::string secondPassphrase = "", + const Configuration& configuration = {}); + + static Transaction buildVote( + std::vector votes, + std::string passphrase, + std::string secondPassphrase = "", + const Configuration& configuration = {}); + + static Transaction buildMultiSignatureRegistration( + uint8_t min, + uint8_t lifetime, + std::vector& keysgroup, + std::string passphrase, + std::string secondPassphrase = "", + const Configuration& configuration = {}); + +private: Builder(); - static Transaction sign(Transaction transaction, std::string passphrase, std::string secondPassphrase = ""); + static Transaction sign( + Transaction transaction, + std::string passphrase, + std::string secondPassphrase = "", + const Configuration& configuration = {}); Builder sign(const std::string& passphrase); - private: +private: void serializeVendorField(std::vector& bytes); void serializeType(std::vector& bytes); void serializeTransfer(std::vector& bytes); @@ -47,9 +87,9 @@ class Builder { Transaction _transaction; }; - -} // namespace Transactions -} // namespace Crypto -} // namespace Ark +/**/ +}; // namespace Transactions +}; // namespace Crypto +}; // namespace Ark #endif diff --git a/src/transactions/deserializer.cpp b/src/transactions/deserializer.cpp index 6a05c17d..e1576dee 100644 --- a/src/transactions/deserializer.cpp +++ b/src/transactions/deserializer.cpp @@ -1,19 +1,31 @@ + #include "transactions/deserializer.h" -#include "bcl/Sha256.hpp" -#include "enums/types.h" -#include "helpers/crypto.h" -#include "identities/address.h" #include +#include #include #include +#include +#include + +#include "defaults/transaction_types.hpp" +#include "identities/address.h" +#include "identities/privatekey.h" +#include "identities/publickey.h" +#include "helpers/crypto.h" +#include "helpers/crypto_helpers.h" +#include "helpers/encoding/hex.h" + +#include "bcl/Sha256.hpp" namespace Ark { namespace Crypto { namespace Transactions { Deserializer::Deserializer(const std::string& serialized) - : _serialized(serialized), _binary(HexToBytes(serialized.c_str())), _assetOffset(0) {} + : _serialized(serialized), + _binary(HexToBytes(serialized.c_str())), + _assetOffset(0) {} Transaction Deserializer::deserialize() { Transaction transaction; @@ -24,20 +36,24 @@ Transaction Deserializer::deserialize() { if (transaction.version == 1) { handleVersionOne(transaction); - } + }; return transaction; } +/**/ + void Deserializer::deserializeHeader(Transaction& transaction) { - unpack(&transaction.header, &this->_binary[0]); // 1 Byte - unpack(&transaction.version, &this->_binary[1]); // 1 Byte - unpack(&transaction.network, &this->_binary[2]); // 1 Byte - unpack(&transaction.type, &this->_binary[3]); // 1 Byte - unpack(&transaction.timestamp, &this->_binary[4]); // 4 Byte + unpack(&transaction.header, &this->_binary[0]); // 1 Byte + unpack(&transaction.version, &this->_binary[1]); // 1 Byte + unpack(&transaction.network, &this->_binary[2]); // 1 Byte + unpack(&transaction.type, &this->_binary[3]); // 1 Byte + unpack(&transaction.timestamp, &this->_binary[4]); // 4 Byte // 33 Byte - transaction.senderPublicKey = BytesToHex(this->_binary.begin() + 8, this->_binary.begin() + 33 + 8); + transaction.senderPublicKey = BytesToHex( + this->_binary.begin() + 8, + this->_binary.begin() + 33 + 8); unpack(&transaction.fee, &this->_binary[41]); // 8 Byte @@ -45,89 +61,103 @@ void Deserializer::deserializeHeader(Transaction& transaction) { uint8_t vendorFieldLength = 0; unpack(&vendorFieldLength, &this->_binary[49]); // 1 Byte if (vendorFieldLength > 0) { - transaction.vendorFieldHex = this->_serialized.substr(vendorFieldOffset, vendorFieldLength * 2); - } + transaction.vendorFieldHex = this->_serialized.substr( + vendorFieldOffset, + vendorFieldLength * 2); + }; _assetOffset = vendorFieldOffset + vendorFieldLength * 2; } -void Deserializer::deserializeType(Transaction& transaction) { +/**/ + +void Deserializer::deserializeType( + Transaction& transaction) { switch (transaction.type) { - case Enums::Types::TRANSFER: { + case defaults::TransactionTypes::Transfer: { deserializeTransfer(transaction); break; - } - case Enums::Types::SECOND_SIGNATURE_REGISTRATION: { + }; + case defaults::TransactionTypes::SecondSignatureRegistration: { deserializeSecondSignatureRegistration(transaction); break; - } - case Enums::Types::DELEGATE_REGISTRATION: { + }; + case defaults::TransactionTypes::DelegateRegistration: { deserializeDelegateRegistration(transaction); break; - } - case Enums::Types::VOTE: { + }; + case defaults::TransactionTypes::Vote: { deserializeVote(transaction); break; - } - case Enums::Types::MULTI_SIGNATURE_REGISTRATION: { + }; + case defaults::TransactionTypes::MultiSignatureRegistration: { deserializeMultiSignatureRegistration(transaction); break; - } - case Enums::Types::IPFS: { - break; - } - case Enums::Types::TIMELOCK_TRANSFER: { - break; - } - case Enums::Types::MULTI_PAYMENT: { - break; - } - case Enums::Types::DELEGATE_RESIGNATION: { - break; - } - } + }; + case defaults::TransactionTypes::Ipfs: { break; }; + case defaults::TransactionTypes::TimelockTransfer: { break; }; + case defaults::TransactionTypes::MultiPayment: { break; }; + case defaults::TransactionTypes::DelegateResignation: { break; }; + }; } -void Deserializer::deserializeTransfer(Transaction& transaction) { +/**/ + +void Deserializer::deserializeTransfer( + Transaction& transaction) { unpack(&transaction.amount, &this->_binary[_assetOffset / 2]); unpack(&transaction.expiration, &this->_binary[_assetOffset / 2 + 8]); - transaction.recipientId = Identities::Address::base58encode(&this->_binary[(_assetOffset / 2) + 12]); + transaction.recipientId = Identities::Address::base58encode( + &this->_binary[(_assetOffset / 2) + 12]); _assetOffset += (8 + 4 + 21) * 2; -} +}; -void Deserializer::deserializeSecondSignatureRegistration(Transaction& transaction) { - transaction.asset.signature.publicKey = this->_serialized.substr(_assetOffset, 66); +void Deserializer::deserializeSecondSignatureRegistration( + Transaction& transaction) { + transaction.asset.signature.publicKey = this->_serialized.substr( + _assetOffset, + 66); _assetOffset += 66; -} +}; -void Deserializer::deserializeDelegateRegistration(Transaction& transaction) { +void Deserializer::deserializeDelegateRegistration( + Transaction& transaction) { uint8_t usernameLength = 0; unpack(&usernameLength, &this->_binary[_assetOffset / 2]); usernameLength &= 0xff; - std::string username = this->_serialized.substr((_assetOffset / 2 + 1) * 2, usernameLength * 2); - std::vector bytes = HexToBytes(username.c_str()); - transaction.asset.delegate.username = std::string(bytes.begin(), bytes.end()); + std::string username = this->_serialized.substr( + (_assetOffset / 2 + 1) * 2, usernameLength * 2); + std::vector bytes = HexToBytes(username.c_str()); + transaction.asset.delegate.username = std::string( + bytes.begin(), + bytes.end()); _assetOffset += (usernameLength + 1) * 2; -} +}; -void Deserializer::deserializeVote(Transaction& transaction) { +void Deserializer::deserializeVote( + Transaction& transaction) { uint8_t voteLength = 0; unpack(&voteLength, &this->_binary[_assetOffset / 2]); voteLength &= 0xff; for (uint8_t i = 0; i < voteLength; i++) { - std::string vote = this->_serialized.substr(_assetOffset + 2 + i * 2 * 32, 68); + std::string vote = this->_serialized.substr( + _assetOffset + 2 + i * 2 * 32, + 68); vote = (vote[1] == '1' ? "+" : "-") + vote.substr(2); transaction.asset.votes.push_back(vote); - } + }; _assetOffset += 2 + voteLength * 34 * 2; } -void Deserializer::deserializeMultiSignatureRegistration(Transaction& transaction) { +/**/ + +void Deserializer::deserializeMultiSignatureRegistration( + Transaction& transaction) { uint8_t min = 0; unpack(&min, &this->_binary[_assetOffset / 2]); min &= 0xff; @@ -144,85 +174,114 @@ void Deserializer::deserializeMultiSignatureRegistration(Transaction& transactio transaction.asset.multiSignature.lifetime = lifetime; for (uint8_t i = 0; i < count; i++) { - std::string key = this->_serialized.substr(_assetOffset + 6 + i * 66, 66); + std::string key = this->_serialized.substr( + _assetOffset + 6 + i * 66, + 66); transaction.asset.multiSignature.keysgroup.push_back(key); - } + }; _assetOffset += 6 + count * 66; } +/**/ + static uint8_t parseSignatureLength(const std::string& hex) { - assert(hex.length() <= 2); + if (hex.length() > 2) { return 0; }; unsigned int length; sscanf(hex.c_str(), "%x", &length); return static_cast(length + 2); } -void Deserializer::deserializeSignatures(Transaction& transaction) { +/**/ + +void Deserializer::deserializeSignatures( + Transaction& transaction) { std::string signature = this->_serialized.substr(_assetOffset); size_t multiSignatureOffset = 0; if (!signature.empty()) { size_t signatureLength = parseSignatureLength(signature.substr(2, 2)); - transaction.signature = this->_serialized.substr(_assetOffset, signatureLength * 2); + transaction.signature = this->_serialized.substr( + _assetOffset, + signatureLength * 2); multiSignatureOffset += signatureLength * 2; - transaction.secondSignature = this->_serialized.substr((_assetOffset + signatureLength * 2)); + transaction.secondSignature = this->_serialized.substr( + (_assetOffset + signatureLength * 2)); if (!transaction.secondSignature.empty()) { if (transaction.secondSignature.substr(0, 2) == "ff") { transaction.secondSignature = ""; } else { - size_t secondSignatureLength = parseSignatureLength(transaction.secondSignature.substr(2, 2)); - transaction.secondSignature = transaction.secondSignature.substr(0, secondSignatureLength * 2); + size_t secondSignatureLength = parseSignatureLength( + transaction.secondSignature.substr(2, 2)); + transaction.secondSignature = transaction.secondSignature.substr( + 0, + secondSignatureLength * 2); multiSignatureOffset += secondSignatureLength * 2; - } - } + }; + }; - std::string signatures = this->_serialized.substr(_assetOffset + multiSignatureOffset); + std::string signatures = this->_serialized.substr( + _assetOffset + multiSignatureOffset); if (!signatures.empty() && signatures.substr(0, 2) == "ff") { signatures = signatures.substr(2); while (!signatures.empty()) { - size_t multiSignatureLength = parseSignatureLength(signatures.substr(2, 2)); + size_t multiSignatureLength = parseSignatureLength( + signatures.substr(2, 2)); if (multiSignatureLength > 0) { - transaction.signatures.push_back(signatures.substr(0, multiSignatureLength * 2)); - } + transaction.signatures.push_back( + signatures.substr(0, + multiSignatureLength * 2)); + }; signatures = signatures.substr(multiSignatureLength * 2); - } - } - } + }; + }; + }; } -void Deserializer::handleVersionOne(Transaction& transaction) { +/**/ + +void Deserializer::handleVersionOne( + Transaction& transaction) { transaction.signSignature = transaction.secondSignature; - if (transaction.type == Enums::Types::VOTE) { - const auto publicKey = Identities::PublicKey::fromHex(transaction.senderPublicKey.c_str()); - const auto address = Identities::Address::fromPublicKey(publicKey, transaction.network); + if (transaction.type == defaults::TransactionTypes::Vote) { + const auto publicKey = Identities::PublicKey::fromHex( + transaction.senderPublicKey.c_str()); + const auto address = Identities::Address::fromPublicKey( + publicKey, + transaction.network); transaction.recipientId = address.toString(); - } + }; - if (transaction.type == Enums::Types::MULTI_SIGNATURE_REGISTRATION) { - std::for_each(transaction.asset.multiSignature.keysgroup.begin(), transaction.asset.multiSignature.keysgroup.end(), - [](std::string& key) { key.insert(0, "+"); }); - } + if (transaction.type == defaults::TransactionTypes::MultiSignatureRegistration) { + std::for_each( + transaction.asset.multiSignature.keysgroup.begin(), + transaction.asset.multiSignature.keysgroup.end(), + [](std::string& key) { key.insert(0, "+"); } + ); + }; if (!transaction.vendorFieldHex.empty()) { const auto bytes = HexToBytes(transaction.vendorFieldHex.c_str()); transaction.vendorField = std::string(bytes.begin(), bytes.end()); - } + }; if (transaction.id.empty()) { transaction.id = transaction.getId(); - } - - if (transaction.type == Enums::Types::SECOND_SIGNATURE_REGISTRATION || - transaction.type == Enums::Types::MULTI_SIGNATURE_REGISTRATION) { - const auto publicKey = Identities::PublicKey::fromHex(transaction.senderPublicKey.c_str()); - const auto address = Identities::Address::fromPublicKey(publicKey, transaction.network); + }; + + if (transaction.type == defaults::TransactionTypes::SecondSignatureRegistration + || transaction.type == defaults::TransactionTypes::MultiSignatureRegistration) { + const auto publicKey = Identities::PublicKey::fromHex( + transaction.senderPublicKey.c_str()); + const auto address = Identities::Address::fromPublicKey( + publicKey, + transaction.network); transaction.recipientId = address.toString(); - } + }; } } // namespace Transactions diff --git a/src/transactions/deserializer.h b/src/transactions/deserializer.h index 869b2f54..ccaf217d 100644 --- a/src/transactions/deserializer.h +++ b/src/transactions/deserializer.h @@ -10,22 +10,22 @@ #ifndef DESERIALIZER_H #define DESERIALIZER_H -#include "helpers/encoding/hex.h" -#include "helpers/crypto_helpers.h" -#include "identities/privatekey.h" -#include "identities/publickey.h" #include "transactions/transaction.h" +#include +#include +#include + namespace Ark { namespace Crypto { namespace Transactions { - +/**/ class Deserializer { - public: +public: Deserializer(const std::string& serialized); Transaction deserialize(); - private: +private: void deserializeHeader(Transaction& transaction); void deserializeType(Transaction& transaction); void deserializeTransfer(Transaction& transaction); @@ -44,9 +44,9 @@ class Deserializer { std::vector _binary; uint32_t _assetOffset; }; - -} // namespace Transactions -} // namespace Crypto -} // namespace Ark +/**/ +}; // namespace Transactions +}; // namespace Crypto +}; // namespace Ark #endif diff --git a/src/transactions/serializer.cpp b/src/transactions/serializer.cpp index e3e4b519..7aaa78ca 100644 --- a/src/transactions/serializer.cpp +++ b/src/transactions/serializer.cpp @@ -1,27 +1,45 @@ + #include "transactions/serializer.h" -#include "configuration/network.h" -#include "enums/types.h" -#include "helpers/crypto_helpers.h" + +#include +#include +#include + +#include "common/configuration.hpp" +#include "defaults/transaction_types.hpp" #include "identities/address.h" +#include "helpers/crypto_helpers.h" +#include "helpers/encoding/hex.h" namespace Ark { namespace Crypto { namespace Transactions { // TODO: remove class ? -Serializer::Serializer(const Transaction& transaction) : _transaction(transaction) {} +Serializer::Serializer(Transaction transaction) + : _transaction(std::move(transaction)) {} std::string Serializer::serialize() { std::vector bytes; bytes.push_back(0xff); - bytes.push_back(_transaction.version > 0 ? _transaction.version : 0x01); - bytes.push_back(_transaction.network > 0 ? _transaction.network : Configuration::Network().get().version()); + bytes.push_back( + _transaction.version > 0 + ? _transaction.version + : 0x01); + bytes.push_back( + _transaction.network > 0 + ? _transaction.network + : Configuration().getNetwork().version()); bytes.push_back(_transaction.type); pack(bytes, _transaction.timestamp); - std::vector senderPublicKeyBytes = HexToBytes(_transaction.senderPublicKey.c_str()); - bytes.insert(bytes.end(), senderPublicKeyBytes.begin(), senderPublicKeyBytes.end()); + std::vector senderPublicKeyBytes = HexToBytes( + _transaction.senderPublicKey.c_str()); + bytes.insert( + bytes.end(), + senderPublicKeyBytes.begin(), + senderPublicKeyBytes.end()); pack(bytes, _transaction.fee); @@ -32,129 +50,186 @@ std::string Serializer::serialize() { return BytesToHex(bytes); } -void Serializer::serializeVendorField(std::vector& bytes) { +/**/ + +void Serializer::serializeVendorField( + std::vector& bytes) { if (_transaction.vendorField.length() > 0) { - auto vendorFieldLength = static_cast(_transaction.vendorField.length()); + auto vendorFieldLength = static_cast( + _transaction.vendorField.length()); bytes.push_back(vendorFieldLength); - bytes.insert(bytes.end(), std::begin(_transaction.vendorField), std::end(_transaction.vendorField)); - + bytes.insert( + bytes.end(), + std::begin(_transaction.vendorField), + std::end(_transaction.vendorField)); } else if (_transaction.vendorFieldHex.length() > 0) { - auto vendorFieldHexLength = static_cast(_transaction.vendorFieldHex.length() / 2); + auto vendorFieldHexLength = static_cast( + _transaction.vendorFieldHex.length() / 2); bytes.push_back(vendorFieldHexLength); - bytes.insert(bytes.end(), std::begin(_transaction.vendorFieldHex), std::end(_transaction.vendorFieldHex)); + bytes.insert( + bytes.end(), + std::begin(_transaction.vendorFieldHex), + std::end(_transaction.vendorFieldHex)); } else { bytes.push_back(0x00); - } + }; } -void Serializer::serializeType(std::vector& bytes) { +/**/ + +void Serializer::serializeType( + std::vector& bytes) { switch (_transaction.type) { - case Enums::Types::TRANSFER: { + case defaults::TransactionTypes::Transfer: { serializeTransfer(bytes); break; - } - case Enums::Types::SECOND_SIGNATURE_REGISTRATION: { + }; + case defaults::TransactionTypes::SecondSignatureRegistration: { serializeSecondSignatureRegistration(bytes); break; - } - case Enums::Types::DELEGATE_REGISTRATION: { + }; + case defaults::TransactionTypes::DelegateRegistration: { serializeDelegateRegistration(bytes); break; - } - case Enums::Types::VOTE: { + }; + case defaults::TransactionTypes::Vote: { serializeVote(bytes); break; - } - case Enums::Types::MULTI_SIGNATURE_REGISTRATION: { + }; + case defaults::TransactionTypes::MultiSignatureRegistration: { serializeMultiSignatureRegistration(bytes); break; - } - case Enums::Types::IPFS: { - break; - } - case Enums::Types::TIMELOCK_TRANSFER: { - break; - } - case Enums::Types::MULTI_PAYMENT: { - break; - } - case Enums::Types::DELEGATE_RESIGNATION: { - break; - } - } + }; + case defaults::TransactionTypes::Ipfs: { break; }; + case defaults::TransactionTypes::TimelockTransfer: { break; }; + case defaults::TransactionTypes::MultiPayment: { break; }; + case defaults::TransactionTypes::DelegateResignation: { break; }; + }; } -void Serializer::serializeTransfer(std::vector& bytes) { +/**/ + +void Serializer::serializeTransfer( + std::vector& bytes) { pack(bytes, _transaction.amount); pack(bytes, _transaction.expiration); - std::vector recipientIdBytes = Identities::Address::bytesFromBase58Check(_transaction.recipientId.c_str()); - bytes.insert(bytes.end(), recipientIdBytes.begin(), recipientIdBytes.end()); + std::vector recipientIdBytes = Identities::Address::bytesFromBase58Check( + _transaction.recipientId.c_str()); + bytes.insert( + bytes.end(), + recipientIdBytes.begin(), + recipientIdBytes.end()); } -void Serializer::serializeSecondSignatureRegistration(std::vector& bytes) { - std::vector publicKeyBytes = HexToBytes(_transaction.asset.signature.publicKey.c_str()); - bytes.insert(bytes.end(), publicKeyBytes.begin(), publicKeyBytes.end()); +/**/ + +void Serializer::serializeSecondSignatureRegistration( + std::vector& bytes) { + std::vector publicKeyBytes = HexToBytes( + _transaction.asset.signature.publicKey.c_str()); + bytes.insert( + bytes.end(), + publicKeyBytes.begin(), + publicKeyBytes.end()); } -void Serializer::serializeDelegateRegistration(std::vector& bytes) { +/**/ + +void Serializer::serializeDelegateRegistration( + std::vector& bytes) { const auto username = _transaction.asset.delegate.username; bytes.push_back(static_cast(username.size())); - bytes.insert(bytes.end(), username.begin(), username.end()); + bytes.insert( + bytes.end(), + username.begin(), + username.end()); } -void Serializer::serializeVote(std::vector& bytes) { +/**/ + +void Serializer::serializeVote( + std::vector& bytes) { std::string votes; for (const auto& vote : _transaction.asset.votes) { votes += (vote[0] == '+' ? "01" : "00") + vote.substr(1); - } + }; std::vector voteBytes = HexToBytes(votes.c_str()); - bytes.push_back(static_cast(_transaction.asset.votes.size())); - bytes.insert(bytes.end(), voteBytes.begin(), voteBytes.end()); + bytes.push_back(static_cast( + _transaction.asset.votes.size())); + bytes.insert( + bytes.end(), + voteBytes.begin(), + voteBytes.end()); } -void Serializer::serializeMultiSignatureRegistration(std::vector& bytes) { +/**/ + +void Serializer::serializeMultiSignatureRegistration( + std::vector& bytes) { std::string keysgroup; if (_transaction.version == 1) { for (const auto& kg : _transaction.asset.multiSignature.keysgroup) { keysgroup += kg.substr(1); - } + }; } else { keysgroup = join(_transaction.asset.multiSignature.keysgroup); - } + }; bytes.push_back(_transaction.asset.multiSignature.min); - bytes.push_back(static_cast(_transaction.asset.multiSignature.keysgroup.size())); + bytes.push_back(static_cast( + _transaction.asset.multiSignature.keysgroup.size())); bytes.push_back(_transaction.asset.multiSignature.lifetime); std::vector keysgroupBytes = HexToBytes(keysgroup.c_str()); - bytes.insert(bytes.end(), keysgroupBytes.begin(), keysgroupBytes.end()); + bytes.insert( + bytes.end(), + keysgroupBytes.begin(), + keysgroupBytes.end()); } -void Serializer::serializeSignatures(std::vector& bytes) { +/**/ + +void Serializer::serializeSignatures( + std::vector& bytes) { if (_transaction.signature.length() > 0) { - std::vector signatureBytes = HexToBytes(_transaction.signature.c_str()); - bytes.insert(bytes.end(), signatureBytes.begin(), signatureBytes.end()); - } + std::vector signatureBytes = HexToBytes( + _transaction.signature.c_str()); + bytes.insert( + bytes.end(), + signatureBytes.begin(), + signatureBytes.end()); + }; if (_transaction.secondSignature.length() > 0) { - std::vector secondSignatureBytes = HexToBytes(_transaction.secondSignature.c_str()); - bytes.insert(bytes.end(), secondSignatureBytes.begin(), secondSignatureBytes.end()); + std::vector secondSignatureBytes = HexToBytes( + _transaction.secondSignature.c_str()); + bytes.insert( + bytes.end(), + secondSignatureBytes.begin(), + secondSignatureBytes.end()); } else if (_transaction.signSignature.length() > 0) { - std::vector signSignatureBytes = HexToBytes(_transaction.signSignature.c_str()); - bytes.insert(bytes.end(), signSignatureBytes.begin(), signSignatureBytes.end()); - } + std::vector signSignatureBytes = HexToBytes( + _transaction.signSignature.c_str()); + bytes.insert( + bytes.end(), + signSignatureBytes.begin(), + signSignatureBytes.end()); + }; if (!_transaction.signatures.empty()) { bytes.push_back(0xff); std::string joined = join(_transaction.signatures); for (const auto& signature : _transaction.signatures) { std::vector signatureBytes = HexToBytes(signature.c_str()); - bytes.insert(bytes.end(), std::begin(signatureBytes), std::end(signatureBytes)); - } - } + bytes.insert( + bytes.end(), + std::begin(signatureBytes), + std::end(signatureBytes)); + }; + }; } } // namespace Transactions diff --git a/src/transactions/serializer.h b/src/transactions/serializer.h index e70c4282..b33994d5 100644 --- a/src/transactions/serializer.h +++ b/src/transactions/serializer.h @@ -12,16 +12,20 @@ #include "transactions/transaction.h" +#include +#include +#include + namespace Ark { namespace Crypto { namespace Transactions { - +/**/ class Serializer { - public: - Serializer(const Transaction& transaction); +public: + Serializer(Transaction transaction); std::string serialize(); - private: +private: void serializeVendorField(std::vector& bytes); void serializeType(std::vector& bytes); void serializeTransfer(std::vector& bytes); @@ -33,7 +37,7 @@ class Serializer { Transaction _transaction; }; - +/**/ } // namespace Transactions } // namespace Crypto } // namespace Ark diff --git a/src/transactions/transaction.cpp b/src/transactions/transaction.cpp index fa022886..e0d95b00 100644 --- a/src/transactions/transaction.cpp +++ b/src/transactions/transaction.cpp @@ -1,28 +1,37 @@ + #include "transactions/transaction.h" -#include "bcl/Sha256.hpp" -#include "enums/types.h" + +#include +#include +#include +#include + +#include "defaults/transaction_types.hpp" +#include "identities/address.h" +#include "identities/privatekey.h" #include "helpers/crypto.h" #include "helpers/crypto_helpers.h" +#include "helpers/encoding/hex.h" #include "helpers/json.h" -#include "identities/address.h" -#include "identities/privatekey.h" -#include +#include "bcl/Sha256.hpp" using namespace Ark::Crypto::Identities; -Ark::Crypto::Transactions::Transaction::Transaction() {} - std::string Ark::Crypto::Transactions::Transaction::getId() const { auto bytes = this->toBytes(false, false); const auto shaHash = Sha256::getHash(&bytes[0], bytes.size()); - memcpy(&bytes[0], shaHash.value, shaHash.HASH_LEN); - return BytesToHex(&bytes[0], &bytes[0] + shaHash.HASH_LEN); + memcpy(&bytes[0], shaHash.value, Sha256Hash::HASH_LEN); + return BytesToHex(&bytes[0], &bytes[0] + Sha256Hash::HASH_LEN); } -std::string Ark::Crypto::Transactions::Transaction::sign(const char* passphrase) { +/**/ + +std::string Ark::Crypto::Transactions::Transaction::sign( + const char* passphrase) { PrivateKey privateKey = PrivateKey::fromPassphrase(passphrase); - this->senderPublicKey = Identities::PublicKey::fromPrivateKey(privateKey).toString(); + this->senderPublicKey = Identities::PublicKey::fromPrivateKey( + privateKey).toString(); const auto bytes = this->toBytes(); const auto hash = Sha256::getHash(&bytes[0], bytes.size()); @@ -34,7 +43,10 @@ std::string Ark::Crypto::Transactions::Transaction::sign(const char* passphrase) return this->signature; } -std::string Ark::Crypto::Transactions::Transaction::secondSign(const char* passphrase) { +/**/ + +std::string Ark::Crypto::Transactions::Transaction::secondSign( + const char* passphrase) { PrivateKey privateKey = PrivateKey::fromPassphrase(passphrase); const auto bytes = this->toBytes(false); const auto hash = Sha256::getHash(&bytes[0], bytes.size()); @@ -46,126 +58,203 @@ std::string Ark::Crypto::Transactions::Transaction::secondSign(const char* passp return this->secondSignature; } +/**/ + bool Ark::Crypto::Transactions::Transaction::verify() const { - return this->internalVerify(this->senderPublicKey, this->toBytes(), this->signature); + return this->internalVerify( + this->senderPublicKey, + this->toBytes(), + this->signature); } -bool Ark::Crypto::Transactions::Transaction::secondVerify(const char* secondPublicKey) const { - return this->internalVerify(secondPublicKey, this->toBytes(false), this->secondSignature); +/**/ + +bool Ark::Crypto::Transactions::Transaction::secondVerify( + const char* secondPublicKey) const { + std::string secondPublicKeyString = secondPublicKey; + return this->internalVerify( + secondPublicKeyString, + this->toBytes(false), + this->secondSignature); } +/**/ + bool Ark::Crypto::Transactions::Transaction::internalVerify( std::string publicKey, std::vector bytes, std::string signature) const { + if (bytes.empty()) { return false; }; + const auto hash = Sha256::getHash(&bytes[0], bytes.size()); const auto key = Identities::PublicKey::fromHex(publicKey.c_str()); auto signatureBytes = HexToBytes(signature.c_str()); + return cryptoVerify(key, hash, signatureBytes); } +/**/ + std::vector Ark::Crypto::Transactions::Transaction::toBytes( bool skipSignature, bool skipSecondSignature) const { std::vector bytes; + if (this->type == 0 && amount < 1ULL) { return bytes; }; + pack(bytes, this->type); pack(bytes, this->timestamp); - const auto senderKeyBytes = HexToBytes(this->senderPublicKey.c_str()); - bytes.insert(std::end(bytes), std::begin(senderKeyBytes), std::end(senderKeyBytes)); + const auto senderKeyBytes = HexToBytes( + this->senderPublicKey.c_str()); + bytes.insert( + std::end(bytes), + std::begin(senderKeyBytes), + std::end(senderKeyBytes)); - const auto skipRecipientId = type - == Enums::Types::SECOND_SIGNATURE_REGISTRATION - || type == Enums::Types::MULTI_SIGNATURE_REGISTRATION; + const auto skipRecipientId = + type == defaults::TransactionTypes::SecondSignatureRegistration + || type ==defaults::TransactionTypes::MultiSignatureRegistration; if (!this->recipientId.empty() && !skipRecipientId) { - std::vector recipientIdBytes = Address::bytesFromBase58Check(this->recipientId.c_str()); - bytes.insert(std::end(bytes), std::begin(recipientIdBytes), std::end(recipientIdBytes)); + std::vector recipientIdBytes = Address::bytesFromBase58Check( + this->recipientId.c_str()); + bytes.insert( + std::end(bytes), + std::begin(recipientIdBytes), + std::end(recipientIdBytes)); } else { std::vector filler(21, 0); - bytes.insert(std::end(bytes), std::begin(filler), std::end(filler)); - } - - if (!this->vendorField.empty()) { - bytes.insert(std::end(bytes), std::begin(this->vendorField), std::end(this->vendorField)); + bytes.insert( + std::end(bytes), + std::begin(filler), + std::end(filler)); + }; + if (!this->vendorField.empty() && vendorField.length() <= 255) { + bytes.insert( + std::end(bytes), + std::begin(this->vendorField), + std::end(this->vendorField)); size_t diff = 64 - vendorField.length(); if (diff > 0) { std::vector filler(diff, 0); - bytes.insert(std::end(bytes), std::begin(filler), std::end(filler)); - } - + bytes.insert( + std::end(bytes), + std::begin(filler), + std::end(filler)); + }; } else { std::vector filler(64, 0); - bytes.insert(std::end(bytes), std::begin(filler), std::end(filler)); - } + bytes.insert( + std::end(bytes), + std::begin(filler), + std::end(filler)); + }; pack(bytes, this->amount); pack(bytes, this->fee); - if (type == Enums::Types::SECOND_SIGNATURE_REGISTRATION) { - const auto publicKeyBytes = HexToBytes(this->asset.signature.publicKey.c_str()); - bytes.insert(std::end(bytes), std::begin(publicKeyBytes), std::end(publicKeyBytes)); - - } else if (type == Enums::Types::DELEGATE_REGISTRATION) { - bytes.insert(std::end(bytes), std::begin(this->asset.delegate.username), std::end(this->asset.delegate.username)); - - } else if (type == Enums::Types::VOTE) { + if (type == defaults::TransactionTypes::SecondSignatureRegistration) { + // SECOND_SIGNATURE_REGISTRATION + const auto publicKeyBytes = HexToBytes( + this->asset.signature.publicKey.c_str()); + bytes.insert( + std::end(bytes), + std::begin(publicKeyBytes), + std::end(publicKeyBytes)); + } else if (type == defaults::TransactionTypes::DelegateRegistration) { + // DELEGATE_REGISTRATION + bytes.insert( + std::end(bytes), + std::begin(this->asset.delegate.username), + std::end(this->asset.delegate.username)); + } else if (type == defaults::TransactionTypes::Vote) { + // VOTE const auto joined = join(this->asset.votes); - bytes.insert(std::end(bytes), std::begin(joined), std::end(joined)); - - } else if (type == Enums::Types::MULTI_SIGNATURE_REGISTRATION) { + bytes.insert( + std::end(bytes), + std::begin(joined), + std::end(joined)); + } else if (type == defaults::TransactionTypes::MultiSignatureRegistration) { + // MULTI_SIGNATURE_REGISTRATION pack(bytes, this->asset.multiSignature.min); pack(bytes, this->asset.multiSignature.lifetime); const auto joined = join(this->asset.multiSignature.keysgroup); - bytes.insert(std::end(bytes), std::begin(joined), std::end(joined)); - } + bytes.insert( + std::end(bytes), + std::begin(joined), + std::end(joined)); + }; if (!skipSignature && !this->signature.empty()) { const auto signatureBytes = HexToBytes(this->signature.c_str()); - bytes.insert(std::end(bytes), std::begin(signatureBytes), std::end(signatureBytes)); - } + bytes.insert( + std::end(bytes), + std::begin(signatureBytes), + std::end(signatureBytes)); + }; if (!skipSecondSignature && !this->secondSignature.empty()) { - const auto secondSignatureBytes = HexToBytes(this->secondSignature.c_str()); - bytes.insert(std::end(bytes), std::begin(secondSignatureBytes), std::end(secondSignatureBytes)); - } + const auto secondSignatureBytes = HexToBytes( + this->secondSignature.c_str()); + bytes.insert( + std::end(bytes), + std::begin(secondSignatureBytes), + std::end(secondSignatureBytes)); + }; return bytes; } +/**/ + std::map Ark::Crypto::Transactions::Transaction::toArray() { // buffers for variable and non-string type-values. - char amount[24], assetName[16], assetValue[512], fee[24], network[8], signatures[512], timestamp[36], type[8], version[8]; + char amount[24]; + char assetName[16]; + char assetValue[512]; + char fee[24]; + char network[8]; + char signatures[512]; + char timestamp[36]; + char type[8]; + char version[8]; // Amount - sprintf(amount, "%llu", this->amount); + snprintf(amount, sizeof(amount), "%" PRIu64, this->amount); // Asset - if (this->type == 0) { // Transfer - //do nothing - } else if (this->type == 1) { // Second Signature Registration - - strcpy(assetName, "publicKey"); - strcpy(assetValue, this->asset.signature.publicKey.c_str()); - - } else if (this->type == 2) { // Delegate Registration - - strcpy(assetName, "username"); - strcpy(assetValue, this->asset.delegate.username.c_str()); - - } else if (this->type == 3) { // Vote - - strcpy(assetName, "votes"); - strcpy(assetValue, ""); + if (this->type == 0) { + // Transfer + // do nothing + } else if (this->type == 1) { + // Second Signature Registration + strncpy(assetName, "publicKey", sizeof(assetName)); + strncpy( + assetValue, + this->asset.signature.publicKey.c_str(), + this->asset.signature.publicKey.length() + 1); + } else if (this->type == 2) { + // Delegate Registration + strncpy(assetName, "username", sizeof(assetName)); + strncpy( + assetValue, + this->asset.delegate.username.c_str(), + this->asset.delegate.username.length() + 1); + } else if (this->type == 3) { + // Vote + strncpy(assetName, "votes", sizeof(assetName)); + strncpy(assetValue, "", 1); for (unsigned int i = 0; i < this->asset.votes.size(); ++i) { - strcat(assetValue, this->asset.votes[i].c_str()); - + strncat( + assetValue, + this->asset.votes[i].c_str(), + this->asset.votes[i].length() + 1); if (i < this->asset.votes.size() - 1) { - strcat(assetValue, ","); - } - } + strncat(assetValue, ",", 1); + }; + }; // } else if (this->type == 4) { // Multisignature Registration // // TODO @@ -180,87 +269,88 @@ std::map Ark::Crypto::Transactions::Transaction::toArr }; // Fee - // fee << this->fee; - sprintf(fee, "%llu", this->fee); + snprintf(fee, sizeof(fee), "%" PRIu64, this->fee); // Signatures strcpy(signatures, ""); for (unsigned int i = 0; i < this->signatures.size(); ++i) { - strcat(signatures, this->signatures[i].c_str()); + strncat( + signatures, + this->signatures[i].c_str(), + this->signatures[i].length() + 1); if (i < this->signatures.size() - 1) { - strcpy(signatures, ","); - } - } + strncpy(signatures, ",", 1); + }; + }; // Network - sprintf(network, "%d", this->network); + snprintf(network, sizeof(network), "%d", this->network); // Timestamp - sprintf(timestamp, "%d", this->timestamp); + snprintf(timestamp, sizeof(timestamp), "%d", this->timestamp); // Type - sprintf(type, "%d", this->type); + snprintf(type, sizeof(type), "%u", this->type); // Version - sprintf(version, "%d", this->version); + snprintf(version, sizeof(version), "%d", this->version); return { - {"amount", amount}, - {assetName, assetValue}, - {"fee", fee}, - {"id", this->id}, - {"network", network}, - {"recipientId", this->recipientId}, - {"secondSignature", this->secondSignature}, - {"senderPublicKey", this->senderPublicKey}, - {"signature", this->signature}, - {"signatures", signatures}, - {"signSignature", this->signSignature}, - {"timestamp", timestamp}, - {"type", type}, - {"vendorField", this->vendorField}, - {"version", version} + { "amount", amount }, + { assetName, assetValue }, + { "fee", fee }, + { "id", this->id }, + { "network", network }, + { "recipientId", this->recipientId }, + { "secondSignature", this->secondSignature }, + { "senderPublicKey", this->senderPublicKey }, + { "signature", this->signature }, + { "signatures", signatures }, + { "signSignature", this->signSignature }, + { "timestamp", timestamp }, + { "type", type }, + { "vendorField", this->vendorField }, + { "version", version } }; } +/**/ + std::string Ark::Crypto::Transactions::Transaction::toJson() { std::map txArray = this->toArray(); - const size_t capacity = JSON_OBJECT_SIZE(15); - DynamicJsonBuffer jsonBuffer(capacity); - - JsonObject& root = jsonBuffer.createObject(); + const size_t docCapacity = 900; + DynamicJsonDocument doc(docCapacity); // Amount - root["amount"] = txArray["amount"]; + doc["amount"] = strtoull(txArray["amount"].c_str(), nullptr, 10); // Asset - if (this->type == 0) { // Transfer + if (this->type == 0) { + // Transfer //do nothing - } else if (this->type == 1) { // Second Signature Registration - - JsonObject& tAsset = root.createNestedObject("asset"); - JsonObject& signature = tAsset.createNestedObject("signature"); + } else if (this->type == 1) { + // Second Signature Registration + JsonObject tAsset = doc.createNestedObject("asset"); + JsonObject signature = tAsset.createNestedObject("signature"); signature["publicKey"] = txArray["publicKey"]; - - } else if (this->type == 2) { // Delegate Registration - - JsonObject& dAsset = root.createNestedObject("asset"); - JsonObject& delegate = dAsset.createNestedObject("delegate"); + } else if (this->type == 2) { + // Delegate Registration + JsonObject dAsset = doc.createNestedObject("asset"); + JsonObject delegate = dAsset.createNestedObject("delegate"); delegate["username"] = txArray["username"]; + } else if (this->type == 3) { + // Vote + JsonObject vAsset = doc.createNestedObject("asset"); + JsonArray votes = vAsset.createNestedArray("votes"); - }else if (this->type == 3) { // Vote - - JsonObject& vAsset = root.createNestedObject("asset"); - JsonArray& votes = vAsset.createNestedArray("votes"); - - std::string::size_type lastPos = txArray["votes"].find_first_not_of(",", 0); - std::string::size_type pos = txArray["votes"].find_first_of(",", lastPos); + std::string::size_type lastPos = txArray["votes"].find_first_not_of(',', 0); + std::string::size_type pos = txArray["votes"].find_first_of(',', lastPos); while (std::string::npos != pos || std::string::npos != lastPos) { votes.add(txArray["votes"].substr(lastPos, pos - lastPos)); - lastPos = txArray["votes"].find_first_not_of(",", pos); - pos = txArray["votes"].find_first_of(",", lastPos); - } + lastPos = txArray["votes"].find_first_not_of(',', pos); + pos = txArray["votes"].find_first_of(',', lastPos); + }; // } else if (this->type == 4) { // Multisignature Registration // // TODO @@ -275,65 +365,65 @@ std::string Ark::Crypto::Transactions::Transaction::toJson() { }; // Fee - root["fee"] = txArray["fee"]; + doc["fee"] = strtoull(txArray["fee"].c_str(), nullptr, 10); // Id - root["id"] = txArray["id"]; + doc["id"] = txArray["id"]; // Network if (txArray["network"] != "0") { - root["network"] = txArray["network"]; - } + doc["network"] = atoi(txArray["network"].c_str()); + }; // RecipientId - root["recipientId"] = txArray["recipientId"]; + doc["recipientId"] = txArray["recipientId"]; // SecondSignature if (std::strlen(txArray["secondSignature"].c_str()) > 0) { - root["secondSignature"] = txArray["secondSignature"]; - } + doc["secondSignature"] = txArray["secondSignature"]; + }; // SenderPublicKey - root["senderPublicKey"] = txArray["senderPublicKey"]; + doc["senderPublicKey"] = txArray["senderPublicKey"]; // Signature - root["signature"] = txArray["signature"]; + doc["signature"] = txArray["signature"]; // Signatures - if (this->signatures.size() > 0) { - JsonArray& signatures = root.createNestedArray("signatures"); - std::string::size_type lastPos = txArray["signatures"].find_first_not_of(",", 0); - std::string::size_type pos = txArray["signatures"].find_first_of(",", lastPos); + if (!this->signatures.empty()) { + JsonArray signatures = doc.createNestedArray("signatures"); + std::string::size_type lastPos = txArray["signatures"].find_first_not_of(',', 0); + std::string::size_type pos = txArray["signatures"].find_first_of(',', lastPos); while (std::string::npos != pos || std::string::npos != lastPos) { signatures.add(txArray["signatures"].substr(lastPos, pos - lastPos)); - lastPos = txArray["signatures"].find_first_not_of(",", pos); - pos = txArray["signatures"].find_first_of(",", lastPos); - } - } + lastPos = txArray["signatures"].find_first_not_of(',', pos); + pos = txArray["signatures"].find_first_of(',', lastPos); + }; + }; // SignSignature if (std::strlen(txArray["signSignature"].c_str()) > 0) { - root["signSignature"] = txArray["signSignature"]; - } + doc["signSignature"] = txArray["signSignature"]; + }; // Timestamp - root["timestamp"] = txArray["timestamp"]; + doc["timestamp"] = strtoul(txArray["timestamp"].c_str(), nullptr, 10); // Type - root["type"] = txArray["type"]; + doc["type"] = atoi(txArray["type"].c_str()); // VendorField if (std::strlen(txArray["vendorField"].c_str()) > 0) { - root["vendorField"] = txArray["vendorField"]; - } + doc["vendorField"] = txArray["vendorField"]; + }; // Version if (txArray["version"] != "0") { - root["version"] = txArray["version"]; - } + doc["version"] = atoi(txArray["version"].c_str()); + }; - char jsonChar[root.measureLength() + 1]; - root.printTo((char*)jsonChar, sizeof(jsonChar)); + char jsonChar[docCapacity]; + serializeJson(doc, jsonChar, docCapacity); return jsonChar; } diff --git a/src/transactions/transaction.h b/src/transactions/transaction.h index 1f1ef9b0..07472338 100644 --- a/src/transactions/transaction.h +++ b/src/transactions/transaction.h @@ -10,8 +10,6 @@ #ifndef TRANSACTION_H #define TRANSACTION_H -#include "helpers/encoding/hex.h" -#include "helpers/crypto_helpers.h" #include "identities/privatekey.h" #include "identities/publickey.h" @@ -22,7 +20,7 @@ namespace Ark { namespace Crypto { namespace Transactions { - +/**/ struct TransactionAsset { struct { std::string publicKey; @@ -40,10 +38,10 @@ struct TransactionAsset { std::vector keysgroup; } multiSignature; }; - +/**/ class Transaction { public: - Transaction(); + Transaction() = default; std::string getId() const; @@ -79,11 +77,14 @@ class Transaction { uint64_t timelock = 0; private: - bool internalVerify(std::string publicKey, std::vector bytes, std::string signature) const; + bool internalVerify( + std::string publicKey, + std::vector bytes, + std::string signature) const; }; - -} // namespace Transactions -} // namespace Crypto -} // namespace Ark +/**/ +}; // namespace Transactions +}; // namespace Crypto +}; // namespace Ark #endif diff --git a/src/utils/message.cpp b/src/utils/message.cpp index ddc32737..c5a8feaf 100644 --- a/src/utils/message.cpp +++ b/src/utils/message.cpp @@ -1,50 +1,31 @@ -/** - * This file is part of Ark Cpp Crypto. - * - * (c) Ark Ecosystem - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - **/ #include "utils/message.h" #include "helpers/json.h" -/** - * @brief Create a message object for checking its validity. - * - * @param std::string msg - * @param PublicKey pubKey - * @param std::vector sig - **/ Ark::Crypto::Utils::Message::Message( std::string msg, PublicKey pubKey, std::vector sig) - : message(msg), + : message(std::move(msg)), publicKey(pubKey), - signature(sig){}; + signature(std::move(sig)) {}; + /**/ -/** - * @brief Sign a message using the given passphrase. - * - * @param string message - * @param string passphrase - * - * @return bool - **/ -bool Ark::Crypto::Utils::Message::sign(std::string newMessage, const char *const passphrase) { - this->message = newMessage; +bool Ark::Crypto::Utils::Message::sign( + std::string newMessage, + const char *const passphrase) { + this->message = std::move(newMessage); /* Get the PrivateKey */ - PrivateKey privateKey = Ark::Crypto::Identities::PrivateKey::fromPassphrase(passphrase); + auto privateKey = PrivateKey::fromPassphrase(passphrase); /* Set the PublicKey from the derived PrivateKey */ - this->publicKey = Ark::Crypto::Identities::PublicKey::fromPrivateKey(privateKey); + this->publicKey = PublicKey::fromPrivateKey(privateKey); /* Get the Hash */ - const auto unsignedMessage = reinterpret_cast(message.c_str()); + const auto unsignedMessage = reinterpret_cast( + message.c_str()); const auto hash = Sha256::getHash(unsignedMessage, this->message.length()); /* Sign it */ @@ -52,56 +33,48 @@ bool Ark::Crypto::Utils::Message::sign(std::string newMessage, const char *const return this->verify(); }; + /**/ -/** - * @brief Verify the message contents. - * - * @return bool - **/ bool Ark::Crypto::Utils::Message::verify() { // cast message to unsigned char* - const auto unsignedMessage = reinterpret_cast(this->message.c_str()); + const auto unsignedMessage = reinterpret_cast( + this->message.c_str()); const auto hash = Sha256::getHash(unsignedMessage, this->message.length()); return cryptoVerify(this->publicKey, hash, this->signature); }; + /**/ -/** - * @brief Convert the message to its array representation using an array of pairs - * - * @return std::map - **/ std::map Ark::Crypto::Utils::Message::toArray() { return { - {"publickey", this->publicKey.toString()}, - {"signature", BytesToHex(this->signature.begin(), this->signature.end())}, - {"message", this->message} + { "publickey", this->publicKey.toString() }, + { "signature", BytesToHex(this->signature.begin(), this->signature.end()) }, + { "message", this->message } }; } + /**/ -/** - * @brief Convert the message to its JSON representation. - * - * @return std::string - **/ std::string Ark::Crypto::Utils::Message::toJson() { std::map messageArray = this->toArray(); - const size_t capacity = JSON_OBJECT_SIZE(3); - DynamicJsonBuffer jsonBuffer(capacity); + const size_t docLength + = (33 + 1) // publickey length + + (72 + 1) // signature length + + this->message.length(); + const size_t docCapacity = JSON_OBJECT_SIZE(3) + docLength + 120; - JsonObject& root = jsonBuffer.createObject(); + DynamicJsonDocument doc(docCapacity); - root["publickey"] = messageArray["publickey"]; - root["signature"] = messageArray["signature"]; - root["message"] = messageArray["message"]; + doc["publickey"] = messageArray["publickey"]; + doc["signature"] = messageArray["signature"]; + doc["message"] = messageArray["message"]; - char jsonChar[root.measureLength() + 1]; - root.printTo((char*)jsonChar, sizeof(jsonChar)); + std::string jsonStr; + jsonStr.reserve(docCapacity); + serializeJson(doc, &jsonStr[0], docCapacity); - return jsonChar; + return jsonStr; } -/**/ diff --git a/src/utils/message.h b/src/utils/message.h index f159c549..53d9eba4 100644 --- a/src/utils/message.h +++ b/src/utils/message.h @@ -24,8 +24,6 @@ #include "rfc6979/rfc6979.h" -#include -#include #include #include #include @@ -35,12 +33,7 @@ using namespace Ark::Crypto::Identities; namespace Ark { namespace Crypto { namespace Utils { - -/** - * This is the message class. - * - * @author Simon Downey - **/ +/**/ class Message { public: std::string message; @@ -57,7 +50,6 @@ class Message { std::string toJson(); }; /**/ - }; // namespace Utils }; // namespace Crypto }; // namespace Ark diff --git a/src/utils/slot.cpp b/src/utils/slot.cpp index 02ff2240..165f757c 100644 --- a/src/utils/slot.cpp +++ b/src/utils/slot.cpp @@ -1,61 +1,84 @@ -#include "helpers/crypto_helpers.h" #include "utils/slot.h" -#include -#include - -#undef round -#include "date/date.h" - -uint64_t Ark::Crypto::Utils::Slot::epoch(Crypto::Networks::AbstractNetwork network) { - // https://stackoverflow.com/questions/33421450/c-c-time-zone-correct-time-conversion-to-seconds-since-epoch/33438989#33438989 - std::istringstream in(network.epoch()); - std::chrono::system_clock::time_point tp; - in >> date::parse("%FT%TZ", tp); - if (in.fail()) { - in.clear(); - in.str(network.epoch()); - in >> date::parse("%FT%T%z", tp); - }; - // cast milliseconds as uint64_t in seconds(/ 1000) - return static_cast( - std::chrono::duration_cast( - tp.time_since_epoch() - ).count() - ) / 1000; -} +#include "common/network.hpp" + +#include "helpers/crypto_helpers.h" + +#ifndef USE_IOT // OS Builds + + #include + #include + + #undef round + #include "date/date.h" + + uint64_t Ark::Crypto::Utils::Slot::epoch( + const Ark::Crypto::Network& network) { + // https://stackoverflow.com/questions/33421450/c-c-time-zone-correct-time-conversion-to-seconds-since-epoch/33438989#33438989 + std::istringstream in(network.epoch()); + std::chrono::system_clock::time_point tp; + in >> date::parse("%FT%TZ", tp); -uint64_t Ark::Crypto::Utils::Slot::time(Crypto::Networks::AbstractNetwork network) { + // cast milliseconds as uint64_t in seconds(/ 1000) + return static_cast( + std::chrono::duration_cast( + tp.time_since_epoch() + ).count() + ) / 1000; + } + + uint64_t Ark::Crypto::Utils::Slot::now() { + return std::chrono::duration_cast( + std::chrono::system_clock::now().time_since_epoch() + ).count(); + } + +#endif + +uint64_t Ark::Crypto::Utils::Slot::time( + const Ark::Crypto::Network& network) { const auto time = now() - epoch(network); return (time > 0) ? time : 0; } -#ifdef ESP32 +#if defined(ESP32) || defined(ESP8266) -uint64_t Ark::Crypto::Utils::Slot::now() { - struct tm t; - std::stringstream ss; - if(getLocalTime(&t)){ - ss << std::mktime(&t); - } else { - return 0; - }; - uint64_t temp; - ss >> temp; - return temp; -}; + #include + #include /* strtol */ + #include -#elif defined(ESP8266) // NOT STABLE/NOT SUPPORTED + uint64_t Ark::Crypto::Utils::Slot::epoch( + const Ark::Crypto::Network& network) { + constexpr const size_t expectedLength = sizeof("2017-03-21T13:00:00.000Z") - 1; + if (expectedLength != 24) { return 0; } // Unexpected ISO 8601 date/time length -uint64_t Ark::Crypto::Utils::Slot::now() { return 0; } + std::string input(network.epoch()); -#else // OS Builds + if (input.length() < expectedLength) { + return 0; + }; -uint64_t Ark::Crypto::Utils::Slot::now() { - return std::chrono::duration_cast( - std::chrono::system_clock::now().time_since_epoch() - ).count(); -} + struct tm time; + time.tm_year = strtol(&input[0], nullptr, 10) - 1900; + time.tm_mon = strtol(&input[5], nullptr, 10) - 1; + time.tm_mday = strtol(&input[8], nullptr, 10); + time.tm_hour = strtol(&input[11], nullptr, 10); + time.tm_min = strtol(&input[14], nullptr, 10); + time.tm_sec = strtol(&input[17], nullptr, 10); + time.tm_isdst = 0; + + return mktime(&time); + } + + /***/ + + // 'time(0) will collide with Slot::time + // so we create the call outside the Slot namespace. + static uint64_t Now() { return time(0); } + + uint64_t Ark::Crypto::Utils::Slot::now() { + return Now(); + } -#endif // #ifndef USE_IOT +#endif diff --git a/src/utils/slot.h b/src/utils/slot.h index 93650f19..96865884 100644 --- a/src/utils/slot.h +++ b/src/utils/slot.h @@ -10,23 +10,25 @@ #ifndef ARK_UTILITIES_SLOTS_H #define ARK_UTILITIES_SLOTS_H -#include "configuration/network.h" +#include + +#include "common/network.hpp" namespace Ark { namespace Crypto { namespace Utils { - +/**/ class Slot { public: - static uint64_t epoch(Crypto::Networks::AbstractNetwork network); - static uint64_t time(Crypto::Networks::AbstractNetwork network); + static uint64_t epoch(const Network& network); + static uint64_t time(const Network& network); private: static uint64_t now(); }; - -} // namespace Utils -} // namespace Crypto -} // namespace Ark +/**/ +}; // namespace Utils +}; // namespace Crypto +}; // namespace Ark #endif