From f160f58e9099bd7d618d5d5d6aefe0c5ec963f85 Mon Sep 17 00:00:00 2001 From: Dnomd343 Date: Sat, 29 Jun 2024 09:23:42 +0800 Subject: [PATCH] update: several improvements of ShortCode --- src/core/benchmark/codec.cc | 18 +++++------ src/core/short_code/internal/offset/offset.h | 6 ++-- src/core/short_code/internal/serialize.cc | 30 +++++++++++-------- .../short_code/internal/serialize_chars.h | 23 ++++++++++---- src/core/short_code/internal/short_code.inl | 8 ++--- src/core/short_code/short_code.h | 11 ++++--- 6 files changed, 56 insertions(+), 40 deletions(-) diff --git a/src/core/benchmark/codec.cc b/src/core/benchmark/codec.cc index d98f508..b979f2f 100644 --- a/src/core/benchmark/codec.cc +++ b/src/core/benchmark/codec.cc @@ -166,7 +166,7 @@ static void ShortCodeSerialize(benchmark::State &state) { for (auto _ : state) { for (const auto code : samples) { - volatile auto ret = klotski::codec::ShortCode::string_encode(code); + volatile auto ret = ShortCode::string_encode(code); } } @@ -185,7 +185,7 @@ static void ShortCodeDeserialize(benchmark::State &state) { for (const auto code : samples) { - volatile auto ret = klotski::codec::ShortCode::string_decode(code); + volatile auto ret = ShortCode::string_decode(code); } @@ -197,8 +197,8 @@ static void ShortCodeDeserialize(benchmark::State &state) { static void ShortCodeToCommonCode(benchmark::State &state) { - ShortCode::speed_up(true); - // ShortCode::speed_up(false); + // ShortCode::speed_up(true); + ShortCode::speed_up(false); // ShortCode::fast_decode(4091296); @@ -221,8 +221,8 @@ static void ShortCodeToCommonCode(benchmark::State &state) { } static void CommonCodeToShortCode(benchmark::State &state) { - ShortCode::speed_up(true); - // ShortCode::speed_up(false); + // ShortCode::speed_up(true); + ShortCode::speed_up(false); auto common_code = CommonCode::unsafe_create(0x1A9BF0C00); @@ -248,11 +248,11 @@ static void CommonCodeToShortCode(benchmark::State &state) { // BENCHMARK(CommonCodeSerializeShorten)->Range(8, 256); // BENCHMARK(CommonCodeDeserializeShorten)->Range(8, 256); -// BENCHMARK(ShortCodeSerialize)->Range(8, 256); -// BENCHMARK(ShortCodeDeserialize)->Range(8, 256); +BENCHMARK(ShortCodeSerialize)->Range(8, 256); +BENCHMARK(ShortCodeDeserialize)->Range(8, 256); // BENCHMARK(ShortCodeToCommonCode); -BENCHMARK(CommonCodeToShortCode); +// BENCHMARK(CommonCodeToShortCode); // static void CommonCodeDecode(benchmark::State &state) { // const auto tmp = str_common_codes(state.range(0)); diff --git a/src/core/short_code/internal/offset/offset.h b/src/core/short_code/internal/offset/offset.h index 85c7f6a..3e3848e 100644 --- a/src/core/short_code/internal/offset/offset.h +++ b/src/core/short_code/internal/offset/offset.h @@ -6,9 +6,9 @@ namespace klotski::codec { -/// This is the index for basic ranges, and its position (0 ~ 7311884) in all -/// basic ranges is located according to the first 12-bit (0 ~ 4095) within the -/// 32-bit `range`. +/// This is the offset index of basic ranges, and its position (0 ~ 7311884) in +/// all basic ranges is located according to the first 12-bit (0 ~ 4095) within +/// the 32-bit `range` value. constexpr auto RANGES_GLOBAL_OFFSET = std::to_array({ #include "constant/offset.inc" diff --git a/src/core/short_code/internal/serialize.cc b/src/core/short_code/internal/serialize.cc index 386f6d8..5a666c2 100644 --- a/src/core/short_code/internal/serialize.cc +++ b/src/core/short_code/internal/serialize.cc @@ -1,34 +1,38 @@ +#include + #include "serialize_chars.h" #include "short_code/short_code.h" using klotski::codec::ShortCode; +using klotski::cases::ALL_CASES_NUM_; std::string ShortCode::string_encode(uint32_t short_code) { - char result[5]; - for (int n = 0; n < 5; ++n) { - result[4 - n] = SHORT_CODE_TABLE[short_code & 0b11111]; + KLSK_ASSUME(short_code < ALL_CASES_NUM_); + std::array arr {}; + for (auto &c : arr | std::views::reverse) { + c = SHORT_CODE_TABLE[short_code & 0b11111]; // table convert short_code >>= 5; } - return {result, result + 5}; + return {arr.begin(), arr.end()}; } std::optional ShortCode::string_decode(const std::string_view short_code) { if (short_code.length() != 5) { return std::nullopt; // invalid string length } - uint32_t result = 0; - for (auto bit : short_code) { - if (bit < '1' || bit > 'z') { // invalid characters + uint32_t code = 0; + for (const uint8_t bit : short_code) { + if (bit > 'z') { // invalid characters return std::nullopt; } - result <<= 5; - result += (bit = SHORT_CODE_TABLE_REV[bit - 49]); // table convert - if (bit == -1) { // invalid character - return std::nullopt; + if (const auto val = SHORT_CODE_TABLE_REV[bit]; val != -1) { + (code <<= 5) += val; + continue; } + return std::nullopt; // invalid character } - if (!check(result)) { // check converted short code + if (!check(code)) { // check converted short code return std::nullopt; } - return result; // apply convert result + return code; // apply convert result } diff --git a/src/core/short_code/internal/serialize_chars.h b/src/core/short_code/internal/serialize_chars.h index fce6ca6..4ee3183 100644 --- a/src/core/short_code/internal/serialize_chars.h +++ b/src/core/short_code/internal/serialize_chars.h @@ -1,5 +1,3 @@ -#pragma once - /// ShortCode Convert Table /// /// ------------------------------------------------- /// /// | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | /// @@ -15,17 +13,28 @@ /// | `S` | `T` | `U` | `V` | `W` | `X` | `Y` | `Z` | /// /// ------------------------------------------------- /// +#pragma once + +#include + namespace klotski::codec { -constexpr char SHORT_CODE_TABLE[32] { +constexpr auto SHORT_CODE_TABLE = std::to_array({ '1', '2', '3', '4', '5', '6', '7', '8', '9', // skip `0` 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // skip `I` 'J', 'K', // skip `L` 'M', 'N', // skip `O` 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', -}; +}); + +static_assert(SHORT_CODE_TABLE.size() == 32); -constexpr char SHORT_CODE_TABLE_REV[74] { +constexpr auto SHORT_CODE_TABLE_REV = std::to_array({ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // | [0, 9] + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // | [10, 19] + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // | [20, 29] + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // | [30, 39] + -1, -1, -1, -1, -1, -1, -1, -1, -1, // | [40, 48] 0, 1, 2, 3, 4, 5, 6, 7, 8, // `1` ~ `9` | [49, 57] -1, -1, -1, -1, -1, -1, -1, // | [58, 64] 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, // `A` ~ `J` | [65, 74] @@ -35,6 +44,8 @@ constexpr char SHORT_CODE_TABLE_REV[74] { 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, // `a` ~ `j` | [97, 106] 18, -1, 19, 20, -1, 21, 22, 23, 24, 25, // `k` ~ `t` | [107, 116] 26, 27, 28, 29, 30, 31, // `u` ~ `z` | [117, 122] -}; +}); + +static_assert(SHORT_CODE_TABLE_REV.size() == 'z' + 1); } // namespace klotski::codec diff --git a/src/core/short_code/internal/short_code.inl b/src/core/short_code/internal/short_code.inl index e3d2714..c0b031b 100644 --- a/src/core/short_code/internal/short_code.inl +++ b/src/core/short_code/internal/short_code.inl @@ -1,12 +1,10 @@ #pragma once -#include - #include "common_code/common_code.h" namespace klotski::codec { -// ------------------------------------------------------------------------------------- // +// ----------------------------------------------------------------------------------------- // inline ShortCode::ShortCode(const CommonCode common_code) { if (fast_) { @@ -27,7 +25,7 @@ inline std::optional ShortCode::create(const uint32_t short_code) { return unsafe_create(short_code); } -// ------------------------------------------------------------------------------------- // +// ----------------------------------------------------------------------------------------- // inline ShortCode::operator uint32_t() const { return code_; @@ -97,7 +95,7 @@ inline std::optional ShortCode::from_common_code(const std::string_vi return CommonCode::from_string(common_code).transform(convert); } -// ------------------------------------------------------------------------------------- // +// ----------------------------------------------------------------------------------------- // constexpr auto operator==(const ShortCode &lhs, const uint32_t rhs) { return lhs.code_ == rhs; diff --git a/src/core/short_code/short_code.h b/src/core/short_code/short_code.h index 39834fd..5b226f5 100644 --- a/src/core/short_code/short_code.h +++ b/src/core/short_code/short_code.h @@ -1,7 +1,7 @@ /// Klotski Engine by Dnomd343 @2024 /// ShortCode is a high-compression encoding scheme based on CommonCode. Since -/// there are a total of 29334498 valid klotski cases, arrange then from small +/// there are a total of 29334498 valid klotski cases, arrange them from small /// to large by their CommonCodes (36-bit positive integers), and use the index /// as the ShortCode. @@ -160,7 +160,7 @@ private: static KLSK_INLINE uint64_t fast_decode(uint32_t short_code); /// Convert CommonCode to ShortCode based on AllCases data. - static uint32_t fast_encode(uint64_t common_code); + static KLSK_INLINE uint32_t fast_encode(uint64_t common_code); /// Convert ShortCode to CommonCode based on BasicRanges data. static uint64_t tiny_decode(uint32_t short_code); @@ -171,10 +171,10 @@ private: // ------------------------------------------------------------------------------------- // /// Serialize ShortCode into 5-bit length string. - static std::string string_encode(uint32_t short_code); + static KLSK_INLINE std::string string_encode(uint32_t short_code); /// Deserialize ShortCode from string and return nullopt on error. - static std::optional string_decode(std::string_view short_code); + static KLSK_INLINE std::optional string_decode(std::string_view short_code); // ------------------------------------------------------------------------------------- // @@ -193,6 +193,9 @@ private: // ------------------------------------------------------------------------------------- // }; +static_assert(std::is_standard_layout_v); +static_assert(std::is_trivially_copyable_v); + } // namespace klotski::codec #include "internal/short_code.inl"