1
0
Fork 0
mirror of https://github.com/KingDuckZ/kamokan.git synced 2025-07-02 14:04:16 +00:00

Use the largest int type - it should do 8 chars at time on 64-bit.

This commit is contained in:
King_DuckZ 2017-06-19 19:54:06 +01:00
parent e649e9a196
commit 9c0734c31d

View file

@ -25,10 +25,26 @@
# include <algorithm> # include <algorithm>
#endif #endif
#include <climits> #include <climits>
#include <type_traits>
namespace tawashi { namespace tawashi {
namespace { namespace {
typedef uint_fast32_t uint;
#if !defined(HTML_ESCAPE_WITH_HOUDINI) #if !defined(HTML_ESCAPE_WITH_HOUDINI)
template <typename T>
[[gnu::pure]]
T count_bits_set (T parVal) {
static_assert(std::is_integral<T>::value and std::is_unsigned<T>::value, "Type T must be an unsigned int");
static_assert(sizeof(T) != sizeof(uint32_t), "The specialization should have been chosen");
auto& v = parVal;
v = v - ((v >> 1) & (T)~(T)0/3); // temp
v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3); // temp
v = (v + (v >> 4)) & (T)~(T)0/255*15; // temp
return (T)(v * ((T)~(T)0/255)) >> (sizeof(T) - 1) * CHAR_BIT; // count
}
template <>
[[gnu::pure]] [[gnu::pure]]
uint32_t count_bits_set (uint32_t parVal) { uint32_t count_bits_set (uint32_t parVal) {
auto& v = parVal; auto& v = parVal;
@ -39,35 +55,35 @@ namespace tawashi {
#endif #endif
#if !defined(HTML_ESCAPE_WITH_HOUDINI) #if !defined(HTML_ESCAPE_WITH_HOUDINI)
template <uint32_t I, char Haystack, char... HaystackRest> template <int I, char Haystack, char... HaystackRest>
struct find_impl { struct find_impl {
static uint32_t find (char parNeedle) { static int find (char parNeedle) {
return (Haystack == parNeedle ? return (Haystack == parNeedle ?
I : find_impl<I + 1, HaystackRest...>::find(parNeedle) I : find_impl<I + 1, HaystackRest...>::find(parNeedle)
); );
} }
}; };
template <uint32_t I, char Haystack> template <int I, char Haystack>
struct find_impl<I, Haystack> { struct find_impl<I, Haystack> {
static uint32_t find (char parNeedle) { static int find (char parNeedle) {
return (Haystack == parNeedle ? I : I + 1); return (Haystack == parNeedle ? I : I + 1);
} }
}; };
template <char... Haystack> template <char... Haystack>
[[gnu::pure,gnu::flatten]] [[gnu::pure,gnu::flatten]]
uint32_t find (char parNeedle) { int find (char parNeedle) {
return find_impl<0, Haystack...>::find(parNeedle); return find_impl<0, Haystack...>::find(parNeedle);
} }
#endif #endif
#if !defined(HTML_ESCAPE_WITH_HOUDINI) #if !defined(HTML_ESCAPE_WITH_HOUDINI)
template <char... Needle, std::size_t... Sizes> template <char... Needle, std::size_t... Sizes>
void slow_copy (const char* parSource, std::string& parDest, uint32_t parCount, const char (&...parWith)[Sizes]) { void slow_copy (const char* parSource, std::string& parDest, int parCount, const char (&...parWith)[Sizes]) {
std::array<const char*, sizeof...(Needle)> withs {parWith...}; std::array<const char*, sizeof...(Needle)> withs {parWith...};
std::array<uint32_t, sizeof...(Needle)> sizes {(static_cast<uint32_t>(Sizes) - 1)...}; std::array<uint16_t, sizeof...(Needle)> sizes {(static_cast<uint16_t>(Sizes) - 1)...};
for (uint32_t z = 0; z < parCount; ++z) { for (int z = 0; z < parCount; ++z) {
const uint32_t match_index = find<Needle...>(parSource[z]); const int match_index = find<Needle...>(parSource[z]);
if (sizeof...(Needle) > match_index) if (sizeof...(Needle) > match_index)
parDest.append(withs[match_index], sizes[match_index]); parDest.append(withs[match_index], sizes[match_index]);
else else
@ -78,7 +94,7 @@ namespace tawashi {
void expand (const char* parSource, std::string& parDest, P parWhich, const char (&...parWith)[Sizes]) { void expand (const char* parSource, std::string& parDest, P parWhich, const char (&...parWith)[Sizes]) {
static_assert(sizeof...(Needle) + 1 <= 0xFF, "Too many search chars, their indices won't fit in a byte"); static_assert(sizeof...(Needle) + 1 <= 0xFF, "Too many search chars, their indices won't fit in a byte");
std::array<const char*, sizeof...(Needle)> withs {parWith...}; std::array<const char*, sizeof...(Needle)> withs {parWith...};
std::array<uint32_t, sizeof...(Needle)> sizes {(static_cast<uint32_t>(Sizes) - 1)...}; std::array<uint16_t, sizeof...(Needle)> sizes {(static_cast<uint16_t>(Sizes) - 1)...};
for (unsigned int z = 0; z < sizeof(P) * CHAR_BIT; z += CHAR_BIT) { for (unsigned int z = 0; z < sizeof(P) * CHAR_BIT; z += CHAR_BIT) {
const auto curr = 0xFF bitand (parWhich >> z); const auto curr = 0xFF bitand (parWhich >> z);
@ -95,12 +111,12 @@ namespace tawashi {
std::string replace_with (const boost::string_view& parStr, const char (&...parWith)[Sizes]) { std::string replace_with (const boost::string_view& parStr, const char (&...parWith)[Sizes]) {
//Setup data //Setup data
static_assert(sizeof...(Needle) == sizeof...(Sizes), "Size mismatch"); static_assert(sizeof...(Needle) == sizeof...(Sizes), "Size mismatch");
const std::array<uint32_t, sizeof...(Needle)> packs = { const std::array<uint, sizeof...(Needle)> packs = {
(compl static_cast<uint32_t>(0) / 0xFF * Needle)... (compl static_cast<uint>(0) / 0xFF * Needle)...
}; };
const std::array<char, sizeof...(Needle)> needles = { Needle... }; const std::array<char, sizeof...(Needle)> needles = { Needle... };
const std::array<unsigned int, sizeof...(Needle)> sizes = { const std::array<uint16_t, sizeof...(Needle)> sizes = {
(static_cast<unsigned int>(Sizes) - 1)... (static_cast<uint16_t>(Sizes) - 1)...
}; };
//Calculate the new string's size //Calculate the new string's size
@ -121,18 +137,18 @@ namespace tawashi {
} }
assert(0 == (reinterpret_cast<uintptr_t>(parStr.data()) + pre_bytes) % alignof(decltype(packs[0])) or 0 == mid_bytes); assert(0 == (reinterpret_cast<uintptr_t>(parStr.data()) + pre_bytes) % alignof(decltype(packs[0])) or 0 == mid_bytes);
const uint32_t c1 = 0x01010101UL; const uint c1 = compl static_cast<uint>(0) / 0xFF * 0x01; //0x01010101UL;
const uint32_t c2 = 0x80808080UL; const uint c2 = compl static_cast<uint>(0) / 0xFF * 0x80; //0x80808080UL;
assert(inp_size >= pre_bytes + mid_bytes); assert(inp_size >= pre_bytes + mid_bytes);
const unsigned int post_bytes = inp_size - pre_bytes - mid_bytes; const unsigned int post_bytes = inp_size - pre_bytes - mid_bytes;
assert(post_bytes < alignof(decltype(packs[0]))); assert(post_bytes < alignof(decltype(packs[0])));
assert(post_bytes == (inp_size - pre_bytes) % alignof(decltype(packs[0]))); assert(post_bytes == (inp_size - pre_bytes) % alignof(decltype(packs[0])));
assert(inp_size == pre_bytes + mid_bytes + post_bytes); assert(inp_size == pre_bytes + mid_bytes + post_bytes);
for (unsigned int z = pre_bytes; z < inp_size - post_bytes; z += sizeof(packs[0])) { for (unsigned int z = pre_bytes; z < inp_size - post_bytes; z += sizeof(packs[0])) {
const uint32_t& val = *reinterpret_cast<const uint32_t*>(parStr.data() + z); const uint& val = *reinterpret_cast<const uint*>(parStr.data() + z);
for (unsigned int i = 0; i < sizeof...(Needle); ++i) { for (unsigned int i = 0; i < sizeof...(Needle); ++i) {
const uint32_t t = val xor packs[i]; const uint t = val xor packs[i];
const uint32_t has_zero = (t - c1) bitand compl t bitand c2; const uint has_zero = (t - c1) bitand compl t bitand c2;
new_size += (sizes[i] - 1) * count_bits_set(has_zero); new_size += (sizes[i] - 1) * count_bits_set(has_zero);
replace_count += count_bits_set(has_zero); replace_count += count_bits_set(has_zero);
} }
@ -155,12 +171,12 @@ namespace tawashi {
retval.reserve(new_size); retval.reserve(new_size);
slow_copy<Needle...>(parStr.data(), retval, pre_bytes, parWith...); slow_copy<Needle...>(parStr.data(), retval, pre_bytes, parWith...);
for (unsigned int z = pre_bytes; z < inp_size - post_bytes; z += sizeof(packs[0])) { for (unsigned int z = pre_bytes; z < inp_size - post_bytes; z += sizeof(packs[0])) {
const uint32_t& val = *reinterpret_cast<const uint32_t*>(parStr.data() + z); const uint& val = *reinterpret_cast<const uint*>(parStr.data() + z);
uint32_t escape_bytes = 0; uint escape_bytes = 0;
uint8_t char_index = 1; //indices are 1-based uint8_t char_index = 1; //indices are 1-based
for (uint32_t pack : packs) { for (uint pack : packs) {
const uint32_t t = val xor pack; const uint t = val xor pack;
const uint32_t placeholders = ((t - c1) bitand compl t bitand c2) >> 7; const uint placeholders = ((t - c1) bitand compl t bitand c2) >> 7;
assert((escape_bytes bitand (placeholders * 0xFF)) == 0); assert((escape_bytes bitand (placeholders * 0xFF)) == 0);
escape_bytes |= placeholders * char_index++; escape_bytes |= placeholders * char_index++;
} }