From dea69677ebb863923591340a560bb34585ccbae7 Mon Sep 17 00:00:00 2001 From: Matt Borland Date: Wed, 18 Jan 2023 11:36:04 -0800 Subject: [PATCH] Add binary search trees for 32, 64 and 128 bit types --- .../charconv/detail/integer_search_trees.hpp | 233 ++++++++++++++++++ include/boost/charconv/to_chars.hpp | 1 + 2 files changed, 234 insertions(+) create mode 100644 include/boost/charconv/detail/integer_search_trees.hpp diff --git a/include/boost/charconv/detail/integer_search_trees.hpp b/include/boost/charconv/detail/integer_search_trees.hpp new file mode 100644 index 0000000..41f23fb --- /dev/null +++ b/include/boost/charconv/detail/integer_search_trees.hpp @@ -0,0 +1,233 @@ +// Copyright 2023 Matt Borland +// Distributed under the Boost Software License, Version 1.0. +// https://www.boost.org/LICENSE_1_0.txt + +#ifndef BOOST_CHARCONV_DETAIL_INTEGER_SEARCH_TREES_HPP +#define BOOST_CHARCONV_DETAIL_INTEGER_SEARCH_TREES_HPP + +// https://stackoverflow.com/questions/1489830/efficient-way-to-determine-number-of-digits-in-an-integer?page=1&tab=scoredesc#tab-top +// https://graphics.stanford.edu/~seander/bithacks.html + +#include "../config.hpp" +#include +#include +#include + +// Generic solution +template +BOOST_CXX14_CONSTEXPR int num_digits(T x) noexcept +{ + int digits = 0; + + while (x) + { + x /= 10; + ++digits; + } + + return digits; +} + +template <> +BOOST_CXX14_CONSTEXPR int num_digits(std::uint32_t x) noexcept +{ + if (x >= UINT32_C(10000)) + { + if (x >= UINT32_C(10000000)) + { + if (x >= UINT32_C(100000000)) + { + if (x >= UINT32_C(1000000000)) + { + return 10; + } + return 9; + } + return 8; + } + + else if (x >= UINT32_C(100000)) + { + if (x >= UINT32_C(1000000)) + { + return 7; + } + return 6; + } + return 5; + } + else if (x >= UINT32_C(100)) + { + if (x >= UINT32_C(1000)) + { + return 4; + } + return 3; + } + else if (x >= UINT32_C(10)) + { + return 2; + } + + return 1; +} + +template <> +BOOST_CXX14_CONSTEXPR int num_digits(std::uint64_t x) noexcept +{ + if (x >= UINT64_C(10000000000)) + { + if (x >= UINT64_C(100000000000000)) + { + if (x >= UINT64_C(10000000000000000)) + { + if (x >= UINT64_C(100000000000000000)) + { + if (x >= UINT64_C(1000000000000000000)) + { + if (x >= UINT64_C(10000000000000000000)) + { + return 20; + } + return 19; + } + return 18; + } + return 17; + } + else if (x >= UINT64_C(1000000000000000)) + { + return 16; + } + return 15; + } + if (x >= UINT64_C(1000000000000)) + { + if (x >= UINT64_C(10000000000000)) + { + return 14; + } + return 13; + } + if (x >= UINT64_C(100000000000)) + { + return 12; + } + return 11; + } + else if (x >= UINT64_C(100000)) + { + if (x >= UINT64_C(10000000)) + { + if (x >= UINT64_C(100000000)) + { + if (x >= UINT64_C(1000000000)) + { + return 10; + } + return 9; + } + return 8; + } + if (x >= UINT64_C(1000000)) + { + return 7; + } + return 6; + } + if (x >= UINT64_C(100)) + { + if (x >= UINT64_C(1000)) + { + if (x >= UINT64_C(10000)) + { + return 5; + } + return 4; + } + return 3; + } + if (x >= UINT64_C(10)) + { + return 2; + } + return 1; +} + +#ifdef __GLIBCXX_TYPE_INT_N_0 +static constexpr std::array powers_of_10 = +{{ + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, + 100000000000, 1000000000000, 10000000000000, 100000000000000, 1000000000000000, 10000000000000000, + 100000000000000000, 1000000000000000000, 10000000000000000000 +}}; + +// Assume that if someone is using 128 bit ints they are favoring the top end of the range +// Max value is 340,282,366,920,938,463,463,374,607,431,768,211,455 (39 digits) +BOOST_CXX14_CONSTEXPR int num_digits(unsigned __int128 x) noexcept +{ + // There is not literal for unsigned __int128 so we need to calculate them using the max value of the + // std::uint64_t powers of 10 + constexpr unsigned __int128 digits_39 = static_cast(powers_of_10[19]) * static_cast(powers_of_10[18]); + constexpr unsigned __int128 digits_38 = digits_39 / 10; + constexpr unsigned __int128 digits_37 = digits_38 / 10; + constexpr unsigned __int128 digits_36 = digits_37 / 10; + constexpr unsigned __int128 digits_35 = digits_36 / 10; + constexpr unsigned __int128 digits_34 = digits_35 / 10; + constexpr unsigned __int128 digits_33 = digits_34 / 10; + constexpr unsigned __int128 digits_32 = digits_33 / 10; + constexpr unsigned __int128 digits_31 = digits_32 / 10; + constexpr unsigned __int128 digits_30 = digits_31 / 10; + constexpr unsigned __int128 digits_29 = digits_30 / 10; + constexpr unsigned __int128 digits_28 = digits_29 / 10; + constexpr unsigned __int128 digits_27 = digits_28 / 10; + constexpr unsigned __int128 digits_26 = digits_27 / 10; + constexpr unsigned __int128 digits_25 = digits_26 / 10; + constexpr unsigned __int128 digits_24 = digits_25 / 10; + constexpr unsigned __int128 digits_23 = digits_24 / 10; + constexpr unsigned __int128 digits_22 = digits_23 / 10; + constexpr unsigned __int128 digits_21 = digits_22 / 10; + + return (x > digits_39) ? 39 : + (x > digits_38) ? 38 : + (x > digits_37) ? 37 : + (x > digits_36) ? 36 : + (x > digits_35) ? 35 : + (x > digits_34) ? 34 : + (x > digits_33) ? 33 : + (x > digits_32) ? 32 : + (x > digits_31) ? 31 : + (x > digits_30) ? 30 : + (x > digits_29) ? 29 : + (x > digits_28) ? 28 : + (x > digits_27) ? 27 : + (x > digits_26) ? 26 : + (x > digits_25) ? 25 : + (x > digits_24) ? 24 : + (x > digits_23) ? 23 : + (x > digits_22) ? 22 : + (x > digits_21) ? 21 : + (x > powers_of_10[19]) ? 20 : + (x > powers_of_10[18]) ? 19 : + (x > powers_of_10[17]) ? 18 : + (x > powers_of_10[16]) ? 17 : + (x > powers_of_10[15]) ? 16 : + (x > powers_of_10[14]) ? 15 : + (x > powers_of_10[13]) ? 14 : + (x > powers_of_10[12]) ? 13 : + (x > powers_of_10[11]) ? 12 : + (x > powers_of_10[10]) ? 11 : + (x > powers_of_10[9]) ? 10 : + (x > powers_of_10[8]) ? 9 : + (x > powers_of_10[7]) ? 8 : + (x > powers_of_10[6]) ? 7 : + (x > powers_of_10[5]) ? 6 : + (x > powers_of_10[4]) ? 5 : + (x > powers_of_10[3]) ? 4 : + (x > powers_of_10[2]) ? 3 : + (x > powers_of_10[1]) ? 2 : + (x > powers_of_10[0]) ? 1 : 0; +} +#endif // 128-bit support + +#endif // BOOST_CHARCONV_DETAIL_INTEGER_SEARCH_TREES_HPP diff --git a/include/boost/charconv/to_chars.hpp b/include/boost/charconv/to_chars.hpp index 9c693dc..577745b 100644 --- a/include/boost/charconv/to_chars.hpp +++ b/include/boost/charconv/to_chars.hpp @@ -6,6 +6,7 @@ #ifndef BOOST_CHARCONV_TO_CHARS_HPP_INCLUDED #define BOOST_CHARCONV_TO_CHARS_HPP_INCLUDED +#include #include #include #include