Working on optimisation but I'm still losing to std::to_string()
This commit is contained in:
parent
420257f578
commit
9dbabcb5c4
6 changed files with 52 additions and 20 deletions
|
@ -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()
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue