| e8555c89 Andy McCall |
1 |
#ifndef SMALL_COMPARE_HH |
| 2 |
#define SMALL_COMPARE_HH |
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
|
| 14 |
|
| 15 |
|
| 16 |
|
| 17 |
|
| 18 |
|
| 19 |
|
| 20 |
|
| 21 |
|
| 22 |
|
| 23 |
|
| 24 |
|
| 25 |
|
| 26 |
|
| 27 |
|
| 28 |
|
| 29 |
|
| 30 |
|
| 31 |
|
| 32 |
|
| 33 |
|
| 34 |
|
| 35 |
|
| 36 |
|
| 37 |
|
| 38 |
|
| 39 |
#include "aligned.hh" |
| 40 |
#include "endian.hh" |
| 41 |
|
| 42 |
#include <algorithm> |
| 43 |
#include <array> |
| 44 |
#include <bit> |
| 45 |
#include <cassert> |
| 46 |
#include <cstdint> |
| 47 |
#include <cstring> |
| 48 |
#include <string_view> |
| 49 |
#include <type_traits> |
| 50 |
|
| 51 |
|
| 52 |
|
| 53 |
template<size_t N> struct StringLiteral { |
| 54 |
constexpr StringLiteral(const char (&str)[N]) |
| 55 |
{ |
| 56 |
assert(str[N - 1] == '\0'); |
| 57 |
std::copy_n(str, N - 1, value.data()); |
| 58 |
} |
| 59 |
|
| 60 |
[[nodiscard]] constexpr size_t size() const { return value.size(); } |
| 61 |
[[nodiscard]] constexpr const char* data() const { return value.data(); } |
| 62 |
|
| 63 |
std::array<char, N - 1> value; |
| 64 |
}; |
| 65 |
|
| 66 |
namespace detail { |
| 67 |
|
| 68 |
|
| 69 |
struct Load8 { |
| 70 |
using type = uint8_t; |
| 71 |
[[nodiscard]] type operator()(const void* p) const { return *std::bit_cast<const uint8_t*>(p); } |
| 72 |
}; |
| 73 |
struct Load16 { |
| 74 |
using type = uint16_t; |
| 75 |
[[nodiscard]] type operator()(const void* p) const { return unalignedLoad16(p); } |
| 76 |
}; |
| 77 |
struct Load32 { |
| 78 |
using type = uint32_t; |
| 79 |
[[nodiscard]] type operator()(const void* p) const { return unalignedLoad32(p); } |
| 80 |
}; |
| 81 |
struct Load64 { |
| 82 |
using type = uint64_t; |
| 83 |
[[nodiscard]] type operator()(const void* p) const { return unalignedLoad64(p); } |
| 84 |
}; |
| 85 |
struct ErrorNotSupportedLoader; |
| 86 |
template<size_t N> struct SelectLoader |
| 87 |
: std::conditional_t<N <= 1, Load8, |
| 88 |
std::conditional_t<N <= 2, Load16, |
| 89 |
std::conditional_t<N <= 4, Load32, |
| 90 |
std::conditional_t<N <= 8, Load64, |
| 91 |
ErrorNotSupportedLoader>>>> {}; |
| 92 |
|
| 93 |
|
| 94 |
template<typename T> constexpr std::pair<T, T> calcValueMask(auto str) |
| 95 |
{ |
| 96 |
T v = 0; |
| 97 |
T m = 0; |
| 98 |
int s = Endian::LITTLE ? 0 : (8 * (sizeof(T) - 1)); |
| 99 |
for (size_t i = 0; i < str.size(); ++i) { |
| 100 |
v = T(v + (T(str.data()[i]) << s)); |
| 101 |
m = T(m + (T(255) << s)); |
| 102 |
s += Endian::LITTLE ? 8 : -8; |
| 103 |
} |
| 104 |
return {v, m}; |
| 105 |
} |
| 106 |
|
| 107 |
} |
| 108 |
|
| 109 |
template<StringLiteral Literal> |
| 110 |
[[nodiscard]] bool small_compare(const char* p) |
| 111 |
{ |
| 112 |
using Loader = detail::SelectLoader<Literal.size()>; |
| 113 |
using Type = typename Loader::type; |
| 114 |
static constexpr auto vm = detail::calcValueMask<Type>(Literal); |
| 115 |
auto [value, mask] = vm; |
| 116 |
|
| 117 |
Loader loader; |
| 118 |
return (loader(p) & mask) == value; |
| 119 |
} |
| 120 |
|
| 121 |
template<StringLiteral Literal> |
| 122 |
[[nodiscard]] bool small_compare(std::string_view str) |
| 123 |
{ |
| 124 |
if (str.size() != Literal.size()) return false; |
| 125 |
return small_compare<Literal>(str.data()); |
| 126 |
} |
| 127 |
|
| 128 |
#endif |