diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml new file mode 100644 index 00000000..bed6ffd9 --- /dev/null +++ b/.github/workflows/macos.yml @@ -0,0 +1,22 @@ +name: macOS + +on: + push: + branches: + - master + pull_request: + +jobs: + xcode: + runs-on: macos-latest + env: + DEVELOPER_DIR: /Applications/Xcode_12.4.app/Contents/Developer + + steps: + - uses: actions/checkout@v2 + - name: cmake + run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=g++-11 -DOPENSSL_ROOT_DIR=/usr/local/Cellar/openssl@1.1/1.1.1k + - name: build + run: cmake --build build --parallel 2 + - name: test + run: cd build && ctest -j 2 --output-on-failure diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 7fc03677..135f6888 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -35,11 +35,11 @@ jobs: working-directory: ${{github.workspace}}/build shell: bash # Execute the build. You can specify a specific target with "--target " - run: cmake --build . --config ${{matrix.buildmode}} -j 8 + run: cmake --build . --config ${{matrix.buildmode}} -j 2 - name: Test working-directory: ${{github.workspace}}/build shell: bash # Execute tests defined by the CMake configuration. Print debug traces on failure # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail - run: ctest -j 8 -C ${{matrix.buildmode}} --output-on-failure + run: ctest -j 2 -C ${{matrix.buildmode}} --output-on-failure diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index ee2f4a27..8f5db630 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -34,8 +34,8 @@ jobs: - name: Build working-directory: ${{github.workspace}}/build - run: cmake --build . --config ${{matrix.buildmode}} + run: cmake --build . --config ${{matrix.buildmode}} --parallel 2 - name: Tests working-directory: ${{github.workspace}}/build - run: ctest -C ${{matrix.buildmode}} -j 10 --output-on-failure + run: ctest -C ${{matrix.buildmode}} -j 2 --output-on-failure diff --git a/README.md b/README.md index 1b4f4937..77e3ea98 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ -[![ubuntu](https://github.com/sjanel/coincenter/actions/workflows/ubuntu.yml/badge.svg?branch=master)](https://github.com/sjanel/coincenter/actions/workflows/ubuntu.yml) [![alpine_docker](https://github.com/sjanel/coincenter/actions/workflows/alpine_docker.yml/badge.svg?branch=master)](https://github.com/sjanel/coincenter/actions/workflows/alpine_docker.yml) +[![macos](https://github.com/sjanel/coincenter/actions/workflows/macos.yml/badge.svg?branch=master)](https://github.com/sjanel/coincenter/actions/workflows/macos.yml) +[![ubuntu](https://github.com/sjanel/coincenter/actions/workflows/ubuntu.yml/badge.svg?branch=master)](https://github.com/sjanel/coincenter/actions/workflows/ubuntu.yml) [![windows](https://github.com/sjanel/coincenter/actions/workflows/windows.yml/badge.svg?branch=master)](https://github.com/sjanel/coincenter/actions/workflows/windows.yml) [![formatted](https://github.com/sjanel/coincenter/actions/workflows/clang-format-check.yml/badge.svg?branch=master)](https://github.com/sjanel/coincenter/actions/workflows/clang-format-check.yml) diff --git a/src/tools/include/cct_mathhelpers.hpp b/src/tools/include/cct_mathhelpers.hpp index 8e20955f..585d2159 100644 --- a/src/tools/include/cct_mathhelpers.hpp +++ b/src/tools/include/cct_mathhelpers.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -67,42 +68,72 @@ constexpr int64_t ipow(int64_t base, uint8_t exp) { } } -/// Return the number of digits of given integral. -/// Uses dichotomy for highest performance as possible. -constexpr int ndigits(int32_t n) { - if (n < 0) { - if (CCT_UNLIKELY(n == std::numeric_limits::min())) { - ++n; - } - n *= -1; - } - return 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)); -} +template +concept SignedIntegral = std::integral&& std::is_signed::value; + +template +concept UnsignedIntegral = std::integral && !SignedIntegral; /// Return the number of digits of given integral. /// Uses dichotomy for highest performance as possible. -constexpr int ndigits(uint64_t n) { - 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))); +template +constexpr int ndigits(T 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))); + } } /// Return the number of digits of given integral. /// Uses dichotomy for highest performance as possible. -constexpr int ndigits(int64_t n) { - if (n < 0) { - if (CCT_UNLIKELY(n == std::numeric_limits::min())) { - ++n; - } - n *= -1; +template +constexpr int ndigits(T 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))); } - return ndigits(static_cast(n)); } + } // namespace cct \ No newline at end of file diff --git a/src/tools/test/cct_mathhelpers_test.cpp b/src/tools/test/cct_mathhelpers_test.cpp index 4afcf96d..3fc1de44 100644 --- a/src/tools/test/cct_mathhelpers_test.cpp +++ b/src/tools/test/cct_mathhelpers_test.cpp @@ -15,46 +15,165 @@ TEST(MathHelpers, Power) { static_assert(ipow(-7, 0) == 1); } -TEST(MathHelpers, NDigits) { +TEST(MathHelpers, NDigitsS8) { + 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); + EXPECT_EQ(ndigits(static_cast(-125)), 3); + EXPECT_EQ(ndigits(static_cast(-10)), 2); + EXPECT_EQ(ndigits(static_cast(-1)), 1); + + 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); + EXPECT_EQ(ndigits(static_cast(78)), 2); + EXPECT_EQ(ndigits(static_cast(170)), 3); + EXPECT_EQ(ndigits(static_cast(9245)), 4); + EXPECT_EQ(ndigits(static_cast(31710)), 5); + EXPECT_EQ(ndigits(static_cast(-26816)), 5); + EXPECT_EQ(ndigits(static_cast(-3686)), 4); + EXPECT_EQ(ndigits(static_cast(-686)), 3); + EXPECT_EQ(ndigits(static_cast(-10)), 2); + EXPECT_EQ(ndigits(static_cast(-2)), 1); + + static_assert(ndigits(std::numeric_limits::max()) == 5); + static_assert(ndigits(std::numeric_limits::min()) == 5); +} + +TEST(MathHelpers, NDigitsS32) { EXPECT_EQ(ndigits(0), 1); - EXPECT_EQ(ndigits(-3), 1); - EXPECT_EQ(ndigits(-78), 2); + EXPECT_EQ(ndigits(3), 1); + EXPECT_EQ(ndigits(78), 2); EXPECT_EQ(ndigits(170), 3); - EXPECT_EQ(ndigits(-9245), 4); - EXPECT_EQ(ndigits(100000), 6); + EXPECT_EQ(ndigits(9245), 4); EXPECT_EQ(ndigits(35710), 5); + EXPECT_EQ(ndigits(100000), 6); EXPECT_EQ(ndigits(1035710), 7); - EXPECT_EQ(ndigits(-5905614858), 10); + EXPECT_EQ(ndigits(21035710), 8); + EXPECT_EQ(ndigits(461035710), 9); + EXPECT_EQ(ndigits(5905614858), 10); + EXPECT_EQ(ndigits(-3954784858), 10); EXPECT_EQ(ndigits(-908561485), 9); - EXPECT_EQ(ndigits(18561485), 8); + EXPECT_EQ(ndigits(-18561485), 8); EXPECT_EQ(ndigits(-1861485), 7); EXPECT_EQ(ndigits(-186148), 6); - EXPECT_EQ(ndigits(36816), 5); + EXPECT_EQ(ndigits(-36816), 5); EXPECT_EQ(ndigits(-3686), 4); - EXPECT_EQ(ndigits(686), 3); + EXPECT_EQ(ndigits(-686), 3); EXPECT_EQ(ndigits(-10), 2); - EXPECT_EQ(ndigits(1), 1); + EXPECT_EQ(ndigits(-1), 1); + static_assert(ndigits(std::numeric_limits::max()) == 10); static_assert(ndigits(std::numeric_limits::min()) == 10); +} - EXPECT_EQ(ndigits(std::numeric_limits::max()), 19); - EXPECT_EQ(ndigits(7299385028562659L), 16); - EXPECT_EQ(ndigits(299385028562659L), 15); - EXPECT_EQ(ndigits(29938502856265L), 14); +TEST(MathHelpers, NDigitsS64) { + EXPECT_EQ(ndigits(0L), 1); + EXPECT_EQ(ndigits(3L), 1); + EXPECT_EQ(ndigits(78L), 2); + EXPECT_EQ(ndigits(170L), 3); + EXPECT_EQ(ndigits(9245L), 4); + EXPECT_EQ(ndigits(35710L), 5); + EXPECT_EQ(ndigits(100000L), 6); + EXPECT_EQ(ndigits(1035710L), 7); + EXPECT_EQ(ndigits(18561485L), 8); + EXPECT_EQ(ndigits(908561485L), 9); + EXPECT_EQ(ndigits(5905614858L), 10); + EXPECT_EQ(ndigits(59085614858L), 11); + EXPECT_EQ(ndigits(590385614858L), 12); EXPECT_EQ(ndigits(2938502856265L), 13); + EXPECT_EQ(ndigits(29938502856265L), 14); + EXPECT_EQ(ndigits(299385028562659L), 15); + EXPECT_EQ(ndigits(7299385028562659L), 16); + static_assert(ndigits(72993850285626590L) == 17); + EXPECT_EQ(ndigits(372993850285626590L), 18); + EXPECT_EQ(ndigits(8729938502856126509L), 19); + EXPECT_EQ(ndigits(std::numeric_limits::max()), 19); + EXPECT_EQ(ndigits(std::numeric_limits::min()), 19); + EXPECT_EQ(ndigits(-372909385028562659L), 18); + EXPECT_EQ(ndigits(-87299385028566509L), 17); + EXPECT_EQ(ndigits(-7299385028562659L), 16); + EXPECT_EQ(ndigits(-299385028562659L), 15); + EXPECT_EQ(ndigits(-29938502856265L), 14); + EXPECT_EQ(ndigits(-2938502856265L), 13); EXPECT_EQ(ndigits(-590385614858L), 12); EXPECT_EQ(ndigits(-59085614858L), 11); EXPECT_EQ(ndigits(-5905614858L), 10); - EXPECT_EQ(ndigits(-908561485), 9); - EXPECT_EQ(ndigits(18561485), 8); - EXPECT_EQ(ndigits(1861485), 7); - EXPECT_EQ(ndigits(186148), 6); - EXPECT_EQ(ndigits(36816), 5); - EXPECT_EQ(ndigits(3686), 4); - EXPECT_EQ(ndigits(686), 3); - EXPECT_EQ(ndigits(10), 2); - EXPECT_EQ(ndigits(0), 1); - static_assert(ndigits(72993850285626590L) == 17); + EXPECT_EQ(ndigits(-908561485L), 9); + EXPECT_EQ(ndigits(-93058365L), 8); + EXPECT_EQ(ndigits(-1861485L), 7); + EXPECT_EQ(ndigits(-186148L), 6); + EXPECT_EQ(ndigits(-73686L), 5); + EXPECT_EQ(ndigits(-3686L), 4); + EXPECT_EQ(ndigits(-686L), 3); + EXPECT_EQ(ndigits(-10L), 2); +} + +TEST(MathHelpers, NDigitsU8) { + 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(200)), 3); + + static_assert(ndigits(std::numeric_limits::max()) == 3); + static_assert(ndigits(std::numeric_limits::min()) == 1); +} + +TEST(MathHelpers, NDigitsU16) { + EXPECT_EQ(ndigits(static_cast(0)), 1); + EXPECT_EQ(ndigits(static_cast(10)), 2); + EXPECT_EQ(ndigits(static_cast(170)), 3); + EXPECT_EQ(ndigits(static_cast(4710)), 4); + EXPECT_EQ(ndigits(static_cast(46816)), 5); + + static_assert(ndigits(std::numeric_limits::max()) == 5); + static_assert(ndigits(std::numeric_limits::min()) == 1); } +TEST(MathHelpers, NDigitsU32) { + EXPECT_EQ(ndigits(0U), 1); + EXPECT_EQ(ndigits(3U), 1); + EXPECT_EQ(ndigits(78U), 2); + EXPECT_EQ(ndigits(170U), 3); + EXPECT_EQ(ndigits(9245U), 4); + EXPECT_EQ(ndigits(35710U), 5); + EXPECT_EQ(ndigits(100000U), 6); + EXPECT_EQ(ndigits(1035710U), 7); + EXPECT_EQ(ndigits(31035710U), 8); + EXPECT_EQ(ndigits(561035710U), 9); + EXPECT_EQ(ndigits(4105614858U), 10); + + static_assert(ndigits(std::numeric_limits::max()) == 10); + static_assert(ndigits(std::numeric_limits::min()) == 1); +} + +TEST(MathHelpers, NDigitsU64) { + EXPECT_EQ(ndigits(0UL), 1); + EXPECT_EQ(ndigits(3UL), 1); + EXPECT_EQ(ndigits(78UL), 2); + EXPECT_EQ(ndigits(170UL), 3); + EXPECT_EQ(ndigits(9245UL), 4); + EXPECT_EQ(ndigits(35710UL), 5); + EXPECT_EQ(ndigits(100000UL), 6); + EXPECT_EQ(ndigits(1035710UL), 7); + EXPECT_EQ(ndigits(18561485UL), 8); + EXPECT_EQ(ndigits(908561485UL), 9); + EXPECT_EQ(ndigits(5905614858UL), 10); + EXPECT_EQ(ndigits(59085614858UL), 11); + EXPECT_EQ(ndigits(590385614858UL), 12); + EXPECT_EQ(ndigits(2938502856265UL), 13); + EXPECT_EQ(ndigits(29938502856265UL), 14); + EXPECT_EQ(ndigits(299385028562659UL), 15); + EXPECT_EQ(ndigits(7299385028562659UL), 16); + static_assert(ndigits(72993850285626590UL) == 17); + EXPECT_EQ(ndigits(372993850285626590UL), 18); + EXPECT_EQ(ndigits(8729938502856126509UL), 19); + EXPECT_EQ(ndigits(std::numeric_limits::max()), 20); + EXPECT_EQ(ndigits(std::numeric_limits::min()), 1); +} } // namespace cct