Add case sensitivity support to sse conversion

This commit is contained in:
King_DuckZ 2021-05-29 12:01:01 +02:00
parent 094f7fc679
commit a675624cab
2 changed files with 63 additions and 7 deletions

View file

@ -18,7 +18,8 @@
#ifndef id4754A95F12BE4ADEA65642A056A51907
#define id4754A95F12BE4ADEA65642A056A51907
#include "duckhandy/implem/reversed_sized_array_bt.hpp"
#include "reversed_sized_array_bt.hpp"
#include "../has_method.hpp"
#include <sprout/math/log10.hpp>
#include <sprout/math/abs.hpp>
#include <sprout/math/ceil.hpp>
@ -51,6 +52,14 @@ namespace dhandy {
}
} //unnamed namespace
//Used for checking ASCIITranslator::AltLetter
define_has_enum(AltLetter, AltLetter);
template <typename Tr, bool=HasAltLetterEnum<Tr>::value != 0>
inline auto g_AltLetterOrZero = Tr::AltLetter;
template <typename Tr>
inline auto g_AltLetterOrZero<Tr, false> = Tr::NullChar;
template <typename T, typename C, unsigned int Base, typename Tr>
T to_integer_sse (const C* s, std::size_t l);
@ -202,7 +211,7 @@ namespace dhandy {
};
template <typename I, unsigned int Base, typename Tr>
struct AryConversion<I, Base, Tr, false, typename std::enable_if<Tr::BehavesLikeASCII and std::is_integral<I>::value and not std::is_same<I, bool>::value and sizeof(I) <= sizeof(std::uint32_t)>::type> {
struct AryConversion<I, Base, Tr, false, typename std::enable_if<std::is_integral<I>::value and not std::is_same<I, bool>::value and sizeof(I) <= sizeof(std::uint32_t)>::type> {
constexpr static const bool is_sse = true;
template <typename C> static I from_ary (C* beg, C* end) { return to_integer_sse<I, C, Base, Tr>(beg, end - beg); }
};
@ -246,13 +255,24 @@ namespace dhandy {
__m128i factor = _mm_set_epi32(base3, base2, base1, 1);
__m128i res = _mm_set1_epi32(0);
const __m128i char_0 = _mm_set1_epi32(Tr::FirstDigit);
const __m128i char_a = _mm_set1_epi32(Tr::FirstLetter);
const __m128i char_befo_a = _mm_set1_epi32(Tr::FirstLetter - 1);
const __m128i char_past_f = _mm_set1_epi32(Tr::FirstLetter + Base - 10);
std::size_t idx = 0;
const std::size_t cap = l bitand -4;
do {
const __m128i digits = _mm_set_epi32(s[cap - idx - 3 - 1], s[cap - idx - 2 - 1], s[cap - idx - 1 - 1], s[cap - idx - 0 - 1]);
const __m128i mask = _mm_cmplt_epi32(digits, char_a);
const __m128i addend = _mm_add_epi32(_mm_andnot_si128(mask, _mm_sub_epi32(char_a, _mm_set1_epi32(10))), _mm_and_si128(mask, char_0));
__m128i mask = _mm_and_si128(_mm_cmpgt_epi32(digits, char_befo_a), _mm_cmplt_epi32(digits, char_past_f));
__m128i offs = _mm_and_si128(mask, _mm_set1_epi32(Tr::FirstLetter - 10));
if constexpr (HasAltLetterEnum<Tr>::value) {
const __m128i char_befo_A = _mm_set1_epi32(g_AltLetterOrZero<Tr> - 1);
const __m128i char_past_F = _mm_set1_epi32(g_AltLetterOrZero<Tr> + Base - 10);
const __m128i alt_mask = _mm_and_si128(_mm_cmpgt_epi32(digits, char_befo_A), _mm_cmplt_epi32(digits, char_past_F));
const __m128i alt_offs = _mm_and_si128(alt_mask, _mm_set1_epi32(g_AltLetterOrZero<Tr> - 10));
offs = _mm_add_epi32(alt_offs, offs);
mask = _mm_or_si128(mask, alt_mask);
}
const __m128i addend = _mm_add_epi32(offs, _mm_andnot_si128(mask, char_0));
res = _mm_add_epi32(res, muly(_mm_sub_epi32(digits, addend), factor));
factor = muly(factor, _mm_set1_epi32(base4));
idx += 4;
@ -261,7 +281,7 @@ namespace dhandy {
{
res = _mm_add_epi32(res, _mm_srli_si128(res, 8));
res = _mm_add_epi32(res, _mm_srli_si128(res, 4));
const std::array<int, 4> scale {1, base1, base2, base3};
constexpr const std::array<int, 4> scale {1, base1, base2, base3};
return negated_ifn(to_integer_sse<T, C, Base, Tr>(s + idx, l - idx) + _mm_cvtsi128_si32(res) * scale[l - idx], was_negative);
}
}
@ -272,9 +292,9 @@ namespace dhandy {
template <typename C, C FDigit='0', C FLetter='a', C CPlus='+', C CMinus='-', C CNull='\0'>
struct ASCIITranslator {
typedef C char_type;
static const constexpr bool BehavesLikeASCII = true;
static const constexpr C FirstDigit = FDigit;
static const constexpr C FirstLetter = FLetter;
//static const constexpr C AltLetter = FAltLetter;
static const constexpr C Plus = CPlus;
static const constexpr C Minus = CMinus;
static const constexpr C NullChar = CNull;

View file

@ -29,6 +29,17 @@ template <typename T> using int_info_16 = dhandy::implem::int_info<T, 16>;
template <typename T> using int_info_2 = dhandy::implem::int_info<T, 2>;
namespace {
template <unsigned int Base>
struct ASCIITranslatorIns : public dhandy::ASCIITranslator<char> {
static const constexpr char AltLetter = 'A';
static constexpr int from_digit (char dig) {
if (dig >= FirstLetter and dig <= FirstLetter + Base - 10 - 1)
return dig - FirstLetter + 10;
else
return dig - AltLetter + 10;
}
};
template <typename T, unsigned int Base>
void AryConversionTestHelper (const std::string_view& s, T expected, bool expect_sse) {
using AryConversion = dhandy::implem::AryConversion<T, Base, dhandy::ASCIITranslator<char>, false>;
@ -42,6 +53,13 @@ namespace {
CHECK(AryConversion::is_sse == expect_sse);
CHECK(AryConversion::from_ary(s.data(), s.data() + s.size()) == expected);
}
template <typename T, unsigned int Base>
void AryConversionTestHelperIns (const std::string_view& s, T expected, bool expect_sse) {
using AryConversion = dhandy::implem::AryConversion<T, Base, ASCIITranslatorIns<Base>, false>;
CHECK(AryConversion::is_sse == expect_sse);
CHECK(AryConversion::from_ary(s.data(), s.data() + s.size()) == expected);
}
} //unnamed namespace
TEST_CASE ("Check int to char array conversions", "[s2i][int_conv]") {
@ -170,6 +188,15 @@ TEST_CASE ("Check char array to int conversions", "[i2s][int_conv]") {
AryConversionTestHelper<signed int, 10>("-50000", -50000, sizeof(signed int) <= sizeof(std::uint32_t));
AryConversionTestHelper<std::int64_t, 10>("-1", -1, false);
AryConversionTestHelper<std::int64_t, 10>("-510123123123", -510123123123, false);
//case insensitive SSE conversions
AryConversionTestHelperIns<std::int32_t, 16>("7FfFfFfF", 0x7fffffff, true);
AryConversionTestHelperIns<std::int32_t, 16>("AbCdEf01", 0xabcdef01, true);
AryConversionTestHelperIns<std::int32_t, 16>("aBcDeF01", 0xabcdef01, true);
AryConversionTestHelperIns<std::uint8_t, 16>("Ff", 0xff, true);
AryConversionTestHelperIns<std::int16_t, 16>("AfBe", 0xafbe, true);
AryConversionTestHelperIns<std::int32_t, 16>("aAb", 0xaab, true);
AryConversionTestHelperIns<std::int32_t, 16>("aAbBc", 0xaabbc, true);
}
TEST_CASE ("Check upcase/downcase int to array conversions", "[i2s][int_conv]") {
@ -195,3 +222,12 @@ TEST_CASE ("Check upcase/downcase int to array conversions", "[i2s][int_conv]")
constexpr auto int4 = int_conv<string_view>(integral_constant<short int, -256>{});
CHECK("-256" == int4);
}
TEST_CASE ("Try int conv with non-char", "[i2s][int_conv]") {
using dhandy::int_to_ary;
using dhandy::ASCIITranslator;
std::wstring_view exp1(L"235713");
auto val1 = int_to_ary<int, 10, ASCIITranslator<wchar_t>>(235713).to_string_view();
CHECK(exp1 == val1);
}