From 13a6254e1e7f4f302bd767472c105b7b57210c93 Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Sat, 25 Jun 2022 01:45:38 +0200 Subject: [PATCH] Correct submodule --- .gitmodules | 6 +- contrib/base-x | 1 + contrib/base-x/.gitignore | 4 - contrib/base-x/.travis.yml | 36 - contrib/base-x/LICENSE | 21 - contrib/base-x/README.md | 97 - contrib/base-x/base_x.hh | 614 ------ contrib/base-x/tests/test.cc | 30 - contrib/base-x/tests/testcases/tests.cc | 359 ---- contrib/base-x/uinteger_t.hh | 2546 ----------------------- 10 files changed, 4 insertions(+), 3710 deletions(-) create mode 160000 contrib/base-x delete mode 100644 contrib/base-x/.gitignore delete mode 100755 contrib/base-x/.travis.yml delete mode 100644 contrib/base-x/LICENSE delete mode 100644 contrib/base-x/README.md delete mode 100644 contrib/base-x/base_x.hh delete mode 100644 contrib/base-x/tests/test.cc delete mode 100644 contrib/base-x/tests/testcases/tests.cc delete mode 100644 contrib/base-x/uinteger_t.hh diff --git a/.gitmodules b/.gitmodules index a8924e3aaba..f65806c1da5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -268,9 +268,9 @@ [submodule "contrib/hashidsxx"] path = contrib/hashidsxx url = https://github.com/schoentoon/hashidsxx.git -[submodule "contrib/base-x"] - path = contrib/base-x - url = https://github.com/ClickHouse/base-x.git [submodule "contrib/liburing"] path = contrib/liburing url = https://github.com/axboe/liburing.git +[submodule "contrib/base-x"] + path = contrib/base-x + url = https://github.com/ClickHouse/base-x.git diff --git a/contrib/base-x b/contrib/base-x new file mode 160000 index 00000000000..a85f98fb4ed --- /dev/null +++ b/contrib/base-x @@ -0,0 +1 @@ +Subproject commit a85f98fb4ed52c2f4029a4b6ac1ef0bafdfc56f5 diff --git a/contrib/base-x/.gitignore b/contrib/base-x/.gitignore deleted file mode 100644 index b63b40c8b71..00000000000 --- a/contrib/base-x/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -.DS_Store -test -*.o -*.dSYM \ No newline at end of file diff --git a/contrib/base-x/.travis.yml b/contrib/base-x/.travis.yml deleted file mode 100755 index f55132e614f..00000000000 --- a/contrib/base-x/.travis.yml +++ /dev/null @@ -1,36 +0,0 @@ -sudo: false - -language: cpp - -compiler: - - clang - - gcc - -addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.8 - packages: - - g++-6 - - clang-3.8 - -install: - - if [ "$CXX" = "g++" ]; then export CXX="g++-6"; fi - - if [ "$CXX" == "clang++" ]; then export CXX="clang++-3.8"; fi - - sudo apt-get install -qq git cmake - -before_script: - # not much better than git submodules, but there was never a need/want for the repo in this repo - - cd .. - - git clone https://github.com/google/googletest.git - - cd googletest - - git reset --hard d62d6c6556d96dda924382547c54a4b3afedb22c - - cmake CMakeLists.txt - - make - - - cd ../base-x/tests - - make - -script: - - make run diff --git a/contrib/base-x/LICENSE b/contrib/base-x/LICENSE deleted file mode 100644 index f7b3408abac..00000000000 --- a/contrib/base-x/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2017 German Mendez Bravo (Kronuz) @ german dot mb at gmail.com - -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. diff --git a/contrib/base-x/README.md b/contrib/base-x/README.md deleted file mode 100644 index 5dc4a068043..00000000000 --- a/contrib/base-x/README.md +++ /dev/null @@ -1,97 +0,0 @@ -# base-x [![License][license-img]][license-url] [![GitHub Stars][stars-img]][stars-url] [![GitHub Forks][forks-img]][forks-url] [![GitHub Watchers][watchers-img]][watchers-url] [![Tweet][tweet-img]][tweet-url] - -[![Build Status](https://travis-ci.org/Kronuz/base-x.svg?branch=master)](https://travis-ci.org/Kronuz/base-x) - - -### BaseX encoder / decoder for C++ - -This is a fast base encoder / decoder of any given alphabet. - - -#### Example - -``` cpp -// example.cc -// g++ -std=c++14 -o example example.cc - -#include -#include "base_x.hh" - -int main() { - auto encoded = Base58::base58().encode("Hello world!"); - - std::cout << encoded << std::endl; - // => 1LDlk6QWOejX6rPrJ - - return 0; -} -``` - - -#### Compilation - -* g++ and clang++ are supported. -* C++14 is required. - - -### Alphabets - -See below for a list of commonly recognized alphabets, and their respective base. - -Base | Factory | Alphabet ------|---------------------|------------- - 2 | base2::base2() | `01` - 2 | base8::base8() | `01234567` - 11 | bas11::bas11() | `0123456789a` - 16 | base16::base16() | `0123456789abcdef` - 32 | base32::base32() | `0123456789ABCDEFGHJKMNPQRSTVWXYZ` - 36 | base36::base36() | `0123456789abcdefghijklmnopqrstuvwxyz` - 58 | base58::base58() | `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz` - 58 | base58::bitcoin() | `123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz` - 58 | base58::gmp() | `0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv` - 58 | base58::ripple() | `rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz` - 58 | base58::flickr() | `123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ` - 62 | base62::base62() | `0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz` - 62 | base62::inverted() | `0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ` - 64 | base64::base64() | `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/` - 64 | base64::urlsafe() | `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_` - 66 | base66::base66() | `ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.!~` - - -### How it works - -It encodes octet arrays by doing long divisions on all significant digits in the -array, creating a representation of that number in the new base. - -**If you need standard hex encoding, or base64 encoding, this module is NOT -appropriate.** - - -## Author -[**German Mendez Bravo (Kronuz)**](https://kronuz.io/) - -[![Follow on GitHub][github-follow-img]][github-follow-url] -[![Follow on Twitter][twitter-follow-img]][twitter-follow-url] - - -## License - -MIT License. See [LICENSE](LICENSE) for details. - -Copyright (c) 2017 German Mendez Bravo (Kronuz) @ german dot mb at gmail.com - - -[license-url]: https://github.com/Kronuz/base-x/blob/master/LICENSE -[license-img]: https://img.shields.io/github/license/Kronuz/base-x.svg -[stars-url]: https://github.com/Kronuz/base-x/stargazers -[stars-img]: https://img.shields.io/github/stars/Kronuz/base-x.svg?style=social&label=Stars -[forks-url]: https://github.com/Kronuz/base-x/network/members -[forks-img]: https://img.shields.io/github/forks/Kronuz/base-x.svg?style=social&label=Forks -[watchers-url]: https://github.com/Kronuz/base-x/watchers -[watchers-img]: https://img.shields.io/github/watchers/Kronuz/base-x.svg?style=social&label=Watchers -[tweet-img]: https://img.shields.io/twitter/url/https/github.com/Kronuz/base-x.svg?style=social -[tweet-url]: https://twitter.com/intent/tweet?text=Base-X+encoding%2Fdecoding+for+modern+C%2B%2B+by+%40germbravo:&url=https%3A%2F%2Fgithub.com%2FKronuz%2Fbase-x -[github-follow-url]: https://github.com/Kronuz -[github-follow-img]: https://img.shields.io/github/followers/Kronuz.svg?style=social&label=Follow -[twitter-follow-url]: https://twitter.com/intent/follow?screen_name=germbravo -[twitter-follow-img]: https://img.shields.io/twitter/follow/germbravo.svg?style=social&label=Follow diff --git a/contrib/base-x/base_x.hh b/contrib/base-x/base_x.hh deleted file mode 100644 index fdc06fead2f..00000000000 --- a/contrib/base-x/base_x.hh +++ /dev/null @@ -1,614 +0,0 @@ -/* -base_x.hh -BaseX encoder / decoder for C++ - -Copyright (c) 2017 German Mendez Bravo (Kronuz) @ german dot mb at gmail.com - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#ifndef __BASE_X__H_ -#define __BASE_X__H_ - -#include // for std::find_if, std::reverse -#include // for std::invalid_argument -#include // for std::string -#include // for std::enable_if_t - -#include "uinteger_t.hh" - - -class BaseX { - char _chr[256]; - int _ord[256]; - - const int size; - const int alphabet_base; - const unsigned base_size; - const unsigned alphabet_base_bits; - const unsigned block_size; - const uinteger_t::digit alphabet_base_mask; - const unsigned padding_size; - const char padding; - const int flags; - - constexpr char chr(unsigned char ord) const { - return _chr[ord]; - } - - constexpr int ord(unsigned char chr) const { - return _ord[chr]; - } - -public: - static constexpr int ignore_case = (1 << 0); - static constexpr int with_checksum = (1 << 1); - static constexpr int with_check = (1 << 2); - static constexpr int block_padding = (1 << 3); - - template - constexpr BaseX(int flgs, const char (&alphabet)[alphabet_size1], const char (&extended)[extended_size1], const char (&padding_string)[padding_size1], const char (&translate)[translate_size1]) : - _chr(), - _ord(), - size(alphabet_size1 - 1 + extended_size1 - 1), - alphabet_base(alphabet_size1 - 1), - base_size(uinteger_t::base_size(alphabet_base)), - alphabet_base_bits(uinteger_t::base_bits(alphabet_base)), - block_size((flgs & BaseX::block_padding) ? alphabet_base_bits : 0), - alphabet_base_mask(alphabet_base - 1), - padding_size(padding_size1 - 1), - padding(padding_size ? padding_string[0] : '\0'), - flags(flgs) - { - for (int c = 0; c < 256; ++c) { - _chr[c] = 0; - _ord[c] = alphabet_base; - } - for (int cp = 0; cp < alphabet_base; ++cp) { - auto ch = alphabet[cp]; - _chr[cp] = ch; - ASSERT(_ord[(unsigned char)ch] == alphabet_base); // Duplicate character in the alphabet - _ord[(unsigned char)ch] = cp; - if (flags & BaseX::ignore_case) { - if (ch >= 'A' && ch <='Z') { - _ord[(unsigned char)ch - 'A' + 'a'] = cp; - } else if (ch >= 'a' && ch <='z') { - _ord[(unsigned char)ch - 'a' + 'A'] = cp; - } - } - } - for (std::size_t i = 0; i < extended_size1 - 1; ++i) { - auto ch = extended[i]; - auto cp = alphabet_base + i; - _chr[cp] = ch; - ASSERT(_ord[(unsigned char)ch] == alphabet_base); // Duplicate character in the extended alphabet - _ord[(unsigned char)ch] = cp; - if (flags & BaseX::ignore_case) { - if (ch >= 'A' && ch <='Z') { - _ord[(unsigned char)ch - 'A' + 'a'] = cp; - } else if (ch >= 'a' && ch <='z') { - _ord[(unsigned char)ch - 'a' + 'A'] = cp; - } - } - } - int cp = -1; - for (std::size_t i = 0; i < translate_size1 - 1; ++i) { - auto ch = translate[i]; - auto ncp = _ord[(unsigned char)ch]; - if (ncp >= alphabet_base) { - ASSERT(_ord[(unsigned char)ch] == alphabet_base); // Invalid translation character - _ord[(unsigned char)ch] = cp; - if (flags & BaseX::ignore_case) { - if (ch >= 'A' && ch <='Z') { - _ord[(unsigned char)ch - 'A' + 'a'] = cp; - } else if (ch >= 'a' && ch <='z') { - _ord[(unsigned char)ch - 'a' + 'A'] = cp; - } - } - } else { - cp = ncp; - } - } - } - - // Get string representation of value - template ::value>> - void encode(Result& result, const uinteger_t& input) const { - std::size_t bp = 0; - uinteger_t quotient; - if (block_size) { - bp = ((input.bits() + 7) & 0xf8) % block_size; - bp = bp ? (block_size - bp) % block_size : 0; - if (bp) { - quotient = input << bp; - } - } - const uinteger_t& num = bp ? quotient : input; - auto num_sz = num.size(); - if (num_sz) { - int sum = 0; - result.reserve(num_sz * base_size); - if (alphabet_base_bits) { - std::size_t shift = 0; - auto ptr = reinterpret_cast(num.data()); - uinteger_t::digit v = *ptr++; - v <<= uinteger_t::half_digit_bits; - for (auto i = num_sz * 2 - 1; i; --i) { - v >>= uinteger_t::half_digit_bits; - v |= (static_cast(*ptr++) << uinteger_t::half_digit_bits); - do { - auto d = static_cast((v >> shift) & alphabet_base_mask); - result.push_back(chr(d)); - shift += alphabet_base_bits; - sum += d; - } while (shift <= uinteger_t::half_digit_bits); - shift -= uinteger_t::half_digit_bits; - } - v >>= (shift + uinteger_t::half_digit_bits); - while (v) { - auto d = static_cast(v & alphabet_base_mask); - result.push_back(chr(d)); - v >>= alphabet_base_bits; - sum += d; - } - auto s = chr(0); - auto rit_f = std::find_if(result.rbegin(), result.rend(), [s](const char& c) { return c != s; }); - result.resize(result.rend() - rit_f); // shrink - } else { - uinteger_t uint_base = alphabet_base; - if (!bp) { - quotient = num; - } - do { - auto r = quotient.divmod(uint_base); - auto d = static_cast(r.second); - result.push_back(chr(d)); - quotient = std::move(r.first); - sum += d; - } while (quotient); - } - std::reverse(result.begin(), result.end()); - if (padding_size) { - Result p; - p.resize((padding_size - (result.size() % padding_size)) % padding_size, padding); - result.append(p); - } - if (flags & BaseX::with_check) { - auto chk = static_cast(num % size); - result.push_back(chr(chk)); - sum += chk; - } - if (flags & BaseX::with_checksum) { - auto sz = result.size(); - sz = (sz + sz / size) % size; - sum += sz; - sum = (size - sum % size) % size; - result.push_back(chr(sum)); - } - } else { - result.push_back(chr(0)); - } - } - - template ::value>> - Result encode(const uinteger_t& num) const { - Result result; - encode(result, num); - return result; - } - - template ::value>> - void encode(Result& result, const unsigned char* decoded, std::size_t decoded_size) const { - encode(result, uinteger_t(decoded, decoded_size, 256)); - } - - template ::value>> - Result encode(const unsigned char* decoded, std::size_t decoded_size) const { - Result result; - encode(result, uinteger_t(decoded, decoded_size, 256)); - return result; - } - - template ::value>> - void encode(Result& result, const char* decoded, std::size_t decoded_size) const { - encode(result, uinteger_t(decoded, decoded_size, 256)); - } - - template ::value>> - Result encode(const char* decoded, std::size_t decoded_size) const { - Result result; - encode(result, uinteger_t(decoded, decoded_size, 256)); - return result; - } - - template ::value>> - void encode(Result& result, T (&s)[N]) const { - encode(result, s, N - 1); - } - - template ::value>> - Result encode(T (&s)[N]) const { - Result result; - encode(result, s, N - 1); - return result; - } - - template ::value>> - void encode(Result& result, const std::string& binary) const { - return encode(result, binary.data(), binary.size()); - } - - template ::value>> - Result encode(const std::string& binary) const { - Result result; - encode(result, binary.data(), binary.size()); - return result; - } - - void decode(uinteger_t& result, const char* encoded, std::size_t encoded_size) const { - result = 0; - int sum = 0; - int sumsz = 0; - int direction = 1; - - auto sz = encoded_size; - if (flags & BaseX::with_checksum) --sz; - if (flags & BaseX::with_check) --sz; - - int bp = 0; - - if (alphabet_base_bits) { - for (; sz; --sz, encoded += direction) { - auto c = *encoded; - if (c == padding) break; - auto d = ord(static_cast(c)); - if (d < 0) continue; // ignored character - if (d >= alphabet_base) { - throw std::invalid_argument("Error: Invalid character: '" + std::string(1, c) + "' at " + std::to_string(encoded_size - sz)); - } - sum += d; - ++sumsz; - result = (result << alphabet_base_bits) | d; - bp += block_size; - } - } else { - uinteger_t uint_base = alphabet_base; - for (; sz; --sz, encoded += direction) { - auto c = *encoded; - if (c == padding) break; - auto d = ord(static_cast(c)); - if (d < 0) continue; // ignored character - if (d >= alphabet_base) { - throw std::invalid_argument("Error: Invalid character: '" + std::string(1, c) + "' at " + std::to_string(encoded_size - sz)); - } - sum += d; - ++sumsz; - result = (result * uint_base) + d; - bp += block_size; - } - } - - for (; sz && *encoded == padding; --sz, ++encoded); - - result >>= (bp & 7); - - if (flags & BaseX::with_check) { - auto c = *encoded; - auto d = ord(static_cast(c)); - if (d < 0 || d >= size) { - throw std::invalid_argument("Error: Invalid character: '" + std::string(1, c) + "' at " + std::to_string(encoded_size - sz)); - } - auto chk = static_cast(result % size); - if (d != chk) { - throw std::invalid_argument("Error: Invalid check"); - } - sum += chk; - ++sumsz; - ++encoded; - } - - if (flags & BaseX::with_checksum) { - auto c = *encoded; - auto d = ord(static_cast(c)); - if (d < 0 || d >= size) { - throw std::invalid_argument("Error: Invalid character: '" + std::string(1, c) + "' at " + std::to_string(encoded_size - sz)); - } - sum += d; - sum += (sumsz + sumsz / size) % size; - if (sum % size) { - throw std::invalid_argument("Error: Invalid checksum"); - } - } - } - - template ::value>> - void decode(Result& result, const char* encoded, std::size_t encoded_size) const { - uinteger_t num; - decode(num, encoded, encoded_size); - result = num.template str(256); - } - - template ::value or std::is_integral::value>> - Result decode(const char* encoded, std::size_t encoded_size) const { - Result result; - decode(result, encoded, encoded_size); - return result; - } - - template ::value or std::is_integral::value>> - void decode(Result& result, T (&s)[N]) const { - decode(result, s, N - 1); - } - - template ::value or std::is_integral::value>> - Result decode(T (&s)[N]) const { - Result result; - decode(result, s, N - 1); - return result; - } - - template ::value or std::is_integral::value>> - void decode(Result& result, const std::string& encoded) const { - decode(result, encoded.data(), encoded.size()); - } - - template ::value or std::is_integral::value>> - Result decode(const std::string& encoded) const { - Result result; - decode(result, encoded.data(), encoded.size()); - return result; - } - - bool is_valid(const char* encoded, std::size_t encoded_size) const { - int sum = 0; - int sumsz = 0; - if (flags & BaseX::with_checksum) --sumsz; - for (; encoded_size; --encoded_size, ++encoded) { - auto d = ord(static_cast(*encoded)); - if (d < 0) continue; // ignored character - if (d >= alphabet_base) { - return false; - } - sum += d; - ++sumsz; - } - if (flags & BaseX::with_checksum) { - sum += (sumsz + sumsz / size) % size; - if (sum % size) { - return false; - } - } - return true; - } - - template - bool is_valid(T (&s)[N]) const { - return is_valid(s, N - 1); - } - - bool is_valid(const std::string& encoded) const { - return is_valid(encoded.data(), encoded.size()); - } -}; - -// base2 -struct Base2 { - static const BaseX& base2() { - static constexpr BaseX encoder(0, "01", "", "", ""); - return encoder; - } - static const BaseX& base2chk() { - static constexpr BaseX encoder(BaseX::with_checksum, "01", "", "", ""); - return encoder; - } -}; - -// base8 -struct Base8 { - static const BaseX& base8() { - static constexpr BaseX encoder(0, "01234567", "", "", ""); - return encoder; - } - static const BaseX& base8chk() { - static constexpr BaseX encoder(BaseX::with_checksum, "01234567", "", "", ""); - return encoder; - } -}; - -// base11 -struct Base11 { - static const BaseX& base11() { - static constexpr BaseX encoder(BaseX::ignore_case, "0123456789a", "", "", ""); - return encoder; - } - static const BaseX& base11chk() { - static constexpr BaseX encoder(BaseX::ignore_case | BaseX::with_checksum, "0123456789a", "", "", ""); - return encoder; - } -}; - -// base16 -struct Base16 { - static const BaseX& base16() { - static constexpr BaseX encoder(BaseX::ignore_case, "0123456789abcdef", "", "", ""); - return encoder; - } - static const BaseX& base16chk() { - static constexpr BaseX encoder(BaseX::ignore_case | BaseX::with_checksum, "0123456789abcdef", "", "", ""); - return encoder; - } - static const BaseX& rfc4648() { - static constexpr BaseX encoder(0, "0123456789ABCDEF", "", "", ""); - return encoder; - } -}; - -// base32 -struct Base32 { - static const BaseX& base32() { - static constexpr BaseX encoder(BaseX::ignore_case, "0123456789abcdefghijklmnopqrstuv", "", "", ""); - return encoder; - } - static const BaseX& base32chk() { - static constexpr BaseX encoder(BaseX::ignore_case | BaseX::with_checksum, "0123456789abcdefghijklmnopqrstuv", "", "", ""); - return encoder; - } - static const BaseX& crockford() { - static constexpr BaseX encoder(BaseX::ignore_case, "0123456789ABCDEFGHJKMNPQRSTVWXYZ", "", "", "-0O1IL"); - return encoder; - } - static const BaseX& crockfordchk() { - static constexpr BaseX encoder(BaseX::ignore_case | BaseX::with_check, "0123456789ABCDEFGHJKMNPQRSTVWXYZ", "*~$=U", "", "-0O1IL"); - return encoder; - } - static const BaseX& rfc4648() { - static constexpr BaseX encoder(BaseX::block_padding, "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", "", "========", "\n\r"); - return encoder; - } - static const BaseX& rfc4648hex() { - static constexpr BaseX encoder(BaseX::block_padding, "0123456789ABCDEFGHIJKLMNOPQRSTUV", "", "========", "\n\r"); - return encoder; - } -}; - -// base36 -struct Base36 { - static const BaseX& base36() { - static constexpr BaseX encoder(BaseX::ignore_case, "0123456789abcdefghijklmnopqrstuvwxyz", "", "", ""); - return encoder; - } - static const BaseX& base36chk() { - static constexpr BaseX encoder(BaseX::ignore_case | BaseX::with_checksum, "0123456789abcdefghijklmnopqrstuvwxyz", "", "", ""); - return encoder; - } -}; - -// base58 -struct Base58 { - static const BaseX& base58() { - static constexpr BaseX encoder(0, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv", "", "", ""); - return encoder; - } - static const BaseX& base58chk() { - static constexpr BaseX encoder(BaseX::with_checksum, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuv", "", "", ""); - return encoder; - } - static const BaseX& bitcoin() { - static constexpr BaseX encoder(0, "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", "", "", ""); - return encoder; - } - static const BaseX& bitcoinchk() { - static constexpr BaseX encoder(BaseX::with_checksum, "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", "", "", ""); - return encoder; - } - static const BaseX& ripple() { - static constexpr BaseX encoder(0, "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz", "", "", ""); - return encoder; - } - static const BaseX& ripplechk() { - static constexpr BaseX encoder(BaseX::with_checksum, "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz", "", "", ""); - return encoder; - } - static const BaseX& flickr() { - static constexpr BaseX encoder(0, "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ", "", "", ""); - return encoder; - } - static const BaseX& flickrchk() { - static constexpr BaseX encoder(BaseX::with_checksum, "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ", "", "", ""); - return encoder; - } -}; - -// base59 -struct Base59 { - static const BaseX& base59() { - static constexpr BaseX encoder(0, "23456789abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ", "", "", "l1IO0"); - return encoder; - } - static const BaseX& base59chk() { - static constexpr BaseX encoder(BaseX::with_checksum, "23456789abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ", "", "", "l1IO0"); - return encoder; - } - static const BaseX& dubaluchk() { - static constexpr BaseX encoder(BaseX::with_checksum, "zy9MalDxwpKLdvW2AtmscgbYUq6jhP7E53TiXenZRkVCrouBH4GSQf8FNJO", "", "", "-l1IO0"); - return encoder; - } -}; - -// base62 -struct Base62 { - static const BaseX& base62() { - static constexpr BaseX encoder(0, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", "", "", ""); - return encoder; - } - static const BaseX& base62chk() { - static constexpr BaseX encoder(BaseX::with_checksum, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", "", "", ""); - return encoder; - } - static const BaseX& inverted() { - static constexpr BaseX encoder(0, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", "", "", ""); - return encoder; - } - static const BaseX& invertedchk() { - static constexpr BaseX encoder(BaseX::with_checksum, "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", "", "", ""); - return encoder; - } -}; - -// base64 -struct Base64 { - static const BaseX& base64() { - static constexpr BaseX encoder(0, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", "", "", ""); - return encoder; - } - static const BaseX& base64chk() { - static constexpr BaseX encoder(BaseX::with_checksum, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", "", "", ""); - return encoder; - } - static const BaseX& url() { - static constexpr BaseX encoder(0, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", "", "", ""); - return encoder; - } - static const BaseX& urlchk() { - static constexpr BaseX encoder(BaseX::with_checksum, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", "", "", ""); - return encoder; - } - static const BaseX& rfc4648() { - static constexpr BaseX encoder(BaseX::block_padding, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", "", "====", "\n\r"); - return encoder; - } - static const BaseX& rfc4648url() { - static constexpr BaseX encoder(BaseX::block_padding, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", "", "====", "\n\r"); - return encoder; - } -}; - -// base66 -struct Base66 { - static const BaseX& base66() { - static constexpr BaseX encoder(0, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.!~", "", "", ""); - return encoder; - } - static const BaseX& base66chk() { - static constexpr BaseX encoder(BaseX::with_checksum, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.!~", "", "", ""); - return encoder; - } -}; - -#endif diff --git a/contrib/base-x/tests/test.cc b/contrib/base-x/tests/test.cc deleted file mode 100644 index d47d211173e..00000000000 --- a/contrib/base-x/tests/test.cc +++ /dev/null @@ -1,30 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2017 German Mendez Bravo (Kronuz) @ german dot mb at gmail.com - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include - -int main(int argc, char * argv[]){ - ::testing::InitGoogleTest(&argc, argv); - return RUN_ALL_TESTS(); -} \ No newline at end of file diff --git a/contrib/base-x/tests/testcases/tests.cc b/contrib/base-x/tests/testcases/tests.cc deleted file mode 100644 index c5bebfc8288..00000000000 --- a/contrib/base-x/tests/testcases/tests.cc +++ /dev/null @@ -1,359 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2017 German Mendez Bravo (Kronuz) @ german dot mb at gmail.com - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -#include - -#include "base_x.hh" - - -static constexpr BaseX test_base2(0, "01", "", "", ""); -static constexpr BaseX test_base16(0, "0123456789abcdef", "", "", ""); -static constexpr BaseX test_base58(0, "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", "", "", ""); - - -TEST(UUID, Encode) { - EXPECT_EQ(Base62::base62().encode("\330\105\140\310\23\117\21\346\241\342\64\66\73\322\155\256"), "6a630O1jrtMjCrQDyG3D3O"); - EXPECT_EQ(Base58::bitcoin().encode("\330\105\140\310\23\117\21\346\241\342\64\66\73\322\155\256"), "ThxCy1Ek2q6UhWQhj9CK1o"); - EXPECT_EQ(Base58::base58().encode("\330\105\140\310\23\117\21\346\241\342\64\66\73\322\155\256"), "QetBu0Dh1m5ReTNeg8BI0k"); -} - -TEST(BaseX, checksums) { - EXPECT_EQ(Base64::base64().encode("Hello world!"), "SGVsbG8gd29ybGQh"); - EXPECT_EQ(Base64::base64chk().encode("Hello world!"), "SGVsbG8gd29ybGQhG"); - - EXPECT_EQ(Base64::base64().decode("SGVsbG8gd29ybGQh"), "Hello world!"); - EXPECT_EQ(Base64::base64chk().decode("SGVsbG8gd29ybGQhG"), "Hello world!"); - - EXPECT_EQ(Base62::base62().encode("Hello world!"), "T8dgcjRGuYUueWht"); - EXPECT_EQ(Base62::base62chk().encode("Hello world!"), "T8dgcjRGuYUueWhtE"); - - EXPECT_EQ(Base62::base62().decode("T8dgcjRGuYUueWht"), "Hello world!"); - EXPECT_EQ(Base62::base62chk().decode("T8dgcjRGuYUueWhtE"), "Hello world!"); - - EXPECT_EQ(Base62::base62chk().is_valid("T8dgcjRGuYUueWhtE"), true); - EXPECT_EQ(Base62::base62chk().is_valid("Some random text!"), false); -} - -TEST(base16, Encoder) { - EXPECT_EQ(Base16::base16().encode("A"), "41"); - EXPECT_EQ(Base16::base16().encode("AB"), "4142"); - EXPECT_EQ(Base16::base16().encode("ABC"), "414243"); - EXPECT_EQ(Base16::base16().encode("ABCD"), "41424344"); - EXPECT_EQ(Base16::base16().encode("ABCDE"), "4142434445"); - EXPECT_EQ(Base16::base16().encode("ABCDEF"), "414243444546"); - - EXPECT_EQ(Base16::rfc4648().encode("A"), "41"); - EXPECT_EQ(Base16::rfc4648().encode("AB"), "4142"); - EXPECT_EQ(Base16::rfc4648().encode("ABC"), "414243"); - EXPECT_EQ(Base16::rfc4648().encode("ABCD"), "41424344"); - EXPECT_EQ(Base16::rfc4648().encode("ABCDE"), "4142434445"); - EXPECT_EQ(Base16::rfc4648().encode("ABCDEF"), "414243444546"); -} - -TEST(base16, Decoder) { - EXPECT_EQ(Base16::base16().decode("41"), "A"); - EXPECT_EQ(Base16::base16().decode("4142"), "AB"); - EXPECT_EQ(Base16::base16().decode("414243"), "ABC"); - EXPECT_EQ(Base16::base16().decode("41424344"), "ABCD"); - EXPECT_EQ(Base16::base16().decode("4142434445"), "ABCDE"); - EXPECT_EQ(Base16::base16().decode("414243444546"), "ABCDEF"); - - EXPECT_EQ(Base16::rfc4648().decode("41"), "A"); - EXPECT_EQ(Base16::rfc4648().decode("4142"), "AB"); - EXPECT_EQ(Base16::rfc4648().decode("414243"), "ABC"); - EXPECT_EQ(Base16::rfc4648().decode("41424344"), "ABCD"); - EXPECT_EQ(Base16::rfc4648().decode("4142434445"), "ABCDE"); - EXPECT_EQ(Base16::rfc4648().decode("414243444546"), "ABCDEF"); -} - -TEST(base32, Encoder) { - // Note base64() encoding is NOT the same as the standard (rfc4648) - EXPECT_EQ(Base32::base32().encode("A"), "21"); - EXPECT_EQ(Base32::base32().encode("AB"), "ga2"); - EXPECT_EQ(Base32::base32().encode("ABC"), "42gi3"); - EXPECT_EQ(Base32::base32().encode("ABCD"), "10k4gq4"); - EXPECT_EQ(Base32::base32().encode("ABCDE"), "85146h25"); - EXPECT_EQ(Base32::base32().encode("ABCDEF"), "21891k8ha6"); - EXPECT_EQ(Base32::base32().encode("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), "21891k8ha68t44iiib9h6ksjqga5956l2lapblgmaq"); - - EXPECT_EQ(Base32::rfc4648().encode("A"), "IE======"); - EXPECT_EQ(Base32::rfc4648().encode("AB"), "IFBA===="); - EXPECT_EQ(Base32::rfc4648().encode("ABC"), "IFBEG==="); - EXPECT_EQ(Base32::rfc4648().encode("ABCD"), "IFBEGRA="); - EXPECT_EQ(Base32::rfc4648().encode("ABCDE"), "IFBEGRCF"); - EXPECT_EQ(Base32::rfc4648().encode("ABCDEF"), "IFBEGRCFIY======"); - EXPECT_EQ(Base32::rfc4648().encode("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), "IFBEGRCFIZDUQSKKJNGE2TSPKBIVEU2UKVLFOWCZLI======"); - - EXPECT_EQ(Base32::crockford().encode(519571), "FVCK"); - EXPECT_EQ(Base32::crockfordchk().encode(1234), "16JD"); - EXPECT_EQ(Base32::crockfordchk().encode("Hello World"), "28CNP6RVS0AXQQ4V348"); -} - -TEST(base32, Decoder) { - // Note base64() encoding is NOT the same as the standard (rfc4648) - EXPECT_EQ(Base32::base32().decode("21"), "A"); - EXPECT_EQ(Base32::base32().decode("ga2"), "AB"); - EXPECT_EQ(Base32::base32().decode("42gi3"), "ABC"); - EXPECT_EQ(Base32::base32().decode("10k4gq4"), "ABCD"); - EXPECT_EQ(Base32::base32().decode("85146h25"), "ABCDE"); - EXPECT_EQ(Base32::base32().decode("21891k8ha6"), "ABCDEF"); - EXPECT_EQ(Base32::base32().decode("21891k8ha68t44iiib9h6ksjqga5956l2lapblgmaq"), "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - - EXPECT_EQ(Base32::rfc4648().decode("IE======"), "A"); - EXPECT_EQ(Base32::rfc4648().decode("IFBA===="), "AB"); - EXPECT_EQ(Base32::rfc4648().decode("IFBEG==="), "ABC"); - EXPECT_EQ(Base32::rfc4648().decode("IFBEGRA="), "ABCD"); - EXPECT_EQ(Base32::rfc4648().decode("IFBEGRCF"), "ABCDE"); - EXPECT_EQ(Base32::rfc4648().decode("IFBEGRCFIY======"), "ABCDEF"); - EXPECT_EQ(Base32::rfc4648().decode("IFBEGRCFIZDUQSKKJNGE2TSPKBIVEU2UKVLFOWCZLI======"), "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - - EXPECT_EQ(Base32::crockford().decode("FVCK"), 519571); - EXPECT_EQ(Base32::crockfordchk().is_valid("16JD"), true); - EXPECT_EQ(Base32::crockfordchk().decode("16JD"), 1234); - - EXPECT_EQ(Base32::crockfordchk().decode("2-8cn-p6r-vso-axq-q4v-348"), "Hello World"); -} - -TEST(base58, Encoder) { - EXPECT_EQ(Base58::base58().decode("1TFvCj"), 987654321); - EXPECT_EQ(Base58::base58().encode(987654321), "1TFvCj"); - EXPECT_EQ(Base58::base58().encode("Hello world!"), "1LDlk6QWOejX6rPrJ"); - EXPECT_EQ(Base58::bitcoin().encode("Hello world!"), "2NEpo7TZRhna7vSvL"); -} - -TEST(base62, Encoder) { - EXPECT_EQ(Base62::base62().decode("14q60P"), 987654321); - EXPECT_EQ(Base62::base62().encode(987654321), "14q60P"); - EXPECT_EQ(Base62::base62().encode("Hello world!"), "T8dgcjRGuYUueWht"); - EXPECT_EQ(Base62::inverted().encode("Hello world!"), "t8DGCJrgUyuUEwHT"); -} - -TEST(base64, Encoder) { - // Note Base64 encoding is NOT the same as the standard (rfc4648) - EXPECT_EQ(Base64::base64().encode("A"), "BB"); - EXPECT_EQ(Base64::base64().encode("AB"), "EFC"); - EXPECT_EQ(Base64::base64().encode("ABC"), "QUJD"); - EXPECT_EQ(Base64::base64().encode("ABCD"), "BBQkNE"); - EXPECT_EQ(Base64::base64().encode("ABCDE"), "EFCQ0RF"); - EXPECT_EQ(Base64::base64().encode("ABCDEF"), "QUJDREVG"); - EXPECT_EQ(Base64::base64().encode("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), "EFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFla"); - - EXPECT_EQ(Base64::rfc4648().encode("A"), "QQ=="); - EXPECT_EQ(Base64::rfc4648().encode("AB"), "QUI="); - EXPECT_EQ(Base64::rfc4648().encode("ABC"), "QUJD"); - EXPECT_EQ(Base64::rfc4648().encode("ABCD"), "QUJDRA=="); - EXPECT_EQ(Base64::rfc4648().encode("ABCDE"), "QUJDREU="); - EXPECT_EQ(Base64::rfc4648().encode("ABCDEF"), "QUJDREVG"); - EXPECT_EQ(Base64::rfc4648().encode("ABCDEFGHIJKLMNOPQRSTUVWXYZ"), "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVo="); -} - -TEST(base64, Decoder) { - // Note Base64 encoding is NOT the same as the standard (rfc4648) - EXPECT_EQ(Base64::base64().decode("BB"), "A"); - EXPECT_EQ(Base64::base64().decode("EFC"), "AB"); - EXPECT_EQ(Base64::base64().decode("QUJD"), "ABC"); - EXPECT_EQ(Base64::base64().decode("BBQkNE"), "ABCD"); - EXPECT_EQ(Base64::base64().decode("EFCQ0RF"), "ABCDE"); - EXPECT_EQ(Base64::base64().decode("QUJDREVG"), "ABCDEF"); - EXPECT_EQ(Base64::base64().decode("EFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFla"), "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - - EXPECT_EQ(Base64::rfc4648().decode("QQ=="), "A"); - EXPECT_EQ(Base64::rfc4648().decode("QUI="), "AB"); - EXPECT_EQ(Base64::rfc4648().decode("QUJD"), "ABC"); - EXPECT_EQ(Base64::rfc4648().decode("QUJDRA=="), "ABCD"); - EXPECT_EQ(Base64::rfc4648().decode("QUJDREU="), "ABCDE"); - EXPECT_EQ(Base64::rfc4648().decode("QUJDREVG"), "ABCDEF"); - EXPECT_EQ(Base64::rfc4648().decode("QUJDREVG\nR0hJSktM\nTU5PUFFS\nU1RVVldY\nWVo="), "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); -} - -TEST(base58, ShouldEncodeAndDecodeIntegers) { - auto data = 987654321; - - auto gmpEncoded = Base58::base58().encode(data); - auto bitcoinEncoded = Base58::bitcoin().encode(data); - auto rippleEncoded = Base58::ripple().encode(data); - auto flickrEncoded = Base58::flickr().encode(data); - - EXPECT_EQ(gmpEncoded, "1TFvCj"); - EXPECT_EQ(bitcoinEncoded, "2WGzDn"); - EXPECT_EQ(rippleEncoded, "pWGzD8"); - EXPECT_EQ(flickrEncoded, "2vgZdM"); - - auto gmpDecoded = Base58::base58().decode(gmpEncoded); - auto bitcoinDecoded = Base58::bitcoin().decode(bitcoinEncoded); - auto rippleDecoded = Base58::ripple().decode(rippleEncoded); - auto flickrDecoded = Base58::flickr().decode(flickrEncoded); - - EXPECT_EQ(gmpDecoded, data); - EXPECT_EQ(bitcoinDecoded, data); - EXPECT_EQ(rippleDecoded, data); - EXPECT_EQ(flickrDecoded, data); - - auto encoded = Base58::base58().encode(data); - auto decoded = Base58::base58().decode(encoded); - - EXPECT_EQ(decoded, data); -} - -TEST(base58, LongText) { - auto data = "Lorem ipsum dolor consectetur."; - - auto gmpEncoded = Base58::base58().encode(data); - auto bitcoinEncoded = Base58::bitcoin().encode(data); - auto rippleEncoded = Base58::ripple().encode(data); - auto flickrEncoded = Base58::flickr().encode(data); - - EXPECT_EQ(gmpEncoded, "FIHZQEpJ739QdqChX1PkgTBqP1FaDgJWQiGvY92YA"); - EXPECT_EQ(bitcoinEncoded, "GKJcTFtL84ATguDka2SojWCuS2GdEjLZTmHzbA3bB"); - EXPECT_EQ(rippleEncoded, "GKJcTEtL3hwTguDk2pSojWUuSpGdNjLZTmHzbwsbB"); - EXPECT_EQ(flickrEncoded, "gjiBsfTk84asFUdKz2rNJvcUr2gCeJkysLhZAa3Ab"); - - auto gmpDecoded = Base58::base58().decode(gmpEncoded); - auto bitcoinDecoded = Base58::bitcoin().decode(bitcoinEncoded); - auto rippleDecoded = Base58::ripple().decode(rippleEncoded); - auto flickrDecoded = Base58::flickr().decode(flickrEncoded); - - EXPECT_EQ(gmpDecoded, data); - EXPECT_EQ(bitcoinDecoded, data); - EXPECT_EQ(rippleDecoded, data); - EXPECT_EQ(flickrDecoded, data); -} - -TEST(base58, Tests) { - EXPECT_EQ(test_base2.encode(uinteger_t("000f", 16)), "1111"); - // EXPECT_EQ(test_base2.encode(uinteger_t("00ff", 16)), "011111111"); // ->> - EXPECT_EQ(test_base2.encode(uinteger_t("00ff", 16)), "11111111"); - EXPECT_EQ(test_base2.encode(uinteger_t("0fff", 16)), "111111111111"); - EXPECT_EQ(test_base2.encode(uinteger_t("ff00ff00", 16)), "11111111000000001111111100000000"); - // EXPECT_EQ(test_base16.encode(uinteger_t("0000000f", 16)), "000f"); // ->> - EXPECT_EQ(test_base16.encode(uinteger_t("0000000f", 16)), "f"); - // EXPECT_EQ(test_base16.encode(uinteger_t("000fff", 16)), "0fff"); // ->> - EXPECT_EQ(test_base16.encode(uinteger_t("000fff", 16)), "fff"); - EXPECT_EQ(test_base16.encode(uinteger_t("ffff", 16)), "ffff"); - // EXPECT_EQ(test_base58.encode(uinteger_t("", 16)), ""); // ->> - EXPECT_EQ(test_base58.encode(uinteger_t("", 16)), "1"); - EXPECT_EQ(test_base58.encode(uinteger_t("61", 16)), "2g"); - EXPECT_EQ(test_base58.encode(uinteger_t("626262", 16)), "a3gV"); - EXPECT_EQ(test_base58.encode(uinteger_t("636363", 16)), "aPEr"); - EXPECT_EQ(test_base58.encode(uinteger_t("73696d706c792061206c6f6e6720737472696e67", 16)), "2cFupjhnEsSn59qHXstmK2ffpLv2"); - // EXPECT_EQ(test_base58.encode(uinteger_t("00eb15231dfceb60925886b67d065299925915aeb172c06647", 16)), "1NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"); // ->> - EXPECT_EQ(test_base58.encode(uinteger_t("00eb15231dfceb60925886b67d065299925915aeb172c06647", 16)), "NS17iag9jJgTHD1VXjvLCEnZuQ3rJDE9L"); - EXPECT_EQ(test_base58.encode(uinteger_t("516b6fcd0f", 16)), "ABnLTmg"); - EXPECT_EQ(test_base58.encode(uinteger_t("bf4f89001e670274dd", 16)), "3SEo3LWLoPntC"); - EXPECT_EQ(test_base58.encode(uinteger_t("572e4794", 16)), "3EFU7m"); - EXPECT_EQ(test_base58.encode(uinteger_t("ecac89cad93923c02321", 16)), "EJDM8drfXA6uyA"); - EXPECT_EQ(test_base58.encode(uinteger_t("10c8511e", 16)), "Rt5zm"); - // EXPECT_EQ(test_base58.encode(uinteger_t("00000000000000000000", 16)), "1111111111"); // ->> - EXPECT_EQ(test_base58.encode(uinteger_t("00000000000000000000", 16)), "1"); - EXPECT_EQ(test_base58.encode(uinteger_t("801184cd2cdd640ca42cfc3a091c51d549b2f016d454b2774019c2b2d2e08529fd206ec97e", 16)), "5Hx15HFGyep2CfPxsJKe2fXJsCVn5DEiyoeGGF6JZjGbTRnqfiD"); - // EXPECT_EQ(test_base58.encode(uinteger_t("003c176e659bea0f29a3e9bf7880c112b1b31b4dc826268187", 16)), "16UjcYNBG9GTK4uq2f7yYEbuifqCzoLMGS"); // ->> - EXPECT_EQ(test_base58.encode(uinteger_t("003c176e659bea0f29a3e9bf7880c112b1b31b4dc826268187", 16)), "6UjcYNBG9GTK4uq2f7yYEbuifqCzoLMGS"); - EXPECT_EQ(test_base58.encode(uinteger_t("ffffffffffffffffffff", 16)), "FPBt6CHo3fovdL"); - EXPECT_EQ(test_base58.encode(uinteger_t("ffffffffffffffffffffffffff", 16)), "NKioeUVktgzXLJ1B3t"); - EXPECT_EQ(test_base58.encode(uinteger_t("ffffffffffffffffffffffffffffffff", 16)), "YcVfxkQb6JRzqk5kF2tNLv"); - EXPECT_EQ(test_base2.encode(uinteger_t("fb6f9ac3", 16)), "11111011011011111001101011000011"); - EXPECT_EQ(test_base2.encode(uinteger_t("179eea7a", 16)), "10111100111101110101001111010"); - EXPECT_EQ(test_base2.encode(uinteger_t("6db825db", 16)), "1101101101110000010010111011011"); - EXPECT_EQ(test_base2.encode(uinteger_t("93976aa7", 16)), "10010011100101110110101010100111"); - EXPECT_EQ(test_base58.encode(uinteger_t("ef41b9ce7e830af7", 16)), "h26E62FyLQN"); - EXPECT_EQ(test_base58.encode(uinteger_t("606cbc791036d2e9", 16)), "H8Sa62HVULG"); - EXPECT_EQ(test_base58.encode(uinteger_t("bdcb0ea69c2c8ec8", 16)), "YkESUPpnfoD"); - EXPECT_EQ(test_base58.encode(uinteger_t("1a2358ba67fb71d5", 16)), "5NaBN89ajtQ"); - EXPECT_EQ(test_base58.encode(uinteger_t("e6173f0f4d5fb5d7", 16)), "fVAoezT1ZkS"); - EXPECT_EQ(test_base58.encode(uinteger_t("91c81cbfdd58bbd2", 16)), "RPGNSU3bqTX"); - EXPECT_EQ(test_base58.encode(uinteger_t("329e0bf0e388dbfe", 16)), "9U41ZkwwysT"); - EXPECT_EQ(test_base58.encode(uinteger_t("30b10393210fa65b", 16)), "99NMW3WHjjY"); - EXPECT_EQ(test_base58.encode(uinteger_t("ab3bdd18e3623654", 16)), "VeBbqBb4rCT"); - EXPECT_EQ(test_base58.encode(uinteger_t("fe29d1751ec4af8a", 16)), "jWhmYLN9dUm"); - EXPECT_EQ(test_base58.encode(uinteger_t("c1273ab5488769807d", 16)), "3Tbh4kL3WKW6g"); - EXPECT_EQ(test_base58.encode(uinteger_t("6c7907904de934f852", 16)), "2P5jNYhfpTJxy"); - EXPECT_EQ(test_base58.encode(uinteger_t("05f0be055db47a0dc9", 16)), "5PN768Kr5oEp"); - EXPECT_EQ(test_base58.encode(uinteger_t("3511e6206829b35b12", 16)), "gBREojGaJ6DF"); - EXPECT_EQ(test_base58.encode(uinteger_t("d1c7c2ddc4a459d503", 16)), "3fsekq5Esq2KC"); - EXPECT_EQ(test_base58.encode(uinteger_t("1f88efd17ab073e9a1", 16)), "QHJbmW9ZY7jn"); - EXPECT_EQ(test_base58.encode(uinteger_t("0f45dadf4e64c5d5c2", 16)), "CGyVUMmCKLRf"); - EXPECT_EQ(test_base58.encode(uinteger_t("de1e5c5f718bb7fafa", 16)), "3pyy8U7w3KUa5"); - EXPECT_EQ(test_base58.encode(uinteger_t("123190b93e9a49a46c", 16)), "ES3DeFrG1zbd"); - EXPECT_EQ(test_base58.encode(uinteger_t("8bee94a543e7242e5a", 16)), "2nJnuWyLpGf6y"); - EXPECT_EQ(test_base58.encode(uinteger_t("9fd5f2285362f5cfd834", 16)), "9yqFhqeewcW3pF"); - EXPECT_EQ(test_base58.encode(uinteger_t("6987bac63ad23828bb31", 16)), "6vskE5Y1LhS3U4"); - EXPECT_EQ(test_base58.encode(uinteger_t("19d4a0f9d459cc2a08b0", 16)), "2TAsHPuaLhh5Aw"); - EXPECT_EQ(test_base58.encode(uinteger_t("a1e47ffdbea5a807ab26", 16)), "A6XzPgSUJDf1W5"); - EXPECT_EQ(test_base58.encode(uinteger_t("35c231e5b3a86a9b83db", 16)), "42B8reRwPAAoAa"); - EXPECT_EQ(test_base58.encode(uinteger_t("b2351012a48b8347c351", 16)), "B1hPyomGx4Vhqa"); - EXPECT_EQ(test_base58.encode(uinteger_t("71d402694dd9517ea653", 16)), "7Pv2SyAQx2Upu8"); - EXPECT_EQ(test_base58.encode(uinteger_t("55227c0ec7955c2bd6e8", 16)), "5nR64BkskyjHMq"); - EXPECT_EQ(test_base58.encode(uinteger_t("17b3d8ee7907c1be34df", 16)), "2LEg7TxosoxTGS"); - EXPECT_EQ(test_base58.encode(uinteger_t("7e7bba7b68bb8e95827f", 16)), "879o2ATGnmYyAW"); - EXPECT_EQ(test_base58.encode(uinteger_t("db9c13f5ba7654b01407fb", 16)), "wTYfxjDVbiks874"); - EXPECT_EQ(test_base58.encode(uinteger_t("6186449d20f5fd1e6c4393", 16)), "RBeiWhzZNL6VtMG"); - EXPECT_EQ(test_base58.encode(uinteger_t("5248751cebf4ad1c1a83c3", 16)), "MQSVNnc8ehFCqtW"); - EXPECT_EQ(test_base58.encode(uinteger_t("32090ef18cd479fc376a74", 16)), "DQdu351ExDaeYeX"); - EXPECT_EQ(test_base58.encode(uinteger_t("7cfa5d6ed1e467d986c426", 16)), "XzW67T5qfEnFcaZ"); - EXPECT_EQ(test_base58.encode(uinteger_t("9d8707723c7ede51103b6d", 16)), "g4eTCg6QJnB1UU4"); - EXPECT_EQ(test_base58.encode(uinteger_t("6f4d1e392d6a9b4ed8b223", 16)), "Ubo7kZY5aDpAJp2"); - EXPECT_EQ(test_base58.encode(uinteger_t("38057d98797cd39f80a0c9", 16)), "EtjQ2feamJvuqse"); - EXPECT_EQ(test_base58.encode(uinteger_t("de7e59903177e20880e915", 16)), "xB2N7yRBnDYEoT2"); - EXPECT_EQ(test_base58.encode(uinteger_t("b2ea24a28bc4a60b5c4b8d", 16)), "mNFMpJ2P3TGYqhv"); - EXPECT_EQ(test_base58.encode(uinteger_t("cf84938958589b6ffba6114d", 16)), "4v8ZbsGh2ePz5sipt"); - EXPECT_EQ(test_base58.encode(uinteger_t("dee13be7b8d8a08c94a3c02a", 16)), "5CwmE9jQqwtHkTF45"); - EXPECT_EQ(test_base58.encode(uinteger_t("14cb9c6b3f8cd2e02710f569", 16)), "Pm85JHVAAdeUdxtp"); - EXPECT_EQ(test_base58.encode(uinteger_t("ca3f2d558266bdcc44c79cb5", 16)), "4pMwomBAQHuUnoLUC"); - EXPECT_EQ(test_base58.encode(uinteger_t("c031215be44cbad745f38982", 16)), "4dMeTrcxiVw9RWvj3"); - EXPECT_EQ(test_base58.encode(uinteger_t("1435ab1dbc403111946270a5", 16)), "P7wX3sCWNrbqhBEC"); - EXPECT_EQ(test_base58.encode(uinteger_t("d8c6e4d775e7a66a0d0f9f41", 16)), "56GLoRDGWGuGJJwPN"); - EXPECT_EQ(test_base58.encode(uinteger_t("dcee35e74f0fd74176fce2f4", 16)), "5Ap1zyuYiJJFwWcMR"); - EXPECT_EQ(test_base58.encode(uinteger_t("bfcc0ca4b4855d1cf8993fc0", 16)), "4cvafQW4PEhARKv9D"); - EXPECT_EQ(test_base58.encode(uinteger_t("e02a3ac25ece7b54584b670a", 16)), "5EMM28xkpxZ1kkVUM"); - EXPECT_EQ(test_base58.encode(uinteger_t("fe4d938fc3719f064cabb4bfff", 16)), "NBXKkbHwrAsiWTLAk6"); - EXPECT_EQ(test_base58.encode(uinteger_t("9289cb4f6b15c57e6086b87ea5", 16)), "DCvDpjEXEbHjZqskKv"); - EXPECT_EQ(test_base58.encode(uinteger_t("fc266f35626b3612bfe978537b", 16)), "N186PVoBWrNre35BGE"); - EXPECT_EQ(test_base58.encode(uinteger_t("33ff08c06d92502bf258c07166", 16)), "5LC4SoW6jmTtbkbePw"); - EXPECT_EQ(test_base58.encode(uinteger_t("6a81cac1f3666bc59dc67b1c3c", 16)), "9sXgUySUzwiqDU5WHy"); - EXPECT_EQ(test_base58.encode(uinteger_t("9dfb8e7e744c544c0f323ea729", 16)), "EACsmGmkgcwsrPFzLg"); - EXPECT_EQ(test_base58.encode(uinteger_t("1e7a1e284f70838b38442b682b", 16)), "3YEVk9bE7rw5qExMkv"); - EXPECT_EQ(test_base58.encode(uinteger_t("2a862ad57901a8235f5dc74eaf", 16)), "4YS259nuTLfeXa5Wuc"); - EXPECT_EQ(test_base58.encode(uinteger_t("74c82096baef21f9d3089e5462", 16)), "AjAcKEhUfrqm8smvM7"); - EXPECT_EQ(test_base58.encode(uinteger_t("7a3edbc23d7b600263920261cc", 16)), "BBZXyRgey5S5DDZkcK"); - EXPECT_EQ(test_base58.encode(uinteger_t("20435664c357d25a9c8df751cf4f", 16)), "CrwNL6Fbv4pbRx1zd9g"); - EXPECT_EQ(test_base58.encode(uinteger_t("51a7aa87cf5cb1c12d045ec3422d", 16)), "X27NHGgKXmGzzQvDtpC"); - EXPECT_EQ(test_base58.encode(uinteger_t("344d2e116aa26f1062a2cb6ebbef", 16)), "LEDLDvL1Hg4qt1efVXt"); - EXPECT_EQ(test_base58.encode(uinteger_t("6941add7be4c0b5c7163e4928f8e", 16)), "fhMyN6gwoxE3uYraVzV"); - EXPECT_EQ(test_base58.encode(uinteger_t("10938fcbb7c4ab991649734a14bf", 16)), "76TPrSDxzGQfSzMu974"); - EXPECT_EQ(test_base58.encode(uinteger_t("eafe04d944ba504e9af9117b07de", 16)), "2VPgov563ryfe4L2Bj6M"); - EXPECT_EQ(test_base58.encode(uinteger_t("58d0aeed4d35da20b6f052127edf", 16)), "ZenZhXF9YwP8nQvNtNz"); - EXPECT_EQ(test_base58.encode(uinteger_t("d734984e2f5aecf25f7a3e353f8a", 16)), "2N7n3jFsTdyN49Faoq6h"); - EXPECT_EQ(test_base58.encode(uinteger_t("57d873fdb405b7daf4bafa62068a", 16)), "ZJ7NwoP4wHvwyZg3Wjs"); - EXPECT_EQ(test_base58.encode(uinteger_t("bda4ec7b40d0d65ca95dec4c4d3b", 16)), "2CijxjsNyvqTwPCfDcpA"); - EXPECT_EQ(test_base58.encode(uinteger_t("826c4abdceb1b91f0d4ad665f86d2e", 16)), "4edfvuDQu9KzVxLuXHfMo"); - EXPECT_EQ(test_base58.encode(uinteger_t("e7ecb35d07e65b960cb10574a4f51a", 16)), "7VLRYdB4cToipp2J2p3v9"); - EXPECT_EQ(test_base58.encode(uinteger_t("4f2d72ead87b31d6869fba39eac6dc", 16)), "3DUjqJRcfdWhpsrLrGcQs"); - EXPECT_EQ(test_base58.encode(uinteger_t("8b4f5788d60030950d5dfbf94c585d", 16)), "4u44JSRH5jP5X39YhPsmE"); - EXPECT_EQ(test_base58.encode(uinteger_t("ee4c0a0025d1a74ace9fe349355cc5", 16)), "7fgACjABRQUGUEpN6VBBA"); - EXPECT_EQ(test_base58.encode(uinteger_t("58ac05b9a0b4b66083ff1d489b8d84", 16)), "3UtJPyTwGXapcxHx8Rom5"); - EXPECT_EQ(test_base58.encode(uinteger_t("1aa35c05e1132e8e049aafaef035d8", 16)), "kE2eSU7gM2619pT82iGP"); - EXPECT_EQ(test_base58.encode(uinteger_t("771b0c28608484562a292e5d5d2b30", 16)), "4LGYeWhyfrjUByibUqdVR"); - EXPECT_EQ(test_base58.encode(uinteger_t("78ff9a0e56f9e88dc1cd654b40d019", 16)), "4PLggs66qAdbmZgkaPihe"); - EXPECT_EQ(test_base58.encode(uinteger_t("6d691bdd736346aa5a0a95b373b2ab", 16)), "44Y6qTgSvRMkdqpQ5ufkN"); -} diff --git a/contrib/base-x/uinteger_t.hh b/contrib/base-x/uinteger_t.hh deleted file mode 100644 index 901460f75c4..00000000000 --- a/contrib/base-x/uinteger_t.hh +++ /dev/null @@ -1,2546 +0,0 @@ -/* -uinteger_t.hh -An arbitrary precision unsigned integer type for C++ - -Copyright (c) 2017 German Mendez Bravo (Kronuz) @ german dot mb at gmail.com -Copyright (c) 2013 - 2017 Jason Lee @ calccrypto at gmail.com - -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. - -With much help from Auston Sterling - -Thanks to Stefan Deigmüller for finding -a bug in operator*. - -Thanks to François Dessenne for convincing me -to do a general rewrite of this class. - -Germán Mández Bravo (Kronuz) converted Jason Lee's uint128_t -to header-only and extended to arbitrary bit length. -*/ - -#ifndef __uint_t__ -#define __uint_t__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define ASSERT assert - -// Compatibility inlines -#ifndef __has_builtin // Optional of course -#define __has_builtin(x) 0 // Compatibility with non-clang compilers -#endif - -#if defined _MSC_VER -# define HAVE___ADDCARRY_U64 -# define HAVE___SUBBORROW_U64 -# define HAVE___ADDCARRY_U32 -# define HAVE___SUBBORROW_U32 -# define HAVE___ADDCARRY_U16 -# define HAVE___SUBBORROW_U16 -# define HAVE___UMUL128 -# define HAVE___UMUL64 -# define HAVE___UMUL32 -# include -#endif - -#if (defined(__clang__) && __has_builtin(__builtin_clzll)) || (defined(__GNUC__ ) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))) -# define HAVE____BUILTIN_CLZLL -#endif -#if (defined(__clang__) && __has_builtin(__builtin_clzl)) || (defined(__GNUC__ ) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))) -# define HAVE____BUILTIN_CLZL -#endif -#if (defined(__clang__) && __has_builtin(__builtin_clz)) || (defined(__GNUC__ ) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))) -# define HAVE____BUILTIN_CLZ -#endif -#if (defined(__clang__) && __has_builtin(__builtin_addcll)) -# define HAVE____BUILTIN_ADDCLL -#endif -#if (defined(__clang__) && __has_builtin(__builtin_addcl)) -# define HAVE____BUILTIN_ADDCL -#endif -#if (defined(__clang__) && __has_builtin(__builtin_addc)) -# define HAVE____BUILTIN_ADDC -#endif -#if (defined(__clang__) && __has_builtin(__builtin_subcll)) -# define HAVE____BUILTIN_SUBCLL -#endif -#if (defined(__clang__) && __has_builtin(__builtin_subcl)) -# define HAVE____BUILTIN_SUBCL -#endif -#if (defined(__clang__) && __has_builtin(__builtin_subc)) -# define HAVE____BUILTIN_SUBC -#endif - -#if defined __SIZEOF_INT128__ -#define HAVE____INT128_T -#endif - - -#ifndef DIGIT_T -#define DIGIT_T std::uint64_t -#endif - -#ifndef HALF_DIGIT_T -#define HALF_DIGIT_T std::uint32_t -#endif - -class uinteger_t; - -namespace std { // This is probably not a good idea - // Give uinteger_t type traits - template <> struct is_arithmetic : std::true_type {}; - template <> struct is_integral : std::true_type {}; - template <> struct is_unsigned : std::true_type {}; -} - -class uinteger_t { -public: - using digit = DIGIT_T; - using half_digit = HALF_DIGIT_T; - - static constexpr std::size_t digit_octets = sizeof(digit); // number of octets per digit - static constexpr std::size_t digit_bits = digit_octets * 8; // number of bits per digit - static constexpr std::size_t half_digit_octets = sizeof(half_digit); // number of octets per half_digit - static constexpr std::size_t half_digit_bits = half_digit_octets * 8; // number of bits per half_digit - - using container = std::vector; - - template - struct is_result { - static const bool value = false; - }; - - template - struct is_result> { - static const bool value = true; - }; - - template - struct is_result> { - static const bool value = true; - }; - -private: - static_assert(digit_octets == half_digit_octets * 2, "half_digit must be exactly half the size of digit"); - - static constexpr std::size_t karatsuba_cutoff = 1024 / digit_bits; - static constexpr double growth_factor = 1.5; - - std::size_t _begin; - std::size_t _end; - container _value_instance; - container& _value; - bool _carry; - -public: - // Window to vector (uses _begin and _end) - - void reserve(std::size_t sz) { - _value.reserve(sz + _begin); - } - - std::size_t grow(std::size_t n) { - // expands the vector using a growth factor - // and returns the new capacity. - auto cc = _value.capacity(); - if (n >= cc) { - cc = n * growth_factor; - _value.reserve(cc); - } - return cc; - } - - void resize(std::size_t sz) { - grow(sz + _begin); - _value.resize(sz + _begin); - } - - void resize(std::size_t sz, const digit& c) { - grow(sz + _begin); - _value.resize(sz + _begin, c); - } - - void clear() { - _value.clear(); - _begin = 0; - _end = 0; - _carry = false; - } - - digit* data() noexcept { - return _value.data() + _begin; - } - - const digit* data() const noexcept { - return _value.data() + _begin; - } - - std::size_t size() const noexcept { - return _end ? _end - _begin : _value.size() - _begin; - } - - void prepend(std::size_t sz, const digit& c) { - // Efficiently prepend by growing backwards by growth factor - auto min = std::min(_begin, sz); - if (min) { - // If there is some space before `_begin`, we try using it first: - _begin -= min; - std::fill_n(_value.begin() + _begin, min, c); - sz -= min; - } - if (sz) { - ASSERT(_begin == 0); // _begin should be 0 in here - // If there's still more room needed, we grow the vector: - // Ex.: grow using prepend(3, y) - // sz = 3 - // _begin = 0 (B) - // _end = 1 (E) - // initially (capacity == 12): - // |xxxxxxxxxx- | - // B E - // after reclaiming space after `_end` (same capacity == 12): - // |xxxxxxxxxx | - // B - // _end = 0 - // csz = 10 - // grow returns the new capacity (22) - // isz = 12 (22 - 10) - // _begin = 9 (12 - 3) - // after (capacity == (12 + 3) * 1.5 == 22): - // |---------yyyxxxxxxxxxx| - // B - if (_end) { - // reclaim space after `_end` - _value.resize(_end); - _end = 0; - } - auto csz = _value.size(); - auto isz = grow(csz + sz) - csz; - _value.insert(_value.begin(), isz, c); - _begin = isz - sz; - } - } - - void prepend(const digit& c) { - prepend(1, c); - } - - void prepend(const uinteger_t& num) { - prepend(num.size(), 0); - std::copy(num.begin(), num.end(), begin()); - } - - void append(std::size_t sz, const digit& c) { - // Efficiently append by growing by growth factor - if (_end) { - // reclaim space after `_end` - _value.resize(_end); - _end = 0; - } - auto nsz = _value.size() + sz; - grow(nsz); - _value.resize(nsz, c); - } - - void append(const digit& c) { - append(1, c); - } - - void append(const uinteger_t& num) { - auto sz = num.size(); - append(sz, 0); - std::copy(num.begin(), num.end(), end() - sz); - } - - container::iterator begin() noexcept { - return _value.begin() + _begin; - } - - container::const_iterator begin() const noexcept { - return _value.cbegin() + _begin; - } - - container::iterator end() noexcept { - return _end ? _value.begin() + _end : _value.end(); - } - - container::const_iterator end() const noexcept { - return _end ? _value.cbegin() + _end : _value.cend(); - } - - container::reverse_iterator rbegin() noexcept { - return _end ? container::reverse_iterator(_value.begin() + _end) : _value.rbegin(); - } - - container::const_reverse_iterator rbegin() const noexcept { - return _end ? container::const_reverse_iterator(_value.cbegin() + _end) : _value.crbegin(); - } - - container::reverse_iterator rend() noexcept { - return container::reverse_iterator(_value.begin() + _begin); - } - - container::const_reverse_iterator rend() const noexcept { - return container::const_reverse_iterator(_value.cbegin() + _begin); - } - - container::reference front() { - return *begin(); - } - - container::const_reference front() const { - return *begin(); - } - - container::reference back() { - return *rbegin(); - } - - container::const_reference back() const { - return *rbegin(); - } - -private: - // Optimized primitives for operations - - static digit _bits(digit x) { - #if defined HAVE____BUILTIN_CLZLL - if (digit_octets == sizeof(unsigned long long)) { - return x ? digit_bits - __builtin_clzll(x) : 1; - } - #endif - #if defined HAVE____BUILTIN_CLZL - if (digit_octets == sizeof(unsigned long)) { - return x ? digit_bits - __builtin_clzl(x) : 1; - } - #endif - #if defined HAVE____BUILTIN_CLZ - if (digit_octets == sizeof(unsigned)) { - return x ? digit_bits - __builtin_clz(x) : 1; - } - #endif - { - digit c = x ? 0 : 1; - while (x) { - x >>= 1; - ++c; - } - return c; - } - } - - static digit _mult(digit x, digit y, digit* lo) { - #if defined HAVE___UMUL128 - if (digit_bits == 64) { - digit h; - digit l = _umul128(x, y, &h); // _umul128(x, y, *hi) -> lo - return h; - } - #endif - #if defined HAVE___UMUL64 - if (digit_bits == 32) { - digit h; - digit l = _umul64(x, y, &h); // _umul64(x, y, *hi) -> lo - return h; - } - #endif - #if defined HAVE___UMUL32 - if (digit_bits == 16) { - digit h; - digit l = _umul32(x, y, &h); // _umul32(x, y, *hi) -> lo - return h; - } - #endif - #if defined HAVE____INT128_T - if (digit_bits == 64) { - auto r = static_cast<__uint128_t>(x) * static_cast<__uint128_t>(y); - *lo = r; - return r >> digit_bits; - } - #endif - if (digit_bits == 64) { - digit x0 = x & 0xffffffffUL; - digit x1 = x >> 32; - digit y0 = y & 0xffffffffUL; - digit y1 = y >> 32; - - digit u = (x0 * y0); - digit v = (x1 * y0) + (u >> 32); - digit w = (x0 * y1) + (v & 0xffffffffUL); - - *lo = (w << 32) + (u & 0xffffffffUL); // low - return (x1 * y1) + (v >> 32) + (w >> 32); // high - } if (digit_bits == 32) { - auto r = static_cast(x) * static_cast(y); - *lo = r; - return r >> 32; - } if (digit_bits == 16) { - auto r = static_cast(x) * static_cast(y); - *lo = r; - return r >> 16; - } if (digit_bits == 8) { - auto r = static_cast(x) * static_cast(y); - *lo = r; - return r >> 8; - } - } - - static digit _multadd(digit x, digit y, digit a, digit c, digit* lo) { - #if defined HAVE___UMUL128 && defined HAVE___ADDCARRY_U64 - if (digit_bits == 64) { - digit h; - digit l = _umul128(x, y, &h); // _umul128(x, y, *hi) -> lo - return h + _addcarry_u64(c, l, a, lo); // _addcarry_u64(carryin, x, y, *sum) -> carryout - } - #endif - #if defined HAVE___UMUL64 && defined HAVE___ADDCARRY_U32 - if (digit_bits == 32) { - digit h; - digit l = _umul64(x, y, &h); // _umul64(x, y, *hi) -> lo - return h + _addcarry_u32(c, l, a, lo); // _addcarry_u32(carryin, x, y, *sum) -> carryout - } - #endif - #if defined HAVE___UMUL32 && defined HAVE___ADDCARRY_U16 - if (digit_bits == 16) { - digit h; - digit l = _umul32(x, y, &h); // _umul32(x, y, *hi) -> lo - return h + _addcarry_u16(c, l, a, lo); // _addcarry_u16(carryin, x, y, *sum) -> carryout - } - #endif - #if defined HAVE____INT128_T - if (digit_bits == 64) { - auto r = static_cast<__uint128_t>(x) * static_cast<__uint128_t>(y) + static_cast<__uint128_t>(a) + static_cast<__uint128_t>(c); - *lo = r; - return r >> digit_bits; - } - #endif - if (digit_bits == 64) { - digit x0 = x & 0xffffffffUL; - digit x1 = x >> 32; - digit y0 = y & 0xffffffffUL; - digit y1 = y >> 32; - - digit u = (x0 * y0) + (a & 0xffffffffUL) + (c & 0xffffffffUL); - digit v = (x1 * y0) + (u >> 32) + (a >> 32) + (c >> 32); - digit w = (x0 * y1) + (v & 0xffffffffUL); - - *lo = (w << 32) + (u & 0xffffffffUL); // low - return (x1 * y1) + (v >> 32) + (w >> 32); // high - } - if (digit_bits == 32) { - auto r = static_cast(x) * static_cast(y) + static_cast(a) + static_cast(c); - *lo = r; - return r >> 32; - } - if (digit_bits == 16) { - auto r = static_cast(x) * static_cast(y) + static_cast(a) + static_cast(c); - *lo = r; - return r >> 16; - } - if (digit_bits == 8) { - auto r = static_cast(x) * static_cast(y) + static_cast(a) + static_cast(c); - *lo = r; - return r >> 8; - } - } - - static digit _divmod(digit x_hi, digit x_lo, digit y, digit* result) { - #if defined HAVE____INT128_T - if (digit_bits == 64) { - auto x = static_cast<__uint128_t>(x_hi) << digit_bits | static_cast<__uint128_t>(x_lo); - digit q = x / y; - digit r = x % y; - - *result = q; - return r; - } - #endif - if (digit_bits == 64) { - // quotient - digit q = x_lo << 1; - - // remainder - digit r = x_hi; - - digit carry = x_lo >> 63; - int i; - - for (i = 0; i < 64; i++) { - auto tmp = r >> 63; - r <<= 1; - r |= carry; - carry = tmp; - - if (carry == 0) { - if (r >= y) { - carry = 1; - } else { - tmp = q >> 63; - q <<= 1; - q |= carry; - carry = tmp; - continue; - } - } - - r -= y; - r -= (1 - carry); - carry = 1; - tmp = q >> 63; - q <<= 1; - q |= carry; - carry = tmp; - } - - *result = q; - return r; - } - if (digit_bits == 32) { - auto x = static_cast(x_hi) << 32 | static_cast(x_lo); - digit q = x / y; - digit r = x % y; - - *result = q; - return r; - } - if (digit_bits == 16) { - auto x = static_cast(x_hi) << 16 | static_cast(x_lo); - digit q = x / y; - digit r = x % y; - - *result = q; - return r; - } - if (digit_bits == 8) { - auto x = static_cast(x_hi) << 8 | static_cast(x_lo); - digit q = x / y; - digit r = x % y; - - *result = q; - return r; - } - } - - static digit _addcarry(digit x, digit y, digit c, digit* result) { - #if defined HAVE___ADDCARRY_U64 - if (digit_bits == 64) { - return _addcarry_u64(c, x, y, result); // _addcarry_u64(carryin, x, y, *sum) -> carryout - } - #endif - #if defined HAVE___ADDCARRY_U32 - if (digit_bits == 32) { - return _addcarry_u32(c, x, y, result); // _addcarry_u32(carryin, x, y, *sum) -> carryout - } - #endif - #if defined HAVE___ADDCARRY_U16 - if (digit_bits == 16) { - return _addcarry_u16(c, x, y, result); // _addcarry_u16(carryin, x, y, *sum) -> carryout - } - #endif - #if defined HAVE____BUILTIN_ADDCLL - if (digit_octets == sizeof(unsigned long long)) { - unsigned long long carryout; - *result = __builtin_addcll(x, y, c, &carryout); // __builtin_addcll(x, y, carryin, *carryout) -> sum - return carryout; - } - #endif - #if defined HAVE____BUILTIN_ADDCL - if (digit_octets == sizeof(unsigned long)) { - unsigned long carryout; - *result = __builtin_addcl(x, y, c, &carryout); // __builtin_addcl(x, y, carryin, *carryout) -> sum - return carryout; - } - #endif - #if defined HAVE____BUILTIN_ADDC - if (digit_octets == sizeof(unsigned)) { - unsigned carryout; - *result = __builtin_addc(x, y, c, &carryout); // __builtin_addc(x, y, carryin, *carryout) -> sum - return carryout; - } - #endif - #if defined HAVE____INT128_T - if (digit_bits == 64) { - auto r = static_cast<__uint128_t>(x) + static_cast<__uint128_t>(y) + static_cast<__uint128_t>(c); - *result = r; - return static_cast(r >> digit_bits); - } - #endif - if (digit_bits == 64) { - digit x0 = x & 0xffffffffUL; - digit x1 = x >> 32; - digit y0 = y & 0xffffffffUL; - digit y1 = y >> 32; - - auto u = x0 + y0 + c; - auto v = x1 + y1 + static_cast(u >> 32); - *result = (v << 32) + (u & 0xffffffffUL); - return static_cast(v >> 32); - } - if (digit_bits == 32) { - auto r = static_cast(x) + static_cast(y) + static_cast(c); - *result = r; - return static_cast(r >> 32); - } - if (digit_bits == 16) { - auto r = static_cast(x) + static_cast(y) + static_cast(c); - *result = r; - return static_cast(r >> 16); - } - if (digit_bits == 8) { - auto r = static_cast(x) + static_cast(y) + static_cast(c); - *result = r; - return static_cast(r >> 8); - } - } - - static digit _subborrow(digit x, digit y, digit c, digit* result) { - #if defined HAVE___SUBBORROW_U64 - if (digit_bits == 64) { - return _subborrow_u64(c, x, y, result); // _subborrow_u64(carryin, x, y, *sum) -> carryout - } - #endif - #if defined HAVE___SUBBORROW_U32 - if (digit_bits == 64) { - return _subborrow_u32(c, x, y, result); // _subborrow_u32(carryin, x, y, *sum) -> carryout - } - #endif - #if defined HAVE___SUBBORROW_U16 - if (digit_bits == 64) { - return _subborrow_u16(c, x, y, result); // _subborrow_u16(carryin, x, y, *sum) -> carryout - } - #endif - #if defined HAVE____BUILTIN_SUBCLL - if (digit_octets == sizeof(unsigned long long)) { - unsigned long long carryout; - *result = __builtin_subcll(x, y, c, &carryout); // __builtin_subcll(x, y, carryin, *carryout) -> sum - return carryout; - } - #endif - #if defined HAVE____BUILTIN_SUBCL - if (digit_octets == sizeof(unsigned long)) { - unsigned long carryout; - *result = __builtin_subcl(x, y, c, &carryout); // __builtin_subcl(x, y, carryin, *carryout) -> sum - return carryout; - } - #endif - #if defined HAVE____BUILTIN_SUBC - if (digit_octets == sizeof(unsigned)) { - unsigned carryout; - *result = __builtin_subc(x, y, c, &carryout); // __builtin_subc(x, y, carryin, *carryout) -> sum - return carryout; - } - #endif - #if defined HAVE____INT128_T - if (digit_bits == 64) { - auto r = static_cast<__uint128_t>(x) - static_cast<__uint128_t>(y) - static_cast<__uint128_t>(c); - *result = r; - return static_cast(r >> 64); - } - #endif - if (digit_bits == 64) { - digit x0 = x & 0xffffffffUL; - digit x1 = x >> 32; - digit y0 = y & 0xffffffffUL; - digit y1 = y >> 32; - - auto u = x0 - y0 - c; - auto v = x1 - y1 - static_cast(u >> 32); - *result = (v << 32) + (u & 0xffffffffUL); - return static_cast(v >> 32); - } - if (digit_bits == 32) { - auto r = static_cast(x) - static_cast(y) - static_cast(c); - *result = r; - return static_cast(r >> 32); - } - if (digit_bits == 16) { - auto r = static_cast(x) - static_cast(y) - static_cast(c); - *result = r; - return static_cast(r >> 16); - } - if (digit_bits == 8) { - auto r = static_cast(x) - static_cast(y) - static_cast(c); - *result = r; - return static_cast(r >> 8); - } - } - - // Helper functions - - void trim(digit mask = 0) { - auto rit = rbegin(); - auto rit_e = rend(); - - // Masks the last value of internal vector - mask &= (digit_bits - 1); - if (mask && rit != rit_e) { - *rit &= (static_cast(1) << mask) - 1; - } - - // Removes all unused zeros from the internal vector - auto rit_f = std::find_if(rit, rit_e, [](const digit& c) { return c; }); - resize(rit_e - rit_f); // shrink - } - - static constexpr char chr(int ord) { - constexpr const char _[256] = { - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', - 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - }; - return _[ord]; - } - - static constexpr int ord(int chr) { - constexpr const int _[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, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, - - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - }; - return _[chr]; - } - -public: - static constexpr unsigned base_bits(int base) { - constexpr const unsigned _[256] = { - 0, 1, 0, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, - }; - return _[base - 1]; - } - - static constexpr unsigned base_size(int base) { - constexpr const unsigned _[256] = { - 0, 64, 41, 32, 28, 25, 23, 22, 21, 20, 19, 18, 18, 17, 17, 16, - 16, 16, 16, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 13, 13, - 13, 13, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, - - 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, - - 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, - }; - return _[base - 1]; - } - - static const uinteger_t uint_0() { - static uinteger_t uint_0(0); - return uint_0; - } - - static const uinteger_t uint_1() { - static uinteger_t uint_1(1); - return uint_1; - } - -private: - // Public Implementation -#ifdef UINT_T_PUBLIC_IMPLEMENTATION -public: -#endif - static uinteger_t& bitwise_and(uinteger_t& lhs, const uinteger_t& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - - if (lhs_sz > rhs_sz) { - lhs.resize(rhs_sz); // shrink - } - - auto lhs_it = lhs.begin(); - auto lhs_it_e = lhs.end(); - - auto rhs_it = rhs.begin(); - - for (; lhs_it != lhs_it_e; ++lhs_it, ++rhs_it) { - *lhs_it &= *rhs_it; - } - - // Finish up - lhs.trim(); - return lhs; - } - - static uinteger_t& bitwise_and(uinteger_t& result, const uinteger_t& lhs, const uinteger_t& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - - auto result_sz = std::max(lhs_sz, rhs_sz); - result.resize(result_sz); - - // not using `end()` because resize of `result.resize()` could have - // resized `lhs` or `rhs` if `result` is also either `rhs` or `lhs`. - auto lhs_it = lhs.begin(); - auto lhs_it_e = lhs_it + lhs_sz; - - auto rhs_it = rhs.begin(); - auto rhs_it_e = rhs_it + rhs_sz; - - auto it = result.begin(); - - if (lhs_sz < rhs_sz) { - for (; lhs_it != lhs_it_e; ++lhs_it, ++rhs_it, ++it) { - *it = *lhs_it & *rhs_it; - } - for (; rhs_it != rhs_it_e; ++rhs_it, ++it) { - *it = 0; - } - } else { - for (; rhs_it != rhs_it_e; ++lhs_it, ++rhs_it, ++it) { - *it = *lhs_it & *rhs_it; - } - for (; lhs_it != lhs_it_e; ++lhs_it, ++it) { - *it = 0; - } - } - - // Finish up - result.trim(); - return result; - } - - static uinteger_t bitwise_and(const uinteger_t& lhs, const uinteger_t& rhs) { - uinteger_t result; - bitwise_and(result, lhs, rhs); - return result; - } - - static uinteger_t& bitwise_or(uinteger_t& lhs, const uinteger_t& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - - if (lhs_sz < rhs_sz) { - lhs.resize(rhs_sz, 0); // grow - } - - auto lhs_it = lhs.begin(); - - auto rhs_it = rhs.begin(); - auto rhs_it_e = rhs.end(); - - for (; rhs_it != rhs_it_e; ++lhs_it, ++rhs_it) { - *lhs_it |= *rhs_it; - } - - // Finish up - lhs.trim(); - return lhs; - } - - static uinteger_t& bitwise_or(uinteger_t& result, const uinteger_t& lhs, const uinteger_t& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - - auto result_sz = std::max(lhs_sz, rhs_sz); - result.resize(result_sz); - - // not using `end()` because resize of `result.resize()` could have - // resized `lhs` or `rhs` if `result` is also either `rhs` or `lhs`. - auto lhs_it = lhs.begin(); - auto lhs_it_e = lhs_it + lhs_sz; - - auto rhs_it = rhs.begin(); - auto rhs_it_e = rhs_it + rhs_sz; - - auto it = result.begin(); - - if (lhs_sz < rhs_sz) { - for (; lhs_it != lhs_it_e; ++lhs_it, ++rhs_it, ++it) { - *it = *lhs_it | *rhs_it; - } - for (; rhs_it != rhs_it_e; ++rhs_it, ++it) { - *it = *rhs_it; - } - } else { - for (; rhs_it != rhs_it_e; ++lhs_it, ++rhs_it, ++it) { - *it = *lhs_it | *rhs_it; - } - for (; lhs_it != lhs_it_e; ++lhs_it, ++it) { - *it = *lhs_it; - } - } - - // Finish up - result.trim(); - return result; - } - static uinteger_t bitwise_or(const uinteger_t& lhs, const uinteger_t& rhs) { - uinteger_t result; - bitwise_or(result, lhs, rhs); - return result; - } - - static uinteger_t& bitwise_xor(uinteger_t& lhs, const uinteger_t& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - - if (lhs_sz < rhs_sz) { - lhs.resize(rhs_sz, 0); // grow - } - - auto lhs_it = lhs.begin(); - - auto rhs_it = rhs.begin(); - auto rhs_it_e = rhs.end(); - - for (; rhs_it != rhs_it_e; ++lhs_it, ++rhs_it) { - *lhs_it ^= *rhs_it; - } - - // Finish up - lhs.trim(); - return lhs; - } - - static uinteger_t& bitwise_xor(uinteger_t& result, const uinteger_t& lhs, const uinteger_t& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - - auto result_sz = std::max(lhs_sz, rhs_sz); - result.resize(result_sz); - - // not using `end()` because resize of `result.resize()` could have - // resized `lhs` or `rhs` if `result` is also either `rhs` or `lhs`. - auto lhs_it = lhs.begin(); - auto lhs_it_e = lhs_it + lhs_sz; - - auto rhs_it = rhs.begin(); - auto rhs_it_e = rhs_it + rhs_sz; - - auto it = result.begin(); - - if (lhs_sz < rhs_sz) { - for (; lhs_it != lhs_it_e; ++lhs_it, ++rhs_it, ++it) { - *it = *lhs_it ^ *rhs_it; - } - for (; rhs_it != rhs_it_e; ++rhs_it, ++it) { - *it = *rhs_it; - } - } else { - for (; rhs_it != rhs_it_e; ++lhs_it, ++rhs_it, ++it) { - *it = *lhs_it ^ *rhs_it; - } - for (; lhs_it != lhs_it_e; ++lhs_it, ++it) { - *it = *lhs_it; - } - } - - // Finish up - result.trim(); - return result; - } - - static uinteger_t bitwise_xor(const uinteger_t& lhs, const uinteger_t& rhs) { - uinteger_t result; - bitwise_xor(result, lhs, rhs); - return result; - } - - static uinteger_t& bitwise_inv(uinteger_t& lhs) { - auto lhs_sz = lhs.size(); - - auto b = lhs.bits(); - - if (!lhs_sz) { - lhs.append(0); - } - - // not using `end()` because resize of `result.resize()` could have - // resized `lhs` if `result` is also `lhs`. - auto lhs_it = lhs.begin(); - auto lhs_it_e = lhs_it + lhs_sz; - - for (; lhs_it != lhs_it_e; ++lhs_it) { - *lhs_it = ~*lhs_it; - } - - // Finish up - lhs.trim(b ? b : 1); - return lhs; - } - - static uinteger_t& bitwise_inv(uinteger_t& result, const uinteger_t& lhs) { - auto lhs_sz = lhs.size(); - - auto b = lhs.bits(); - - auto result_sz = lhs_sz ? lhs_sz : 1; - result.resize(result_sz); - - // not using `end()` because resize of `result.resize()` could have - // resized `lhs` if `result` is also `lhs`. - auto lhs_it = lhs.begin(); - auto lhs_it_e = lhs_it + lhs_sz; - - auto it = result.begin(); - auto it_e = it + result_sz; - - for (; lhs_it != lhs_it_e; ++lhs_it, ++it) { - *it = ~*lhs_it; - } - for (; it != it_e; ++it) { - *it = ~static_cast(0); - } - - // Finish up - result.trim(b ? b : 1); - return result; - } - - static uinteger_t bitwise_inv(const uinteger_t& lhs) { - uinteger_t result; - bitwise_inv(result, lhs); - return result; - } - - static uinteger_t& bitwise_lshift(uinteger_t& lhs, const uinteger_t& rhs) { - if (!rhs) { - return lhs; - } - - uinteger_t shifts_q; - uinteger_t shifts_r; - auto _digit_bits = digit_bits; - auto uint_digit_bits = uinteger_t(_digit_bits); - divmod(shifts_q, shifts_r, rhs, uint_digit_bits); - std::size_t shifts = static_cast(shifts_q); - std::size_t shift = static_cast(shifts_r); - - if (shifts) { - lhs.prepend(shifts, 0); - } - if (shift) { - digit shifted = 0; - auto lhs_it = lhs.begin() + shifts; - auto lhs_it_e = lhs.end(); - for (; lhs_it != lhs_it_e; ++lhs_it) { - auto v = (*lhs_it << shift) | shifted; - shifted = *lhs_it >> (_digit_bits - shift); - *lhs_it = v; - } - if (shifted) { - lhs.append(shifted); - } - } - - // Finish up - lhs.trim(); - return lhs; - } - - static uinteger_t& bitwise_lshift(uinteger_t& result, const uinteger_t& lhs, const uinteger_t& rhs) { - if (&result._value == &lhs._value) { - bitwise_lshift(result, rhs); - return result; - } - if (!rhs) { - result = lhs; - return result; - } - - auto lhs_sz = lhs.size(); - - uinteger_t shifts_q; - uinteger_t shifts_r; - auto _digit_bits = digit_bits; - auto uint_digit_bits = uinteger_t(_digit_bits); - divmod(shifts_q, shifts_r, rhs, uint_digit_bits); - std::size_t shifts = static_cast(shifts_q); - std::size_t shift = static_cast(shifts_r); - - auto result_sz = lhs_sz + shifts; - result.grow(result_sz + 1); - result.resize(shifts, 0); - result.resize(result_sz); - - // not using `end()` because resize of `result.resize()` could have - // resized `lhs` if `result` is also `lhs`. - auto lhs_it = lhs.begin(); - auto lhs_it_e = lhs_it + lhs_sz; - - auto it = result.begin() + shifts; - - if (shift) { - digit shifted = 0; - for (; lhs_it != lhs_it_e; ++lhs_it, ++it) { - auto v = (*lhs_it << shift) | shifted; - shifted = *lhs_it >> (_digit_bits - shift); - *it = v; - } - if (shifted) { - result.append(shifted); - } - } else { - for (; lhs_it != lhs_it_e; ++lhs_it, ++it) { - *it = *lhs_it; - } - } - - // Finish up - result.trim(); - return result; - } - - static uinteger_t bitwise_lshift(const uinteger_t& lhs, const uinteger_t& rhs) { - uinteger_t result; - bitwise_lshift(result, lhs, rhs); - return result; - } - - static uinteger_t& bitwise_rshift(uinteger_t& lhs, const uinteger_t& rhs) { - if (!rhs) { - return lhs; - } - - auto lhs_sz = lhs.size(); - - auto _digit_bits = digit_bits; - if (compare(rhs, uinteger_t(lhs_sz * _digit_bits)) >= 0) { - lhs = uint_0(); - return lhs; - } - - uinteger_t shifts_q; - uinteger_t shifts_r; - auto uint_digit_bits = uinteger_t(_digit_bits); - divmod(shifts_q, shifts_r, rhs, uint_digit_bits); - std::size_t shifts = static_cast(shifts_q); - std::size_t shift = static_cast(shifts_r); - - if (shifts) { - lhs._begin += shifts; - } - if (shift) { - digit shifted = 0; - auto lhs_rit = lhs.rbegin(); - auto lhs_rit_e = lhs.rend(); - for (; lhs_rit != lhs_rit_e; ++lhs_rit) { - auto v = (*lhs_rit >> shift) | shifted; - shifted = *lhs_rit << (_digit_bits - shift); - *lhs_rit = v; - } - lhs.trim(); - } - - return lhs; - } - - static uinteger_t& bitwise_rshift(uinteger_t& result, const uinteger_t& lhs, const uinteger_t& rhs) { - if (&result._value == &lhs._value) { - bitwise_lshift(result, rhs); - return result; - } - if (!rhs) { - result = lhs; - return result; - } - - auto lhs_sz = lhs.size(); - - auto _digit_bits = digit_bits; - if (compare(rhs, uinteger_t(lhs_sz * _digit_bits)) >= 0) { - result = uint_0(); - return result; - } - - uinteger_t shifts_q; - uinteger_t shifts_r; - auto uint_digit_bits = uinteger_t(_digit_bits); - divmod(shifts_q, shifts_r, rhs, uint_digit_bits); - std::size_t shifts = static_cast(shifts_q); - std::size_t shift = static_cast(shifts_r); - - auto result_sz = lhs_sz - shifts; - result.resize(result_sz); - - // not using `end()` because resize of `result.resize()` could have - // resized `lhs` if `result` is also `lhs`. - auto lhs_rit = lhs.rbegin(); - auto lhs_rit_e = lhs_rit + lhs_sz - shifts; - - auto rit = result.rbegin(); - auto rit_e = rit + result_sz; - - if (shift) { - digit shifted = 0; - for (; lhs_rit != lhs_rit_e; ++lhs_rit, ++rit) { - ASSERT(rit != rit_e); (void)(rit_e); - auto v = (*lhs_rit >> shift) | shifted; - shifted = *lhs_rit << (_digit_bits - shift); - *rit = v; - } - } else { - for (; lhs_rit != lhs_rit_e; ++lhs_rit, ++rit) { - ASSERT(rit != rit_e); (void)(rit_e); - *rit = *lhs_rit; - } - } - - // Finish up - result.trim(); - return result; - } - - static uinteger_t bitwise_rshift(const uinteger_t& lhs, const uinteger_t& rhs) { - uinteger_t result; - bitwise_rshift(result, lhs, rhs); - return result; - } - - static int compare(const uinteger_t& lhs, const uinteger_t& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - - if (lhs_sz > rhs_sz) return 1; - if (lhs_sz < rhs_sz) return -1; - - auto lhs_rit = lhs.rbegin(); - auto lhs_rit_e = lhs.rend(); - - auto rhs_rit = rhs.rbegin(); - - for (; lhs_rit != lhs_rit_e && *lhs_rit == *rhs_rit; ++lhs_rit, ++rhs_rit); - - if (lhs_rit != lhs_rit_e) { - if (*lhs_rit > *rhs_rit) return 1; - if (*lhs_rit < *rhs_rit) return -1; - } - - return 0; - } - - static uinteger_t& long_add(uinteger_t& lhs, const uinteger_t& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - - if (lhs_sz < rhs_sz) { - lhs.reserve(rhs_sz + 1); - lhs.resize(rhs_sz, 0); // grow - } - - // not using `end()` because resize of `lhs.resize()` could have - // resized `lhs`. - auto lhs_it = lhs.begin(); - auto lhs_it_e = lhs_it + lhs_sz; - - auto rhs_it = rhs.begin(); - auto rhs_it_e = rhs_it + rhs_sz; - - digit carry = 0; - if (lhs_sz < rhs_sz) { - for (; lhs_it != lhs_it_e; ++rhs_it, ++lhs_it) { - carry = _addcarry(*lhs_it, *rhs_it, carry, &*lhs_it); - } - for (; carry && rhs_it != rhs_it_e; ++rhs_it, ++lhs_it) { - carry = _addcarry(0, *rhs_it, carry, &*lhs_it); - } - for (; rhs_it != rhs_it_e; ++rhs_it, ++lhs_it) { - *lhs_it = *rhs_it; - } - } else { - for (; rhs_it != rhs_it_e; ++rhs_it, ++lhs_it) { - carry = _addcarry(*lhs_it, *rhs_it, carry, &*lhs_it); - } - for (; carry && lhs_it != lhs_it_e; ++lhs_it) { - carry = _addcarry(*lhs_it, 0, carry, &*lhs_it); - } - } - - if (carry) { - lhs.append(1); - } - - lhs._carry = false; - - // Finish up - lhs.trim(); - return lhs; - } - - static uinteger_t& long_add(uinteger_t& result, const uinteger_t& lhs, const uinteger_t& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - - auto result_sz = std::max(lhs_sz, rhs_sz); - result.reserve(result_sz + 1); - result.resize(result_sz, 0); - - // not using `end()` because resize of `result.resize()` could have - // resized `lhs` or `rhs` if `result` is also either `rhs` or `lhs`. - auto lhs_it = lhs.begin(); - auto lhs_it_e = lhs_it + lhs_sz; - - auto rhs_it = rhs.begin(); - auto rhs_it_e = rhs_it + rhs_sz; - - auto it = result.begin(); - - digit carry = 0; - if (lhs_sz < rhs_sz) { - for (; lhs_it != lhs_it_e; ++lhs_it, ++rhs_it, ++it) { - carry = _addcarry(*lhs_it, *rhs_it, carry, &*it); - } - for (; carry && rhs_it != rhs_it_e; ++rhs_it, ++it) { - carry = _addcarry(0, *rhs_it, carry, &*it); - } - for (; rhs_it != rhs_it_e; ++rhs_it, ++it) { - *it = *rhs_it; - } - } else { - for (; rhs_it != rhs_it_e; ++lhs_it, ++rhs_it, ++it) { - carry = _addcarry(*lhs_it, *rhs_it, carry, &*it); - } - for (; carry && lhs_it != lhs_it_e; ++lhs_it, ++it) { - carry = _addcarry(*lhs_it, 0, carry, &*it); - } - for (; lhs_it != lhs_it_e; ++lhs_it, ++it) { - *it = *lhs_it; - } - } - - if (carry) { - result.append(1); - } - result._carry = false; - - // Finish up - result.trim(); - return result; - } - - static uinteger_t& add(uinteger_t& lhs, const uinteger_t& rhs) { - // First try saving some calculations: - if (!rhs) { - return lhs; - } - if (!lhs) { - lhs = rhs; - return lhs; - } - - return long_add(lhs, rhs); - } - - static uinteger_t& add(uinteger_t& result, const uinteger_t& lhs, const uinteger_t& rhs) { - // First try saving some calculations: - if (!rhs) { - result = lhs; - return result; - } - if (!lhs) { - result = rhs; - return result; - } - - return long_add(result, lhs, rhs); - } - - static uinteger_t add(const uinteger_t& lhs, const uinteger_t& rhs) { - uinteger_t result; - add(result, lhs, rhs); - return result; - } - - static uinteger_t& long_sub(uinteger_t& lhs, const uinteger_t& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - - if (lhs_sz < rhs_sz) { - lhs.resize(rhs_sz, 0); // grow - } - - // not using `end()` because resize of `lhs.resize()` could have - // resized `lhs`. - auto lhs_it = lhs.begin(); - auto lhs_it_e = lhs_it + lhs_sz; - - auto rhs_it = rhs.begin(); - auto rhs_it_e = rhs_it + rhs_sz; - - digit borrow = 0; - if (lhs_sz < rhs_sz) { - for (; lhs_it != lhs_it_e; ++lhs_it, ++rhs_it) { - borrow = _subborrow(*lhs_it, *rhs_it, borrow, &*lhs_it); - } - for (; rhs_it != rhs_it_e; ++lhs_it, ++rhs_it) { - borrow = _subborrow(0, *rhs_it, borrow, &*lhs_it); - } - } else { - for (; rhs_it != rhs_it_e; ++lhs_it, ++rhs_it) { - borrow = _subborrow(*lhs_it, *rhs_it, borrow, &*lhs_it); - } - for (; borrow && lhs_it != lhs_it_e; ++lhs_it) { - borrow = _subborrow(*lhs_it, 0, borrow, &*lhs_it); - } - } - - lhs._carry = borrow; - - // Finish up - lhs.trim(); - return lhs; - } - - static uinteger_t& long_sub(uinteger_t& result, const uinteger_t& lhs, const uinteger_t& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - - auto result_sz = std::max(lhs_sz, rhs_sz); - result.resize(result_sz, 0); - - // not using `end()` because resize of `result.resize()` could have - // resized `lhs` or `rhs` if `result` is also either `rhs` or `lhs`. - auto lhs_it = lhs.begin(); - auto lhs_it_e = lhs_it + lhs_sz; - - auto rhs_it = rhs.begin(); - auto rhs_it_e = rhs_it + rhs_sz; - - auto it = result.begin(); - - digit borrow = 0; - if (lhs_sz < rhs_sz) { - for (; lhs_it != lhs_it_e; ++lhs_it, ++rhs_it, ++it) { - borrow = _subborrow(*lhs_it, *rhs_it, borrow, &*it); - } - for (; rhs_it != rhs_it_e; ++rhs_it, ++it) { - borrow = _subborrow(0, *rhs_it, borrow, &*it); - } - } else { - for (; rhs_it != rhs_it_e; ++lhs_it, ++rhs_it, ++it) { - borrow = _subborrow(*lhs_it, *rhs_it, borrow, &*it); - } - for (; borrow && lhs_it != lhs_it_e; ++lhs_it, ++it) { - borrow = _subborrow(*lhs_it, 0, borrow, &*it); - } - for (; lhs_it != lhs_it_e; ++lhs_it, ++it) { - *it = *lhs_it; - } - } - - result._carry = borrow; - - // Finish up - result.trim(); - return result; - } - - static uinteger_t& sub(uinteger_t& lhs, const uinteger_t& rhs) { - // First try saving some calculations: - if (!rhs) { - return lhs; - } - - return long_sub(lhs, rhs); - } - - static uinteger_t& sub(uinteger_t& result, const uinteger_t& lhs, const uinteger_t& rhs) { - // First try saving some calculations: - if (!rhs) { - result = lhs; - return result; - } - - return long_sub(result, lhs, rhs); - } - - static uinteger_t sub(const uinteger_t& lhs, const uinteger_t& rhs) { - uinteger_t result; - sub(result, lhs, rhs); - return result; - } - - // Single word long multiplication - // Fastests, but ONLY for single sized rhs - static uinteger_t& single_mult(uinteger_t& result, const uinteger_t& lhs, const uinteger_t& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - - ASSERT(rhs_sz == 1); (void)(rhs_sz); - auto n = rhs.front(); - - uinteger_t tmp; - tmp.resize(lhs_sz + 1, 0); - - auto it_lhs = lhs.begin(); - auto it_lhs_e = lhs.end(); - - auto it_result = tmp.begin(); - - digit carry = 0; - for (; it_lhs != it_lhs_e; ++it_lhs, ++it_result) { - carry = _multadd(*it_lhs, n, 0, carry, &*it_result); - } - if (carry) { - *it_result = carry; - } - - result = std::move(tmp); - - // Finish up - result.trim(); - return result; - } - - static uinteger_t& long_mult(uinteger_t& result, const uinteger_t& lhs, const uinteger_t& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - - if (lhs_sz > rhs_sz) { - // rhs should be the largest: - return long_mult(result, rhs, lhs); - } - - if (lhs_sz == 1) { - return single_mult(result, rhs, lhs); - } - - uinteger_t tmp; - tmp.resize(lhs_sz + rhs_sz, 0); - - auto it_lhs = lhs.begin(); - auto it_lhs_e = lhs.end(); - - auto it_rhs = rhs.begin(); - auto it_rhs_e = rhs.end(); - - auto it_result = tmp.begin(); - auto it_result_s = it_result; - auto it_result_l = it_result; - - for (; it_lhs != it_lhs_e; ++it_lhs, ++it_result) { - if (auto lhs_it_val = *it_lhs) { - auto _it_rhs = it_rhs; - auto _it_result = it_result; - digit carry = 0; - for (; _it_rhs != it_rhs_e; ++_it_rhs, ++_it_result) { - carry = _multadd(*_it_rhs, lhs_it_val, *_it_result, carry, &*_it_result); - } - if (carry) { - *_it_result++ = carry; - } - if (it_result_l < _it_result) { - it_result_l = _it_result; - } - } - } - - tmp.resize(it_result_l - it_result_s); // shrink - - result = std::move(tmp); - - // Finish up - result.trim(); - return result; - } - - // A helper for Karatsuba multiplication to split a number in two, at n. - static std::pair karatsuba_mult_split(const uinteger_t& num, std::size_t n) { - const uinteger_t a(num, num._begin, num._begin + n); - const uinteger_t b(num, num._begin + n, num._end); - return std::make_pair(std::move(a), std::move(b)); - } - - // If rhs has at least twice the digits of lhs, and lhs is big enough that - // Karatsuba would pay off *if* the inputs had balanced sizes. - // View rhs as a sequence of slices, each with lhs.size() digits, - // and multiply the slices by lhs, one at a time. - static uinteger_t& karatsuba_lopsided_mult(uinteger_t& result, const uinteger_t& lhs, const uinteger_t& rhs, std::size_t cutoff) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - - ASSERT(lhs_sz > cutoff); - ASSERT(2 * lhs_sz <= rhs_sz); - - auto rhs_begin = rhs._begin; - std::size_t shift = 0; - - uinteger_t r; - while (rhs_sz > 0) { - // Multiply the next slice of rhs by lhs and add into result: - auto slice_size = std::min(lhs_sz, rhs_sz); - const uinteger_t rhs_slice(rhs, rhs_begin, rhs_begin + slice_size); - uinteger_t p; - karatsuba_mult(p, lhs, rhs_slice, cutoff); - uinteger_t rs(r, shift, 0); - add(rs, rs, p); - shift += slice_size; - rhs_sz -= slice_size; - rhs_begin += slice_size; - } - - result = std::move(r); - return result; - } - - // Karatsuba multiplication - static uinteger_t& karatsuba_mult(uinteger_t& result, const uinteger_t& lhs, const uinteger_t& rhs, std::size_t cutoff = 1) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - - if (lhs_sz > rhs_sz) { - // rhs should be the largest: - return karatsuba_mult(result, rhs, lhs, cutoff); - } - - if (lhs_sz <= cutoff) { - return long_mult(result, lhs, rhs); - } - - // If a is too small compared to b, splitting on b gives a degenerate case - // in which Karatsuba may be (even much) less efficient than long multiplication. - if (2 * lhs_sz <= rhs_sz) { - return karatsuba_lopsided_mult(result, lhs, rhs, cutoff); - } - - // Karatsuba: - // - // A B - // x C D - // --------------------- - // AD BD - // AC BC - // --------------------- - // AC AD + BC BD - // - // AD + BC = - // AC + AD + BC + BD - AC - BD - // (A + B) (C + D) - AC - BD - - // Calculate the split point near the middle of the largest (rhs). - auto shift = rhs_sz >> 1; - - // Split to get A and B: - const auto lhs_pair = karatsuba_mult_split(lhs, shift); - const auto& A = lhs_pair.second; // hi - const auto& B = lhs_pair.first; // lo - - // Split to get C and D: - const auto rhs_pair = karatsuba_mult_split(rhs, shift); - const auto& C = rhs_pair.second; // hi - const auto& D = rhs_pair.first; // lo - - // Get the pieces: - uinteger_t AC; - karatsuba_mult(AC, A, C, cutoff); - - uinteger_t BD; - karatsuba_mult(BD, B, D, cutoff); - uinteger_t AD_BC, AB, CD; - karatsuba_mult(AD_BC, A + B, C + D, cutoff); - AD_BC -= AC; - AD_BC -= BD; - - // Join the pieces, AC and BD (can't overlap) into BD: - BD.reserve(shift * 2 + AC.size()); - BD.resize(shift * 2, 0); - BD.append(AC); - - // And add AD_BC to the middle: (AC BD) + ( AD + BC ): - uinteger_t BDs(BD, shift, 0); - add(BDs, BDs, AD_BC); - - result = std::move(BD); - - // Finish up - result.trim(); - return result; - } - - static uinteger_t& mult(uinteger_t& lhs, const uinteger_t& rhs) { - // Hard to see how this could have a further optimized implementation. - return mult(lhs, lhs, rhs); - } - - static uinteger_t& mult(uinteger_t& result, const uinteger_t& lhs, const uinteger_t& rhs) { - // First try saving some calculations: - if (!lhs || !rhs) { - result = uint_0(); - return result; - } - if (compare(lhs, uint_1()) == 0) { - result = rhs; - return result; - } - if (compare(rhs, uint_1()) == 0) { - result = lhs; - return result; - } - - return karatsuba_mult(result, lhs, rhs, karatsuba_cutoff); - } - - static uinteger_t mult(const uinteger_t& lhs, const uinteger_t& rhs) { - uinteger_t result; - mult(result, lhs, rhs); - return result; - } - - // Single word long division - // Fastests, but ONLY for single sized rhs - static std::pair, std::reference_wrapper> single_divmod(uinteger_t& quotient, uinteger_t& remainder, const uinteger_t& lhs, const uinteger_t& rhs) { - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - - ASSERT(rhs_sz == 1); (void)(rhs_sz); - auto n = rhs.front(); - - auto rit_lhs = lhs.rbegin(); - auto rit_lhs_e = lhs.rend(); - - auto q = uint_0(); - q.resize(lhs_sz, 0); - auto rit_q = q.rbegin(); - - digit r = 0; - for (; rit_lhs != rit_lhs_e; ++rit_lhs, ++rit_q) { - r = _divmod(r, *rit_lhs, n, &*rit_q); - } - - q.trim(); - - quotient = std::move(q); - remainder = r; - return std::make_pair(std::ref(quotient), std::ref(remainder)); - } - - // Implementation of Knuth's Algorithm D - static std::pair, std::reference_wrapper> knuth_divmod(uinteger_t& quotient, uinteger_t& remainder, const uinteger_t& lhs, const uinteger_t& rhs) { - uinteger_t v(lhs); - uinteger_t w(rhs); - - auto v_size = v.size(); - auto w_size = w.size(); - ASSERT(v_size >= w_size && w_size >= 2); - - // D1. normalize: shift rhs left so that its top digit is >= 63 bits. - // shift lhs left by the same amount. Results go into w and v. - auto d = uinteger_t(digit_bits - _bits(w.back())); - v <<= d; - w <<= d; - - if (*v.rbegin() >= *w.rbegin()) { - v.append(0); - } - v_size = v.size(); - v.append(0); - - // Now *v.rbegin() < *w.rbegin() so quotient has at most - // (and usually exactly) k = v.size() - w.size() digits. - auto k = v_size - w_size; - auto q = uint_0(); - q.resize(k + 1, 0); - - auto rit_q = q.rend() - (k + 1); - - auto it_v_b = v.begin(); - auto it_v_k = it_v_b + k; - - auto it_w = w.begin(); - auto it_w_e = w.end(); - - auto rit_w = w.rbegin(); - auto wm1 = *rit_w++; - auto wm2 = *rit_w; - - // D2. inner loop: divide v[k+0..k+n] by w[0..n] - for (; it_v_k >= it_v_b; --it_v_k, ++rit_q) { - // D3. Compute estimate quotient digit q; may overestimate by 1 (rare) - digit _q; - auto _r = _divmod(*(it_v_k + w_size), *(it_v_k + w_size - 1), wm1, &_q); - digit mullo = 0; - auto mulhi = _mult(_q, wm2, &mullo); - auto rlo = *(it_v_k + w_size - 2); - while (mulhi > _r || (mulhi == _r && mullo > rlo)) { - --_q; - if (_addcarry(_r, wm1, 0, &_r)) { - break; - } - mulhi = _mult(_q, wm2, &mullo); - } - - // D4. Multiply and subtract _q * w0[0:size_w] from vk[0:size_w+1] - auto _it_v = it_v_k; - auto _it_w = it_w; - mulhi = 0; - digit carry = 0; - for (; _it_w != it_w_e; ++_it_v, ++_it_w) { - mullo = 0; - mulhi = _multadd(*_it_w, _q, 0, mulhi, &mullo); - carry = _subborrow(*_it_v, mullo, carry, &*_it_v); - } - carry = _subborrow(*_it_v, 0, carry, &*_it_v); - - if (carry) { - // D6. Add w back if q was too large (this branch taken rarely) - --_q; - - _it_v = it_v_k; - _it_w = it_w; - carry = 0; - for (; _it_w != it_w_e; ++_it_v, ++_it_w) { - carry = _addcarry(*_it_v, *_it_w, carry, &*_it_v); - } - carry = _addcarry(*_it_v, 0, carry, &*_it_v); - } - - /* store quotient digit */ - *rit_q = _q; - } - - // D8. unnormalize: unshift remainder. - v.resize(w_size); - v >>= d; - - q.trim(); - v.trim(); - - quotient = std::move(q); - remainder = std::move(v); - return std::make_pair(std::ref(quotient), std::ref(remainder)); - } - - static std::pair, std::reference_wrapper> divmod(uinteger_t& quotient, uinteger_t& remainder, const uinteger_t& lhs, const uinteger_t& rhs) { - // First try saving some calculations: - if (!rhs) { - throw std::domain_error("Error: division or modulus by 0"); - } - auto lhs_sz = lhs.size(); - auto rhs_sz = rhs.size(); - if (lhs_sz == 1 && rhs_sz == 1) { - // Fast division and modulo for single value - auto a = *lhs.begin(); - auto b = *rhs.begin(); - quotient = a / b; - remainder = a % b; - return std::make_pair(std::ref(quotient), std::ref(remainder)); - } - if (compare(rhs, uint_1()) == 0) { - quotient = lhs; - remainder = uint_0(); - return std::make_pair(std::ref(quotient), std::ref(remainder)); - } - auto compared = compare(lhs, rhs); - if (compared == 0) { - quotient = uint_1(); - remainder = uint_0(); - return std::make_pair(std::ref(quotient), std::ref(remainder)); - } - if (!lhs || compared < 0) { - quotient = uint_0(); - remainder = lhs; - return std::make_pair(std::ref(quotient), std::ref(remainder)); - } - if (rhs_sz == 1) { - return single_divmod(quotient, remainder, lhs, rhs); - } - - return knuth_divmod(quotient, remainder, lhs, rhs); - } - - static std::pair divmod(const uinteger_t& lhs, const uinteger_t& rhs) { - uinteger_t quotient; - uinteger_t remainder; - divmod(quotient, remainder, lhs, rhs); - return std::make_pair(std::move(quotient), std::move(remainder)); - } - -private: - // Constructors - - template ::value and not std::is_same>::value>> - void _uint_t(const T& value) { - append(static_cast(value)); - } - - template ::value and not std::is_same>::value>> - void _uint_t(const T& value, Args... args) { - _uint_t(args...); - append(static_cast(value)); - } - - // This constructor creates a window view of the _value - uinteger_t(const uinteger_t& o, std::size_t begin, std::size_t end) : - _begin(begin), - _end(end), - _value(o._value), - _carry(o._carry) { } - -public: - uinteger_t() : - _begin(0), - _end(0), - _value(_value_instance), - _carry(false) { } - - uinteger_t(const uinteger_t& o) : - _begin(0), - _end(0), - _value_instance(o.begin(), o.end()), - _value(_value_instance), - _carry(o._carry) { } - - uinteger_t(uinteger_t&& o) : - _begin(std::move(o._begin)), - _end(std::move(o._end)), - _value_instance(std::move(o._value_instance)), - _value(_value_instance), - _carry(std::move(o._carry)) { } - - template ::value and not std::is_same>::value>> - uinteger_t(const T& value) : - _begin(0), - _end(0), - _value(_value_instance), - _carry(false) { - if (value) { - append(static_cast(value)); - } - } - - template ::value and not std::is_same>::value>> - uinteger_t(const T& value, Args... args) : - _begin(0), - _end(0), - _value(_value_instance), - _carry(false) { - _uint_t(args...); - append(static_cast(value)); - trim(); - } - - template ::value and not std::is_same>::value>> - uinteger_t(std::initializer_list list) : - _begin(0), - _end(0), - _value(_value_instance), - _carry(false) { - reserve(list.size()); - for (const auto& value : list) { - append(static_cast(value)); - } - trim(); - } - - template - explicit uinteger_t(T (&s)[N], int base=10) : - uinteger_t(s, N - 1, base) { } - - explicit uinteger_t(const unsigned char* bytes, std::size_t sz, int base) : - uinteger_t(strtouint(bytes, sz, base)) { } - - explicit uinteger_t(const char* bytes, std::size_t sz, int base) : - uinteger_t(strtouint(bytes, sz, base)) { } - - template - explicit uinteger_t(const std::vector& bytes, int base=10) : - uinteger_t(bytes.data(), bytes.size(), base) { } - - explicit uinteger_t(const std::string& bytes, int base=10) : - uinteger_t(bytes.data(), bytes.size(), base) { } - - // Assignment Operator - uinteger_t& operator=(const uinteger_t& o) { - _begin = 0; - _end = 0; - _value = container(o.begin(), o.end()); - _carry = o._carry; - return *this; - } - uinteger_t& operator=(uinteger_t&& o) { - _begin = std::move(o._begin); - _end = std::move(o._end); - _value_instance = std::move(o._value_instance); - _carry = std::move(o._carry); - return *this; - } - - // Typecast Operators - explicit operator bool() const { - return static_cast(size()); - } - explicit operator unsigned char() const { - return static_cast(size() ? front() : 0); - } - explicit operator unsigned short() const { - return static_cast(size() ? front() : 0); - } - explicit operator unsigned int() const { - return static_cast(size() ? front() : 0); - } - explicit operator unsigned long() const { - return static_cast(size() ? front() : 0); - } - explicit operator unsigned long long() const { - return static_cast(size() ? front() : 0); - } - explicit operator char() const { - return static_cast(size() ? front() : 0); - } - explicit operator short() const { - return static_cast(size() ? front() : 0); - } - explicit operator int() const { - return static_cast(size() ? front() : 0); - } - explicit operator long() const { - return static_cast(size() ? front() : 0); - } - explicit operator long long() const { - return static_cast(size() ? front() : 0); - } - - // Bitwise Operators - uinteger_t operator&(const uinteger_t& rhs) const { - return bitwise_and(*this, rhs); - } - - uinteger_t& operator&=(const uinteger_t& rhs) { - return bitwise_and(*this, rhs); - } - - uinteger_t operator|(const uinteger_t& rhs) const { - return bitwise_or(*this, rhs); - } - - uinteger_t& operator|=(const uinteger_t& rhs) { - return bitwise_or(*this, rhs); - } - - uinteger_t operator^(const uinteger_t& rhs) const { - return bitwise_xor(*this, rhs); - } - - uinteger_t& operator^=(const uinteger_t& rhs) { - return bitwise_xor(*this, rhs); - } - - uinteger_t operator~() const { - return bitwise_inv(*this); - } - - uinteger_t inv() { - return bitwise_inv(*this); - } - - // Bit Shift Operators - uinteger_t operator<<(const uinteger_t& rhs) const { - return bitwise_lshift(*this, rhs); - } - - uinteger_t& operator<<=(const uinteger_t& rhs) { - return bitwise_lshift(*this, rhs); - } - - uinteger_t operator>>(const uinteger_t& rhs) const { - return bitwise_rshift(*this, rhs); - } - - uinteger_t& operator>>=(const uinteger_t& rhs) { - return bitwise_rshift(*this, rhs); - } - - // Logical Operators - bool operator!() const { - return !static_cast(*this); - } - - bool operator&&(const uinteger_t& rhs) const { - return static_cast(*this) && rhs; - } - - bool operator||(const uinteger_t& rhs) const { - return static_cast(*this) || rhs; - } - - // Comparison Operators - bool operator==(const uinteger_t& rhs) const { - return compare(*this, rhs) == 0; - } - - bool operator!=(const uinteger_t& rhs) const { - return compare(*this, rhs) != 0; - } - - bool operator>(const uinteger_t& rhs) const { - return compare(*this, rhs) > 0; - } - - bool operator<(const uinteger_t& rhs) const { - return compare(*this, rhs) < 0; - } - - bool operator>=(const uinteger_t& rhs) const { - return compare(*this, rhs) >= 0; - } - - bool operator<=(const uinteger_t& rhs) const { - return compare(*this, rhs) <= 0; - } - - // Arithmetic Operators - uinteger_t operator+(const uinteger_t& rhs) const { - return add(*this, rhs); - } - - uinteger_t& operator+=(const uinteger_t& rhs) { - return add(*this, rhs); - } - - uinteger_t operator-(const uinteger_t& rhs) const { - return sub(*this, rhs); - } - - uinteger_t& operator-=(const uinteger_t& rhs) { - return sub(*this, rhs); - } - - uinteger_t operator*(const uinteger_t& rhs) const { - return mult(*this, rhs); - } - - uinteger_t& operator*=(const uinteger_t& rhs) { - return mult(*this, rhs); - } - - std::pair divmod(const uinteger_t& rhs) const { - return divmod(*this, rhs); - } - - uinteger_t operator/(const uinteger_t& rhs) const { - return divmod(*this, rhs).first; - } - - uinteger_t& operator/=(const uinteger_t& rhs) { - uinteger_t quotient; - uinteger_t remainder; - divmod(quotient, remainder, *this, rhs); - *this = std::move(quotient); - return *this; - } - - uinteger_t operator%(const uinteger_t& rhs) const { - return divmod(*this, rhs).second; - } - - uinteger_t& operator%=(const uinteger_t& rhs) { - uinteger_t quotient; - uinteger_t remainder; - divmod(quotient, remainder, *this, rhs); - *this = std::move(remainder); - return *this; - } - - // Increment Operator - uinteger_t& operator++() { - return *this += uint_1(); - } - uinteger_t operator++(int) { - uinteger_t temp(*this); - ++*this; - return temp; - } - - // Decrement Operator - uinteger_t& operator--() { - return *this -= uint_1(); - } - uinteger_t operator--(int) { - uinteger_t temp(*this); - --*this; - return temp; - } - - // Nothing done since promotion doesn't work here - uinteger_t operator+() const { - return *this; - } - - // two's complement - uinteger_t operator-() const { - return uint_0() - *this; - } - - // Get private value at index - const digit& value(std::size_t idx) const { - static const digit zero = 0; - return idx < size() ? *(begin() + idx) : zero; - } - - // Get value of bit N - bool operator[](std::size_t n) const { - auto nd = n / digit_bits; - auto nm = n % digit_bits; - return nd < size() ? (*(begin() + nd) >> nm) & 1 : 0; - } - - // Get bitsize of value - std::size_t bits() const { - auto sz = size(); - if (sz) { - return _bits(back()) + (sz - 1) * digit_bits; - } - return 0; - } - - // Get string representation of value - template ::value>> - Result str(int alphabet_base = 10) const { - auto num_sz = size(); - if (alphabet_base >= 2 && alphabet_base <= 36) { - Result result; - if (num_sz) { - auto alphabet_base_bits = base_bits(alphabet_base); - result.reserve(num_sz * base_size(alphabet_base)); - if (alphabet_base_bits) { - digit alphabet_base_mask = alphabet_base - 1; - std::size_t shift = 0; - auto ptr = reinterpret_cast(data()); - digit v = *ptr++; - v <<= half_digit_bits; - for (auto i = num_sz * 2 - 1; i; --i) { - v >>= half_digit_bits; - v |= (static_cast(*ptr++) << half_digit_bits); - do { - auto d = static_cast((v >> shift) & alphabet_base_mask); - result.push_back(chr(d)); - shift += alphabet_base_bits; - } while (shift <= half_digit_bits); - shift -= half_digit_bits; - } - v >>= (shift + half_digit_bits); - while (v) { - auto d = static_cast(v & alphabet_base_mask); - result.push_back(chr(d)); - v >>= alphabet_base_bits; - } - auto s = chr(0); - auto rit_f = std::find_if(result.rbegin(), result.rend(), [s](const char& c) { return c != s; }); - result.resize(result.rend() - rit_f); // shrink - } else { - uinteger_t uint_base = alphabet_base; - uinteger_t quotient = *this; - do { - auto r = quotient.divmod(uint_base); - auto d = static_cast(r.second); - result.push_back(chr(d)); - quotient = std::move(r.first); - } while (quotient); - } - std::reverse(result.begin(), result.end()); - } else { - result.push_back(chr(0)); - } - return result; - } else if (alphabet_base == 256) { - if (num_sz) { - auto ptr = reinterpret_cast(data()); - Result result(ptr, ptr + num_sz * digit_octets); - auto rit_f = std::find_if(result.rbegin(), result.rend(), [](const char& c) { return c; }); - result.resize(result.rend() - rit_f); // shrink - std::reverse(result.begin(), result.end()); - return result; - } else { - Result result; - result.push_back('\x00'); - return result; - } - } else { - throw std::invalid_argument("Base must be in the range [2, 36]"); - } - } - - static uinteger_t strtouint(const void* encoded, std::size_t encoded_size, int alphabet_base) { - const char* data = (const char *)encoded; - uinteger_t result; - - if (alphabet_base >= 2 && alphabet_base <= 36) { - uinteger_t alphabet_base_bits = base_bits(alphabet_base); - uinteger_t uint_base = alphabet_base; - if (alphabet_base_bits) { - for (; encoded_size; --encoded_size, ++data) { - auto d = ord(static_cast(*data)); - if (d < 0) { - throw std::invalid_argument("Error: Not a digit in base " + std::to_string(alphabet_base) + ": '" + std::string(1, *data) + "' at " + std::to_string(encoded_size)); - } - result = (result << alphabet_base_bits) | d; - } - } else { - for (; encoded_size; --encoded_size, ++data) { - auto d = ord(static_cast(*data)); - if (d < 0) { - throw std::invalid_argument("Error: Not a digit in base " + std::to_string(alphabet_base) + ": '" + std::string(1, *data) + "' at " + std::to_string(encoded_size)); - } - result = (result * uint_base) + d; - } - } - } else if (encoded_size && alphabet_base == 256) { - auto value_size = encoded_size / digit_octets; - auto value_padding = encoded_size % digit_octets; - if (value_padding) { - value_padding = digit_octets - value_padding; - ++value_size; - } - result.resize(value_size); // grow (no initialization) - *result.begin() = 0; // initialize value - auto ptr = reinterpret_cast(result.data()); - std::copy(data, data + encoded_size, ptr + value_padding); - std::reverse(ptr, ptr + value_size * digit_octets); - } else { - throw std::invalid_argument("Error: Cannot convert from base " + std::to_string(alphabet_base)); - } - - return result; - } - - template ::value>> - Result bin() const { - return str(2); - } - - template ::value>> - Result oct() const { - return str(8); - } - - template ::value>> - Result hex() const { - return str(16); - } - - template ::value>> - Result raw() const { - return str(256); - } -}; - -namespace std { // This is probably not a good idea - // Make it work with std::string() - inline std::string to_string(uinteger_t& num) { - return num.str(); - } - inline const std::string to_string(const uinteger_t& num) { - return num.str(); - } -} - -// lhs type T as first arguemnt -// If the output is not a bool, casts to type T - -// Bitwise Operators -template ::value and not std::is_same>::value>> -uinteger_t operator&(const T& lhs, const uinteger_t& rhs) { - return uinteger_t(lhs) & rhs; -} - -template ::value and not std::is_same>::value>> -T& operator&=(T& lhs, const uinteger_t& rhs) { - return lhs = static_cast(rhs & lhs); -} - -template ::value and not std::is_same>::value>> -uinteger_t operator|(const T& lhs, const uinteger_t& rhs) { - return uinteger_t(lhs) | rhs; -} - -template ::value and not std::is_same>::value>> -T& operator|=(T& lhs, const uinteger_t& rhs) { - return lhs = static_cast(rhs | lhs); -} - -template ::value and not std::is_same>::value>> -uinteger_t operator^(const T& lhs, const uinteger_t& rhs) { - return uinteger_t(lhs) ^ rhs; -} - -template ::value and not std::is_same>::value>> -T& operator^=(T& lhs, const uinteger_t& rhs) { - return lhs = static_cast(rhs ^ lhs); -} - -// Bitshift operators -template ::value and not std::is_same>::value>> -inline uinteger_t operator<<(T& lhs, const uinteger_t& rhs) { - return uinteger_t(lhs) << rhs; -} - -template ::value and not std::is_same>::value>> -T& operator<<=(T& lhs, const uinteger_t& rhs) { - return lhs = static_cast(lhs << rhs); -} - -template ::value and not std::is_same>::value>> -inline uinteger_t operator>>(T& lhs, const uinteger_t& rhs) { - return uinteger_t(lhs) >> rhs; -} - -template ::value and not std::is_same>::value>> -T& operator>>=(T& lhs, const uinteger_t& rhs) { - return lhs = static_cast(lhs >> rhs); -} - -// Comparison Operators -template ::value and not std::is_same>::value>> -bool operator==(const T& lhs, const uinteger_t& rhs) { - return uinteger_t(lhs) == rhs; -} - -template ::value and not std::is_same>::value>> -bool operator!=(const T& lhs, const uinteger_t& rhs) { - return uinteger_t(lhs) != rhs; -} - -template ::value and not std::is_same>::value>> -bool operator>(const T& lhs, const uinteger_t& rhs) { - return uinteger_t(lhs) > rhs; -} - -template ::value and not std::is_same>::value>> -bool operator<(const T& lhs, const uinteger_t& rhs) { - return uinteger_t(lhs) < rhs; -} - -template ::value and not std::is_same>::value>> -bool operator>=(const T& lhs, const uinteger_t& rhs) { - return uinteger_t(lhs) >= rhs; -} - -template ::value and not std::is_same>::value>> -bool operator<=(const T& lhs, const uinteger_t& rhs) { - return uinteger_t(lhs) <= rhs; -} - -// Arithmetic Operators -template ::value and not std::is_same>::value>> -uinteger_t operator+(const T& lhs, const uinteger_t& rhs) { - return uinteger_t(lhs) + rhs; -} - -template ::value and not std::is_same>::value>> -T& operator+=(T& lhs, const uinteger_t& rhs) { - return lhs = static_cast(rhs + lhs); -} - -template ::value and not std::is_same>::value>> -uinteger_t operator-(const T& lhs, const uinteger_t& rhs) { - return uinteger_t(lhs) - rhs; -} - -template ::value and not std::is_same>::value>> -T& operator-=(T& lhs, const uinteger_t& rhs) { - return lhs = static_cast(lhs - rhs); -} - -template ::value and not std::is_same>::value>> -uinteger_t operator*(const T& lhs, const uinteger_t& rhs) { - return uinteger_t(lhs) * rhs; -} - -template ::value and not std::is_same>::value>> -T& operator*=(T& lhs, const uinteger_t& rhs) { - return lhs = static_cast(rhs * lhs); -} - -template ::value and not std::is_same>::value>> -uinteger_t operator/(const T& lhs, const uinteger_t& rhs) { - return uinteger_t(lhs) / rhs; -} - -template ::value and not std::is_same>::value>> -T& operator/=(T& lhs, const uinteger_t& rhs) { - return lhs = static_cast(lhs / rhs); -} - -template ::value and not std::is_same>::value>> -uinteger_t operator%(const T& lhs, const uinteger_t& rhs) { - return uinteger_t(lhs) % rhs; -} - -template ::value and not std::is_same>::value>> -T& operator%=(T& lhs, const uinteger_t& rhs) { - return lhs = static_cast(lhs % rhs); -} - -// IO Operator -inline std::ostream& operator<<(std::ostream& stream, const uinteger_t& rhs) { - if (stream.flags() & stream.oct) { - stream << rhs.str(8); - } else if (stream.flags() & stream.dec) { - stream << rhs.str(10); - } else if (stream.flags() & stream.hex) { - stream << rhs.str(16); - } - return stream; -} - -#endif