From e54726df8e751302fe921c6df2af6d8e6f4d83be Mon Sep 17 00:00:00 2001 From: Stephane Janel Date: Tue, 7 May 2024 00:25:45 +0200 Subject: [PATCH] Split mathhelpers.hpp into dedicated include files for each functionality --- src/api/exchanges/src/bithumbprivateapi.cpp | 3 +- src/http-request/src/besturlpicker.cpp | 2 +- src/objects/include/monetaryamount.hpp | 3 +- src/objects/src/monetaryamount.cpp | 3 +- src/objects/test/monetaryamount_test.cpp | 2 +- src/tech/CMakeLists.txt | 9 +- src/tech/include/ipow.hpp | 104 +++++++++++ .../include/levenshteindistancecalculator.hpp | 4 +- src/tech/include/mathhelpers.hpp | 175 ------------------ src/tech/include/nchars.hpp | 15 ++ src/tech/include/ndigits.hpp | 99 ++++++++++ src/tech/include/overflow-check.hpp | 1 - .../include/static_string_view_helpers.hpp | 2 +- src/tech/include/stringhelpers.hpp | 3 +- src/tech/include/timedef.hpp | 1 + src/tech/include/timestring.hpp | 1 + src/tech/include/toupperlower.hpp | 1 + src/tech/include/url-encode.hpp | 1 - src/tech/src/simpletable.cpp | 3 +- src/tech/test/ipow_test.cpp | 28 +++ ...{mathhelpers_test.cpp => ndigits_test.cpp} | 31 ++-- 21 files changed, 281 insertions(+), 210 deletions(-) create mode 100644 src/tech/include/ipow.hpp delete mode 100644 src/tech/include/mathhelpers.hpp create mode 100644 src/tech/include/nchars.hpp create mode 100644 src/tech/include/ndigits.hpp create mode 100644 src/tech/test/ipow_test.cpp rename src/tech/test/{mathhelpers_test.cpp => ndigits_test.cpp} (92%) diff --git a/src/api/exchanges/src/bithumbprivateapi.cpp b/src/api/exchanges/src/bithumbprivateapi.cpp index 356d5108..8446e0e4 100644 --- a/src/api/exchanges/src/bithumbprivateapi.cpp +++ b/src/api/exchanges/src/bithumbprivateapi.cpp @@ -42,9 +42,10 @@ #include "exchangepublicapitypes.hpp" #include "file.hpp" #include "httprequesttype.hpp" +#include "ipow.hpp" #include "market.hpp" -#include "mathhelpers.hpp" #include "monetaryamount.hpp" +#include "ndigits.hpp" #include "opened-order.hpp" #include "orderid.hpp" #include "ordersconstraints.hpp" diff --git a/src/http-request/src/besturlpicker.cpp b/src/http-request/src/besturlpicker.cpp index 79616efd..3891361d 100644 --- a/src/http-request/src/besturlpicker.cpp +++ b/src/http-request/src/besturlpicker.cpp @@ -9,7 +9,7 @@ #include #include "cct_log.hpp" -#include "mathhelpers.hpp" +#include "ipow.hpp" namespace cct { BestURLPicker::BestURLPicker(std::span baseUrls) diff --git a/src/objects/include/monetaryamount.hpp b/src/objects/include/monetaryamount.hpp index c1161dca..6df78f2a 100644 --- a/src/objects/include/monetaryamount.hpp +++ b/src/objects/include/monetaryamount.hpp @@ -15,7 +15,8 @@ #include "cct_log.hpp" #include "cct_string.hpp" #include "currencycode.hpp" -#include "mathhelpers.hpp" +#include "ipow.hpp" +#include "ndigits.hpp" namespace cct { diff --git a/src/objects/src/monetaryamount.cpp b/src/objects/src/monetaryamount.cpp index 75de8a25..43bff178 100644 --- a/src/objects/src/monetaryamount.cpp +++ b/src/objects/src/monetaryamount.cpp @@ -23,7 +23,8 @@ #include "cct_exception.hpp" #include "cct_invalid_argument_exception.hpp" #include "currencycode.hpp" -#include "mathhelpers.hpp" +#include "ipow.hpp" +#include "ndigits.hpp" #include "stringhelpers.hpp" namespace cct { diff --git a/src/objects/test/monetaryamount_test.cpp b/src/objects/test/monetaryamount_test.cpp index ec330c50..6a82fa0c 100644 --- a/src/objects/test/monetaryamount_test.cpp +++ b/src/objects/test/monetaryamount_test.cpp @@ -9,7 +9,7 @@ #include "cct_invalid_argument_exception.hpp" #include "cct_string.hpp" #include "currencycode.hpp" -#include "mathhelpers.hpp" +#include "ipow.hpp" namespace cct { diff --git a/src/tech/CMakeLists.txt b/src/tech/CMakeLists.txt index 6f53cb61..5f8240ae 100644 --- a/src/tech/CMakeLists.txt +++ b/src/tech/CMakeLists.txt @@ -91,8 +91,13 @@ else() endif() add_unit_test( - mathhelpers_test - test/mathhelpers_test.cpp + ndigits_test + test/ndigits_test.cpp +) + +add_unit_test( + ipow_test + test/ipow_test.cpp ) add_unit_test( diff --git a/src/tech/include/ipow.hpp b/src/tech/include/ipow.hpp new file mode 100644 index 00000000..ff016fa6 --- /dev/null +++ b/src/tech/include/ipow.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include +#include +#include + +namespace cct { +/// constexpr and integral version of math.power. +/// Taken from https://gist.github.com/orlp/3551590 +constexpr int64_t ipow(int64_t base, uint8_t exp) noexcept { + constexpr uint8_t highest_bit_set[] = {0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, + 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 255, // anything past 63 is a guaranteed overflow with base > 1 + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; + + int64_t result = 1; + + switch (highest_bit_set[exp]) { + case 255: // we use 255 as an overflow marker and return 0 on overflow/underflow + return base == 1 ? 1 : (base == -1 ? (1 - 2 * (exp & 1)) : 0); + case 6: + if ((exp & 1U) != 0) { + result *= base; + } + exp >>= 1; + base *= base; + [[fallthrough]]; + case 5: + if ((exp & 1U) != 0) { + result *= base; + } + exp >>= 1; + base *= base; + [[fallthrough]]; + case 4: + if ((exp & 1U) != 0) { + result *= base; + } + exp >>= 1; + base *= base; + [[fallthrough]]; + case 3: + if ((exp & 1U) != 0) { + result *= base; + } + exp >>= 1; + base *= base; + [[fallthrough]]; + case 2: + if ((exp & 1U) != 0) { + result *= base; + } + exp >>= 1; + base *= base; + [[fallthrough]]; + case 1: + if ((exp & 1U) != 0) { + result *= base; + } + [[fallthrough]]; + default: + return result; + } +} + +/// Optimization of ipow(10, uint8_t exp) +constexpr int64_t ipow10(uint8_t exp) noexcept { + constexpr const int64_t kPow10Table[] = {1LL, + 10LL, + 100LL, + 1000LL, + 10000LL, + 100000LL, + 1000000LL, + 10000000LL, + 100000000LL, + 1000000000LL, + 10000000000LL, + 100000000000LL, + 1000000000000LL, + 10000000000000LL, + 100000000000000LL, + 1000000000000000LL, + 10000000000000000LL, + 100000000000000000LL, + 1000000000000000000LL}; + return exp < sizeof(kPow10Table) / sizeof(kPow10Table[0]) ? kPow10Table[exp] : std::numeric_limits::max(); +} + +} // namespace cct \ No newline at end of file diff --git a/src/tech/include/levenshteindistancecalculator.hpp b/src/tech/include/levenshteindistancecalculator.hpp index 05844e3f..bbd3ca87 100644 --- a/src/tech/include/levenshteindistancecalculator.hpp +++ b/src/tech/include/levenshteindistancecalculator.hpp @@ -5,10 +5,9 @@ #include "cct_vector.hpp" namespace cct { + class LevenshteinDistanceCalculator { public: - LevenshteinDistanceCalculator() noexcept = default; - /// Computes the levenshtein distance between both input words. /// Complexity is in 'word1.length() * word2.length()' in time, /// min(word1.length(), word2.length()) in space. @@ -18,4 +17,5 @@ class LevenshteinDistanceCalculator { // This is only for caching purposes, so that repeated calls to distance calculation do not allocate memory each time vector _minDistance; }; + } // namespace cct \ No newline at end of file diff --git a/src/tech/include/mathhelpers.hpp b/src/tech/include/mathhelpers.hpp deleted file mode 100644 index ee934187..00000000 --- a/src/tech/include/mathhelpers.hpp +++ /dev/null @@ -1,175 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace cct { -/// constexpr and integral version of math.power. -/// Taken from https://gist.github.com/orlp/3551590 -constexpr int64_t ipow(int64_t base, uint8_t exp) noexcept { - constexpr uint8_t highest_bit_set[] = {0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, - 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 255, // anything past 63 is a guaranteed overflow with base > 1 - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; - - int64_t result = 1; - - switch (highest_bit_set[exp]) { - case 255: // we use 255 as an overflow marker and return 0 on overflow/underflow - return base == 1 ? 1 : (base == -1 ? (1 - 2 * (exp & 1)) : 0); - case 6: - if ((exp & 1U) != 0) { - result *= base; - } - exp >>= 1; - base *= base; - [[fallthrough]]; - case 5: - if ((exp & 1U) != 0) { - result *= base; - } - exp >>= 1; - base *= base; - [[fallthrough]]; - case 4: - if ((exp & 1U) != 0) { - result *= base; - } - exp >>= 1; - base *= base; - [[fallthrough]]; - case 3: - if ((exp & 1U) != 0) { - result *= base; - } - exp >>= 1; - base *= base; - [[fallthrough]]; - case 2: - if ((exp & 1U) != 0) { - result *= base; - } - exp >>= 1; - base *= base; - [[fallthrough]]; - case 1: - if ((exp & 1U) != 0) { - result *= base; - } - [[fallthrough]]; - default: - return result; - } -} - -/// Optimization of ipow(10, uint8_t exp) -constexpr int64_t ipow10(uint8_t exp) noexcept { - constexpr const int64_t kPow10Table[] = {1LL, - 10LL, - 100LL, - 1000LL, - 10000LL, - 100000LL, - 1000000LL, - 10000000LL, - 100000000LL, - 1000000000LL, - 10000000000LL, - 100000000000LL, - 1000000000000LL, - 10000000000000LL, - 100000000000000LL, - 1000000000000000LL, - 10000000000000000LL, - 100000000000000000LL, - 1000000000000000000LL}; - return exp < std::size(kPow10Table) ? kPow10Table[exp] : std::numeric_limits::max(); -} - -/// Return the number of digits of given integral. -/// The minus sign is not counted. -/// Uses dichotomy for highest performance as possible. -constexpr int ndigits(std::signed_integral auto n) noexcept { - using T = decltype(n); - if constexpr (std::is_same_v) { - return n < 0 ? (n > -100 ? (n > -10 ? 1 : 2) : 3) : (n < 100 ? (n < 10 ? 1 : 2) : 3); - } else if constexpr (std::is_same_v) { - return n < 0 ? (n > -1000 ? (n > -100 ? (n > -10 ? 1 : 2) : 3) : (n > -10000 ? 4 : 5)) - : (n < 1000 ? (n < 100 ? (n < 10 ? 1 : 2) : 3) : (n < 10000 ? 4 : 5)); - } else if constexpr (std::is_same_v) { - return n < 0 ? (n > -1000000 - ? (n > -1000 ? (n > -100 ? (n > -10 ? 1 : 2) : 3) : (n > -100000 ? (n > -10000 ? 4 : 5) : 6)) - : (n > -100000000 ? (n > -10000000 ? 7 : 8) : (n > -1000000000 ? 9 : 10))) - : (n < 1000000 ? (n < 1000 ? (n < 100 ? (n < 10 ? 1 : 2) : 3) : (n < 100000 ? (n < 10000 ? 4 : 5) : 6)) - : (n < 100000000 ? (n < 10000000 ? 7 : 8) : (n < 1000000000 ? 9 : 10))); - } else { - // int64_t - return n < 0 ? (n > -10000000000L - ? (n > -1000000L ? (n > -1000L ? (n > -100L ? (n > -10L ? 1 : 2) : 3) - : (n > -100000L ? (n > -10000L ? 4 : 5) : 6)) - : (n > -100000000L ? (n > -10000000L ? 7 : 8) : (n > -1000000000L ? 9 : 10))) - : (n > -10000000000000000L - ? (n > -10000000000000L - ? (n > -1000000000000L ? (n > -100000000000L ? 11 : 12) : 13) - : (n > -1000000000000000L ? (n > -100000000000000L ? 14 : 15) : 16)) - : (n > -1000000000000000000L ? (n > -100000000000000000L ? 17 : 18) : 19))) - : (n < 10000000000L - ? (n < 1000000L ? (n < 1000L ? (n < 100L ? (n < 10L ? 1 : 2) : 3) - : (n < 100000L ? (n < 10000L ? 4 : 5) : 6)) - : (n < 100000000L ? (n < 10000000L ? 7 : 8) : (n < 1000000000L ? 9 : 10))) - : (n < 10000000000000000L - ? (n < 10000000000000L ? (n < 1000000000000L ? (n < 100000000000L ? 11 : 12) : 13) - : (n < 1000000000000000L ? (n < 100000000000000L ? 14 : 15) : 16)) - : (n < 1000000000000000000L ? (n < 100000000000000000L ? 17 : 18) : 19))); - } -} - -/// Count the number of digits including the possible minus sign for negative integrals. -constexpr int nchars(std::signed_integral auto n) noexcept { return ndigits(n) + static_cast(n < 0); } - -/// Return the number of digits of given integral. -/// Uses dichotomy for highest performance as possible. -constexpr int ndigits(std::unsigned_integral auto n) noexcept { - using T = decltype(n); - if constexpr (std::is_same_v) { - return n < 100U ? (n < 10U ? 1 : 2) : 3; - } else if constexpr (std::is_same_v) { - return n < 1000U ? (n < 100U ? (n < 10U ? 1 : 2) : 3) : (n < 10000U ? 4 : 5); - } else if constexpr (std::is_same_v) { - return n < 1000000U ? (n < 1000U ? (n < 100U ? (n < 10U ? 1 : 2) : 3) : (n < 100000U ? (n < 10000U ? 4 : 5) : 6)) - : (n < 100000000U ? (n < 10000000U ? 7 : 8) : (n < 1000000000U ? 9 : 10)); - } else { - // uint64_t - return n < 10000000000UL - ? (n < 1000000UL - ? (n < 1000UL ? (n < 100UL ? (n < 10UL ? 1 : 2) : 3) : (n < 100000UL ? (n < 10000UL ? 4 : 5) : 6)) - : (n < 100000000UL ? (n < 10000000UL ? 7 : 8) : (n < 1000000000UL ? 9 : 10))) - : (n < 10000000000000000UL - ? (n < 10000000000000UL ? (n < 1000000000000UL ? (n < 100000000000UL ? 11 : 12) : 13) - : (n < 1000000000000000UL ? (n < 100000000000000UL ? 14 : 15) : 16)) - : (n < 1000000000000000000UL ? (n < 100000000000000000UL ? 17 : 18) - : (n < 10000000000000000000UL ? 19 : 20))); - } -} - -/// Synonym of ndigits for unsigned types. -constexpr int nchars(std::unsigned_integral auto n) noexcept { return ndigits(n); } - -} // namespace cct \ No newline at end of file diff --git a/src/tech/include/nchars.hpp b/src/tech/include/nchars.hpp new file mode 100644 index 00000000..88f3c4dd --- /dev/null +++ b/src/tech/include/nchars.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include + +#include "ndigits.hpp" + +namespace cct { + +/// Count the number of digits including the possible minus sign for negative integrals. +constexpr int nchars(std::signed_integral auto n) noexcept { return ndigits(n) + static_cast(n < 0); } + +/// Synonym of ndigits for unsigned types. +constexpr int nchars(std::unsigned_integral auto n) noexcept { return ndigits(n); } + +} // namespace cct \ No newline at end of file diff --git a/src/tech/include/ndigits.hpp b/src/tech/include/ndigits.hpp new file mode 100644 index 00000000..c2edf668 --- /dev/null +++ b/src/tech/include/ndigits.hpp @@ -0,0 +1,99 @@ +#pragma once + +#include +#include +#include + +namespace cct { + +/// Return the number of digits of given integral. +/// The minus sign is not counted - use nchars if you want it counted. +/// Maximum of int(log2(std::numeric_limits::digits10)) + 2 comparisons. +constexpr int ndigits(std::signed_integral auto n) noexcept { + using T = decltype(n); + + if constexpr (std::numeric_limits::digits10 == 2) { + return n < 0 ? (n > -10 ? 1 : (n > -100 ? 2 : 3)) : n < 10 ? 1 : (n < 100 ? 2 : 3); + } + + else if constexpr (std::numeric_limits::digits10 == 4) { + return n < 0 ? (n > -100 ? (n > -10 ? 1 : 2) : (n > -1000 ? 3 : (n > -10000 ? 4 : 5))) + : (n < 100 ? (n < 10 ? 1 : 2) : (n < 1000 ? 3 : (n < 10000 ? 4 : 5))); + } + + else if constexpr (std::numeric_limits::digits10 == 9) { + return n < 0 ? (n > -100000 + ? (n > -1000 ? (n > -10 ? 1 : (n > -100 ? 2 : 3)) : (n > -10000 ? 4 : 5)) + : (n > -10000000 ? (n > -1000000 ? 6 : 7) : (n > -1000000000 ? (n > -100000000 ? 8 : 9) : 10))) + : (n < 100000 + ? (n < 1000 ? (n < 10 ? 1 : (n < 100 ? 2 : 3)) : (n < 10000 ? 4 : 5)) + : (n < 10000000 ? (n < 1000000 ? 6 : 7) : (n < 1000000000 ? (n < 100000000 ? 8 : 9) : 10))); + } + + else if constexpr (std::numeric_limits::digits10 == 18) { + return n < 0 + ? (n > -1000000000L + ? (n > -10000L ? (n > -100L ? (n > -10L ? 1 : 2) : (n > -1000L ? 3 : 4)) + : (n > -1000000L ? (n > -100000L ? 5 : 6) + : (n > -10000000L ? 7 : (n > -100000000L ? 8 : 9)))) + : (n > -100000000000000L + ? (n > -1000000000000L ? (n > -10000000000L ? 10 : (n > -100000000000L ? 11 : 12)) + : (n > -10000000000000L ? 13 : 14)) + : (n > -10000000000000000L + ? (n > -1000000000000000L ? 15 : 16) + : (n > -1000000000000000000L ? (n > -100000000000000000L ? 17 : 18) : 19)))) + : (n < 1000000000L + ? (n < 10000L + ? (n < 100L ? (n < 10L ? 1 : 2) : (n < 1000L ? 3 : 4)) + : (n < 1000000L ? (n < 100000L ? 5 : 6) : (n < 10000000L ? 7 : (n < 100000000L ? 8 : 9)))) + : (n < 100000000000000L + ? (n < 1000000000000L ? (n < 10000000000L ? 10 : (n < 100000000000L ? 11 : 12)) + : (n < 10000000000000L ? 13 : 14)) + : (n < 10000000000000000L + ? (n < 1000000000000000L ? 15 : 16) + : (n < 1000000000000000000L ? (n < 100000000000000000L ? 17 : 18) : 19)))); + } + + else { + // Note: below ugly template lambda can be replaced with 'static_assert(false);' in C++23 + []() { static_assert(flag, "unknown digits10 value"); }(); + } +} + +/// Return the number of digits of given integral. +/// Maximum of int(log2(std::numeric_limits::digits10)) + 1 comparisons. +constexpr int ndigits(std::unsigned_integral auto n) noexcept { + using T = decltype(n); + + if constexpr (std::numeric_limits::digits10 == 2) { + return n < 10U ? 1 : (n < 100U ? 2 : 3); + } + + else if constexpr (std::numeric_limits::digits10 == 4) { + return n < 100U ? (n < 10U ? 1 : 2) : (n < 1000U ? 3 : (n < 10000U ? 4 : 5)); + } + + else if constexpr (std::numeric_limits::digits10 == 9) { + return n < 100000U ? (n < 1000U ? (n < 10U ? 1 : (n < 100U ? 2 : 3)) : (n < 10000U ? 4 : 5)) + : (n < 10000000U ? (n < 1000000U ? 6 : 7) : (n < 1000000000U ? (n < 100000000U ? 8 : 9) : 10)); + } + + else if constexpr (std::numeric_limits::digits10 == 19) { + return n < 10000000000UL + ? (n < 1000000UL + ? (n < 1000UL ? (n < 100UL ? (n < 10UL ? 1 : 2) : 3) : (n < 100000UL ? (n < 10000UL ? 4 : 5) : 6)) + : (n < 100000000UL ? (n < 10000000UL ? 7 : 8) : (n < 1000000000UL ? 9 : 10))) + : (n < 10000000000000000UL + ? (n < 10000000000000UL ? (n < 1000000000000UL ? (n < 100000000000UL ? 11 : 12) : 13) + : (n < 1000000000000000UL ? (n < 100000000000000UL ? 14 : 15) : 16)) + : (n < 1000000000000000000UL ? (n < 100000000000000000UL ? 17 : 18) + : (n < 10000000000000000000UL ? 19 : 20))); + } + + else { + // Note: below ugly template lambda can be replaced with 'static_assert(false);' in C++23 + []() { static_assert(flag, "unknown digits10 value"); }(); + } +} + +} // namespace cct \ No newline at end of file diff --git a/src/tech/include/overflow-check.hpp b/src/tech/include/overflow-check.hpp index a0c7782a..75d8c055 100644 --- a/src/tech/include/overflow-check.hpp +++ b/src/tech/include/overflow-check.hpp @@ -2,7 +2,6 @@ #include #include -#include namespace cct { diff --git a/src/tech/include/static_string_view_helpers.hpp b/src/tech/include/static_string_view_helpers.hpp index f5df4d4d..a1cc307d 100644 --- a/src/tech/include/static_string_view_helpers.hpp +++ b/src/tech/include/static_string_view_helpers.hpp @@ -5,7 +5,7 @@ #include #include -#include "mathhelpers.hpp" +#include "nchars.hpp" namespace cct { diff --git a/src/tech/include/stringhelpers.hpp b/src/tech/include/stringhelpers.hpp index 1c191502..3bf066de 100644 --- a/src/tech/include/stringhelpers.hpp +++ b/src/tech/include/stringhelpers.hpp @@ -6,13 +6,12 @@ #include #include #include -#include #include "cct_config.hpp" #include "cct_exception.hpp" #include "cct_fixedcapacityvector.hpp" #include "cct_string.hpp" -#include "mathhelpers.hpp" +#include "nchars.hpp" namespace cct { diff --git a/src/tech/include/timedef.hpp b/src/tech/include/timedef.hpp index fa66ab0c..82c20163 100644 --- a/src/tech/include/timedef.hpp +++ b/src/tech/include/timedef.hpp @@ -39,4 +39,5 @@ constexpr int64_t TimestampToMillisecondsSinceEpoch(TimePoint tp) { constexpr int64_t TimestampToUs(TimePoint tp) { return std::chrono::duration_cast(tp.time_since_epoch()).count(); } + } // namespace cct diff --git a/src/tech/include/timestring.hpp b/src/tech/include/timestring.hpp index 54f18f85..f6ba7cbc 100644 --- a/src/tech/include/timestring.hpp +++ b/src/tech/include/timestring.hpp @@ -31,4 +31,5 @@ Nonce Nonce_TimeSinceEpochInMs(Duration delay = Duration{}); /// Create a Nonce in literal format. /// Example: '2021-06-01T14:44:13' inline Nonce Nonce_LiteralDate(const char* format) { return ToString(Clock::now(), format); } + } // namespace cct diff --git a/src/tech/include/toupperlower.hpp b/src/tech/include/toupperlower.hpp index 2bbe3df9..d23b54ca 100644 --- a/src/tech/include/toupperlower.hpp +++ b/src/tech/include/toupperlower.hpp @@ -1,6 +1,7 @@ #pragma once namespace cct { + /// constexpr version of std::toupper with chars, as unfortunately for now (May 2021) std::toupper is not constexpr constexpr char toupper(char ch) noexcept { switch (ch) { diff --git a/src/tech/include/url-encode.hpp b/src/tech/include/url-encode.hpp index e23fc261..a113161b 100644 --- a/src/tech/include/url-encode.hpp +++ b/src/tech/include/url-encode.hpp @@ -32,7 +32,6 @@ string URLEncode(std::span data, IsNotEncodedFunc isNotEncodedFunc) // const char * argument is deleted because it would construct into a span including the unwanted null // terminating character. Use span directly, or string / string_view instead. - template string URLEncode(const char*, IsNotEncodedFunc) = delete; diff --git a/src/tech/src/simpletable.cpp b/src/tech/src/simpletable.cpp index e48a80af..ebfab06e 100644 --- a/src/tech/src/simpletable.cpp +++ b/src/tech/src/simpletable.cpp @@ -12,7 +12,8 @@ #include #include "cct_smallvector.hpp" -#include "mathhelpers.hpp" +#include "ipow.hpp" +#include "nchars.hpp" namespace cct { diff --git a/src/tech/test/ipow_test.cpp b/src/tech/test/ipow_test.cpp new file mode 100644 index 00000000..246a3c55 --- /dev/null +++ b/src/tech/test/ipow_test.cpp @@ -0,0 +1,28 @@ +#include "ipow.hpp" + +#include + +#include +#include + +namespace cct { + +TEST(MathHelpers, Power) { + EXPECT_EQ(ipow(3, 2), 9); + EXPECT_EQ(ipow(4, 3), 64); + EXPECT_EQ(ipow(-3, 3), -27); + EXPECT_EQ(ipow(-2, 1), -2); + EXPECT_EQ(ipow(17, 5), 1419857); + EXPECT_EQ(ipow(10, 10), 10000000000); + static_assert(ipow(5, 3) == 125); + static_assert(ipow(-7, 0) == 1); +} + +TEST(MathHelpers, Power10) { + EXPECT_EQ(ipow10(0), 1); + EXPECT_EQ(ipow10(1), 10); + EXPECT_EQ(ipow10(2), 100); + EXPECT_EQ(ipow10(10), 10000000000); + static_assert(ipow10(3) == 1000); +} +} // namespace cct \ No newline at end of file diff --git a/src/tech/test/mathhelpers_test.cpp b/src/tech/test/ndigits_test.cpp similarity index 92% rename from src/tech/test/mathhelpers_test.cpp rename to src/tech/test/ndigits_test.cpp index ee2d53bd..bcf0c547 100644 --- a/src/tech/test/mathhelpers_test.cpp +++ b/src/tech/test/ndigits_test.cpp @@ -1,4 +1,4 @@ -#include "mathhelpers.hpp" +#include "ndigits.hpp" #include @@ -7,25 +7,6 @@ namespace cct { -TEST(MathHelpers, Power) { - EXPECT_EQ(ipow(3, 2), 9); - EXPECT_EQ(ipow(4, 3), 64); - EXPECT_EQ(ipow(-3, 3), -27); - EXPECT_EQ(ipow(-2, 1), -2); - EXPECT_EQ(ipow(17, 5), 1419857); - EXPECT_EQ(ipow(10, 10), 10000000000); - static_assert(ipow(5, 3) == 125); - static_assert(ipow(-7, 0) == 1); -} - -TEST(MathHelpers, Power10) { - EXPECT_EQ(ipow10(0), 1); - EXPECT_EQ(ipow10(1), 10); - EXPECT_EQ(ipow10(2), 100); - EXPECT_EQ(ipow10(10), 10000000000); - static_assert(ipow10(3) == 1000); -} - TEST(MathHelpers, NDigitsS8) { EXPECT_EQ(ndigits(static_cast(0)), 1); EXPECT_EQ(ndigits(static_cast(3)), 1); @@ -39,6 +20,16 @@ TEST(MathHelpers, NDigitsS8) { static_assert(ndigits(std::numeric_limits::min()) == 3); } +TEST(MathHelpers, NDigitsChar) { + EXPECT_EQ(ndigits(static_cast(0)), 1); + EXPECT_EQ(ndigits(static_cast(3)), 1); + EXPECT_EQ(ndigits(static_cast(78)), 2); + EXPECT_EQ(ndigits(static_cast(112)), 3); + + static_assert(ndigits(std::numeric_limits::max()) == 3); + static_assert(ndigits(std::numeric_limits::min()) == 3); +} + TEST(MathHelpers, NDigitsS16) { EXPECT_EQ(ndigits(static_cast(0)), 1); EXPECT_EQ(ndigits(static_cast(3)), 1);