Working on optimisation but I'm still losing to std::to_string()

This commit is contained in:
King_DuckZ 2021-05-29 22:51:49 +02:00
parent 420257f578
commit 9dbabcb5c4
6 changed files with 52 additions and 20 deletions

View file

@ -41,6 +41,10 @@ target_compile_definitions(${PROJECT_NAME}
INTERFACE SPROUT_USE_TEMPLATE_ALIASES INTERFACE SPROUT_USE_TEMPLATE_ALIASES
) )
target_compile_options(${PROJECT_NAME}
INTERFACE -mprfchw
)
if (BUILD_TESTING) if (BUILD_TESTING)
add_subdirectory(test/unit) add_subdirectory(test/unit)
endif() endif()

View file

@ -104,11 +104,26 @@ namespace dhandy {
template <typename L> template <typename L>
[[gnu::pure,gnu::always_inline]] [[gnu::pure,gnu::always_inline]]
static constexpr L abs(L in) { return (not BecomesUnsigned and std::numeric_limits<L>::is_signed and in < L(0) ? -in : in); } static constexpr L abs(L v);
[[gnu::pure,gnu::always_inline]] [[gnu::pure,gnu::always_inline]]
static constexpr CastedType cast (I in) { return static_cast<CastedType>(in); } static constexpr CastedType cast (I in) { return static_cast<CastedType>(in); }
}; };
template <typename I, std::size_t Base, bool IsSigned, bool ForceUnsigned>
template <typename L>
[[gnu::const,gnu::always_inline]]
inline constexpr L NumberAdaptation<I, Base, IsSigned, ForceUnsigned>::abs(L v) {
if constexpr (not BecomesUnsigned and std::numeric_limits<L>::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<L>(r);
}
else {
return v;
}
}
template <typename I, unsigned int Base, typename Tr, typename=void> template <typename I, unsigned int Base, typename Tr, typename=void>
struct IntConversion { struct IntConversion {
static constexpr RevArray<I, Base, Tr> to_ary (I in) { static constexpr RevArray<I, Base, Tr> to_ary (I in) {
@ -156,18 +171,21 @@ namespace dhandy {
const bool was_negative = implem::is_negative<I, 10>(in); const bool was_negative = implem::is_negative<I, 10>(in);
RetType arr; RetType arr;
if (not std::is_constant_evaluated())
__builtin_prefetch(arr.base_ptr(), 1, 3);
arr.push_front(Tr::NullChar); arr.push_front(Tr::NullChar);
while (Num::abs(in) >= static_cast<I>(100)) { in = Num::abs(in);
const auto index = (Num::abs(in) % 100) * 2; while (in >= static_cast<I>(100)) {
const auto index = (in % 100) * 2;
arr.push_front(Tr::to_digit(static_cast<int>(lookup[index + 1]))); arr.push_front(Tr::to_digit(static_cast<int>(lookup[index + 1])));
arr.push_front(Tr::to_digit(static_cast<int>(lookup[index + 0]))); arr.push_front(Tr::to_digit(static_cast<int>(lookup[index + 0])));
in = static_cast<I>(in / static_cast<I>(100)); in = static_cast<I>(in / static_cast<I>(100));
}; };
if (Num::abs(in) < static_cast<I>(10)) { if (in < static_cast<I>(10)) {
arr.push_front(Tr::to_digit(static_cast<int>(Num::abs(in)))); arr.push_front(Tr::to_digit(static_cast<int>(in)));
} }
else { else {
const auto index = Num::abs(in) * 2; const auto index = in * 2;
arr.push_front(Tr::to_digit(static_cast<int>(lookup[index + 1]))); arr.push_front(Tr::to_digit(static_cast<int>(lookup[index + 1])));
arr.push_front(Tr::to_digit(static_cast<int>(lookup[index + 0]))); arr.push_front(Tr::to_digit(static_cast<int>(lookup[index + 0])));
} }
@ -301,17 +319,24 @@ namespace dhandy {
static const constexpr unsigned int DigitCount = DCount; static const constexpr unsigned int DigitCount = DCount;
static constexpr C to_digit (unsigned int num) { static constexpr C to_digit (unsigned int num) {
return (num < DigitCount ? constexpr const C ret[2] = {FirstDigit, FirstLetter - DigitCount};
static_cast<C>(num + FirstDigit) : #if 0
static_cast<C>(num + FirstLetter - DigitCount) //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) { static constexpr int from_digit (C dig) {
return (dig < FirstLetter ? //return (dig < FirstLetter ? dig - FirstDigit : dig - FirstLetter + DigitCount);
dig - FirstDigit : typedef typename std::make_unsigned<C>::type UC;
dig - FirstLetter + DigitCount constexpr const C ret[2] = {FirstLetter - DigitCount, FirstDigit};
); const auto w = static_cast<UC>(dig - FirstLetter) >> (sizeof(UC) * CHAR_BIT - 1);
return dig - ret[w];
} }
}; };
template <typename C> template <typename C>

View file

@ -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 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 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* 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 begin() { return m_data.begin() + m_curr + 1; }
constexpr iterator end() { return m_data.end(); } constexpr iterator end() { return m_data.end(); }
constexpr const T& back() const { return *(m_data.data() + S - 1); } constexpr const T& back() const { return *(m_data.data() + S - 1); }
@ -62,6 +63,8 @@ namespace dhandy {
bool operator!= (const std::basic_string<T>& other) const { return not operator==(other); } bool operator!= (const std::basic_string<T>& other) const { return not operator==(other); }
bool operator== (const T* other) const { return to_string_view() == std::basic_string_view<T>(other); } bool operator== (const T* other) const { return to_string_view() == std::basic_string_view<T>(other); }
bool operator!= (const T* other) const { return not operator==(other); } bool operator!= (const T* other) const { return not operator==(other); }
std::string to_string() const { return to<std::basic_string<T>>(); }
#endif #endif
private: private:

View file

@ -91,9 +91,9 @@ namespace dhandy {
}; };
} //namespace implem } //namespace implem
template <typename To, typename From> template <typename To, typename From, bool AllCaps=false>
constexpr inline To int_conv (const From& from, bool all_caps=false) { constexpr inline To int_conv (const From& from, std::integral_constant<bool, AllCaps> = std::integral_constant<bool, AllCaps>{}) {
if (all_caps) if constexpr (AllCaps)
return implem::IntConv<To, From, ASCIITranslatorUpcase<char>>::conv(from); return implem::IntConv<To, From, ASCIITranslatorUpcase<char>>::conv(from);
else else
return implem::IntConv<To, From, ASCIITranslator<char>>::conv(from); return implem::IntConv<To, From, ASCIITranslator<char>>::conv(from);

View file

@ -1,9 +1,9 @@
project(dhandy_unit_test CXX) project(dhandy_unit_test CXX)
add_executable(${PROJECT_NAME} add_executable(${PROJECT_NAME}
int_conv_test.cpp
main.cpp main.cpp
endianness_test.cpp endianness_test.cpp
int_conv_test.cpp
reversed_sized_array_test.cpp reversed_sized_array_test.cpp
bitfield_pack_test.cpp bitfield_pack_test.cpp
resource_pool_test.cpp resource_pool_test.cpp

View file

@ -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]") { 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; using dhandy::ASCIITranslator;
std::wstring_view exp1(L"235713"); std::wstring_view exp1(L"235713");
auto val1 = int_to_ary<int, 10, ASCIITranslator<wchar_t>>(235713).to_string_view(); auto val1 = buildtime_int_to_ary<int, 235713, 10, ASCIITranslator<wchar_t>>().to_string_view();
CHECK(exp1 == val1); CHECK(exp1 == val1);
} }