diff --git a/src/core/benchmark/codec.cc b/src/core/benchmark/codec.cc index 8feff16..c769783 100644 --- a/src/core/benchmark/codec.cc +++ b/src/core/benchmark/codec.cc @@ -261,14 +261,14 @@ static void IsMirrorCompare(benchmark::State &state) { } // BENCHMARK(CommonCodeSerialize)->Range(8, 256); -// BENCHMARK(CommonCodeDeserialize)->Range(8, 256); +BENCHMARK(CommonCodeDeserialize)->Range(8, 256); // BENCHMARK(CommonCodeSerializeShorten)->Range(8, 256); // BENCHMARK(CommonCodeDeserializeShorten)->Range(8, 256); // BENCHMARK(ShortCodeSerialize)->Range(8, 256); // BENCHMARK(ShortCodeDeserialize)->Range(8, 256); -BENCHMARK(IsMirrorCompare); +// BENCHMARK(IsMirrorCompare); // BENCHMARK(ShortCodeToCommonCode); // BENCHMARK(CommonCodeToShortCode); diff --git a/src/core/common_code/internal/serialize.cc b/src/core/common_code/internal/serialize.cc index ab53641..63315b1 100644 --- a/src/core/common_code/internal/serialize.cc +++ b/src/core/common_code/internal/serialize.cc @@ -4,13 +4,55 @@ namespace klotski::codec { /// Convert a single hexadecimal digit to a character. static char to_hex_char(const uint64_t hex_bit) { - [[assume(hex_bit < 0x10)]]; + KLSK_ASSUME(hex_bit < 0x10); if (hex_bit < 0xA) { return static_cast(hex_bit + '0'); } return static_cast(hex_bit + 'A' - 10); } +constexpr auto CONVERT_TABLE = std::to_array({ + /// -1 * 48 + -1, -1, -1, -1, -1, -1, // [0, 5] + -1, -1, -1, -1, -1, -1, -1, // [6, 12] + -1, -1, -1, -1, -1, -1, -1, // [13, 19] + -1, -1, -1, -1, -1, -1, -1, // [20, 26] + -1, -1, -1, -1, -1, -1, -1, // [27, 33] + -1, -1, -1, -1, -1, -1, -1, // [34, 40] + -1, -1, -1, -1, -1, -1, -1, // [41, 47] + + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, // [48, 57] + + /// -1 * 7 + -1, -1, -1, -1, -1, -1, -1, // [58, 64] + + 10, 11, 12, 13, 14, 15, // [65, 70] + + /// -1 * 26 + -1, -1, -1, -1, -1, -1, -1, // [71, 77] + -1, -1, -1, -1, -1, -1, -1, // [78, 84] + -1, -1, -1, -1, -1, -1, -1, // [85, 91] + -1, -1, -1, -1, -1, // [92, 96] + + 10, 11, 12, 13, 14, 15, // [97, 102] + + /// -1 * 25 + -1, -1, -1, -1, -1, -1, -1, // [103, 109] + -1, -1, -1, -1, -1, -1, -1, // [110, 116] + -1, -1, -1, -1, -1, -1, -1, // [117, 123] + -1, -1, -1, -1, // [124, 127] + + /// -1 * 128 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}); + std::string CommonCode::string_encode(uint64_t common_code) { char code_str[9]; for (int i = 0; i < 9; ++i) { @@ -29,25 +71,19 @@ std::string CommonCode::string_encode_shorten(const uint64_t common_code) { return code; } -// TODO: direct table lookup can bring about a 30% improvement, -// TODO: but it is necessary to confirm the performance of different CPU caches. std::optional CommonCode::string_decode(const std::string_view common_code) { if (common_code.length() > 9 || common_code.empty()) { return std::nullopt; // invalid string length } - uint64_t result = 0; - for (const auto hex_bit : common_code) { - if (hex_bit >= '0' && hex_bit <= '9') { // 0 ~ 9 - (result <<= 4) |= (hex_bit - '0'); - } else if (hex_bit >= 'A' && hex_bit <= 'F') { // A ~ F - (result <<= 4) |= (hex_bit - 'A' + 10); - } else if (hex_bit >= 'a' && hex_bit <= 'f') { // a ~ f - (result <<= 4) |= (hex_bit - 'a' + 10); - } else { - return std::nullopt; // invalid character + uint64_t code = 0; + for (const uint8_t hex_bit : common_code) { + const auto val = CONVERT_TABLE[hex_bit]; // table convert + if (val == -1) { + return std::nullopt; } + (code <<= 4) |= val; } - return result << (36 - common_code.length() * 4); // low-bits fill with zero + return code << (36 - common_code.length() * 4); // low-bits fill with zero } } // namespace klotski::codec