diff --git a/CMakeLists.txt b/CMakeLists.txt index 1896d76..bd1965b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,10 @@ target_compile_definitions(${PROJECT_NAME} INTERFACE SPROUT_USE_TEMPLATE_ALIASES ) +target_compile_options(${PROJECT_NAME} + INTERFACE -mprfchw +) + if (BUILD_TESTING) add_subdirectory(test/unit) endif() diff --git a/include/duckhandy/implem/int_conv.hpp b/include/duckhandy/implem/int_conv.hpp index 6a901e0..9c6a661 100644 --- a/include/duckhandy/implem/int_conv.hpp +++ b/include/duckhandy/implem/int_conv.hpp @@ -104,11 +104,26 @@ namespace dhandy { template [[gnu::pure,gnu::always_inline]] - static constexpr L abs(L in) { return (not BecomesUnsigned and std::numeric_limits::is_signed and in < L(0) ? -in : in); } + static constexpr L abs(L v); [[gnu::pure,gnu::always_inline]] static constexpr CastedType cast (I in) { return static_cast(in); } }; + template + template + [[gnu::const,gnu::always_inline]] + inline constexpr L NumberAdaptation::abs(L v) { + if constexpr (not BecomesUnsigned and std::numeric_limits::is_signed) { + //https://graphics.stanford.edu/~seander/bithacks.html#IntegerAbs + const L mask = v >> (sizeof(L) * CHAR_BIT - 1); + const UnsignedType r = (v + mask) ^ mask; + return static_cast(r); + } + else { + return v; + } + } + template struct IntConversion { static constexpr RevArray to_ary (I in) { @@ -156,18 +171,21 @@ namespace dhandy { const bool was_negative = implem::is_negative(in); RetType arr; + if (not std::is_constant_evaluated()) + __builtin_prefetch(arr.base_ptr(), 1, 3); arr.push_front(Tr::NullChar); - while (Num::abs(in) >= static_cast(100)) { - const auto index = (Num::abs(in) % 100) * 2; + in = Num::abs(in); + while (in >= static_cast(100)) { + const auto index = (in % 100) * 2; arr.push_front(Tr::to_digit(static_cast(lookup[index + 1]))); arr.push_front(Tr::to_digit(static_cast(lookup[index + 0]))); in = static_cast(in / static_cast(100)); }; - if (Num::abs(in) < static_cast(10)) { - arr.push_front(Tr::to_digit(static_cast(Num::abs(in)))); + if (in < static_cast(10)) { + arr.push_front(Tr::to_digit(static_cast(in))); } else { - const auto index = Num::abs(in) * 2; + const auto index = in * 2; arr.push_front(Tr::to_digit(static_cast(lookup[index + 1]))); arr.push_front(Tr::to_digit(static_cast(lookup[index + 0]))); } @@ -301,17 +319,24 @@ namespace dhandy { static const constexpr unsigned int DigitCount = DCount; static constexpr C to_digit (unsigned int num) { - return (num < DigitCount ? - static_cast(num + FirstDigit) : - static_cast(num + FirstLetter - DigitCount) - ); + constexpr const C ret[2] = {FirstDigit, FirstLetter - DigitCount}; +#if 0 + //https://graphics.stanford.edu/~seander/bithacks.html#ConditionalSetOrClearBitsWithoutBranching + const bool f = num >= DigitCount; + constexpr const unsigned int m = 1; + const unsigned int w = (-f & m); +#else + const auto w = (DigitCount - 1 - num) >> (sizeof(unsigned int) * CHAR_BIT - 1); +#endif + return num + ret[w]; } static constexpr int from_digit (C dig) { - return (dig < FirstLetter ? - dig - FirstDigit : - dig - FirstLetter + DigitCount - ); + //return (dig < FirstLetter ? dig - FirstDigit : dig - FirstLetter + DigitCount); + typedef typename std::make_unsigned::type UC; + constexpr const C ret[2] = {FirstLetter - DigitCount, FirstDigit}; + const auto w = static_cast(dig - FirstLetter) >> (sizeof(UC) * CHAR_BIT - 1); + return dig - ret[w]; } }; template diff --git a/include/duckhandy/implem/reversed_sized_array_bt.hpp b/include/duckhandy/implem/reversed_sized_array_bt.hpp index 225c817..e31641d 100644 --- a/include/duckhandy/implem/reversed_sized_array_bt.hpp +++ b/include/duckhandy/implem/reversed_sized_array_bt.hpp @@ -46,6 +46,7 @@ namespace dhandy { constexpr T& operator[] (std::size_t idx) { if (idx >= size()) throw std::out_of_range("Out of bound array access"); return m_data[idx + m_curr + 1]; } constexpr void push_front (const T& itm) { if (size() == S) throw std::length_error("ReversedSizedArray is full"); m_data[m_curr--] = itm; } constexpr const T* data() const { return m_data.data() + m_curr + 1; } + constexpr const T* base_ptr() const { return m_data.data(); } constexpr iterator begin() { return m_data.begin() + m_curr + 1; } constexpr iterator end() { return m_data.end(); } constexpr const T& back() const { return *(m_data.data() + S - 1); } @@ -62,6 +63,8 @@ namespace dhandy { bool operator!= (const std::basic_string& other) const { return not operator==(other); } bool operator== (const T* other) const { return to_string_view() == std::basic_string_view(other); } bool operator!= (const T* other) const { return not operator==(other); } + + std::string to_string() const { return to>(); } #endif private: diff --git a/include/duckhandy/int_conv.hpp b/include/duckhandy/int_conv.hpp index 1e31501..69fa51c 100644 --- a/include/duckhandy/int_conv.hpp +++ b/include/duckhandy/int_conv.hpp @@ -91,9 +91,9 @@ namespace dhandy { }; } //namespace implem - template - constexpr inline To int_conv (const From& from, bool all_caps=false) { - if (all_caps) + template + constexpr inline To int_conv (const From& from, std::integral_constant = std::integral_constant{}) { + if constexpr (AllCaps) return implem::IntConv>::conv(from); else return implem::IntConv>::conv(from); diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 049d6da..4e5c5f2 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -1,9 +1,9 @@ project(dhandy_unit_test CXX) add_executable(${PROJECT_NAME} + int_conv_test.cpp main.cpp endianness_test.cpp - int_conv_test.cpp reversed_sized_array_test.cpp bitfield_pack_test.cpp resource_pool_test.cpp diff --git a/test/unit/int_conv_test.cpp b/test/unit/int_conv_test.cpp index f79115f..9b3de00 100644 --- a/test/unit/int_conv_test.cpp +++ b/test/unit/int_conv_test.cpp @@ -266,11 +266,11 @@ TEST_CASE ("Check upcase/downcase int to array conversions", "[i2s][int_conv]") } TEST_CASE ("Try int conv with non-char", "[s2i][int_conv]") { - using dhandy::int_to_ary; + using dhandy::buildtime_int_to_ary; using dhandy::ASCIITranslator; std::wstring_view exp1(L"235713"); - auto val1 = int_to_ary>(235713).to_string_view(); + auto val1 = buildtime_int_to_ary>().to_string_view(); CHECK(exp1 == val1); }