Browse Source

update: enhance ShortCode module

legacy
Dnomd343 2 years ago
parent
commit
1b11684726
  1. 12
      src/klotski_core/short_code/convert.cc
  2. 6
      src/klotski_core/short_code/serialize.cc
  3. 27
      src/klotski_core/short_code/serialize_chars.h
  4. 76
      src/klotski_core/short_code/short_code.cc
  5. 74
      src/klotski_core/short_code/short_code.h

12
src/klotski_core/short_code/convert.cc

@ -12,26 +12,26 @@ using klotski::CommonCode;
CommonCode ShortCode::to_common_code() const noexcept { CommonCode ShortCode::to_common_code() const noexcept {
if (ShortCode::mode() == ShortCode::NORMAL) { if (ShortCode::mode() == ShortCode::NORMAL) {
return CommonCode::unsafe_create(tiny_decode(code)); // normal mode return CommonCode::unsafe_create(tiny_decode(code_)); // normal mode
} }
return CommonCode::unsafe_create(fast_decode(code)); // fast mode return CommonCode::unsafe_create(fast_decode(code_)); // fast mode
} }
/// ------------------------- ShortCode to CommonCode ------------------------- /// ------------------------- ShortCode to CommonCode -------------------------
ShortCode::ShortCode(CommonCode &&common_code) noexcept { ShortCode::ShortCode(CommonCode &&common_code) noexcept {
if (ShortCode::mode() == ShortCode::NORMAL) { if (ShortCode::mode() == ShortCode::NORMAL) {
code = tiny_encode(common_code.unwrap()); // normal mode code_ = tiny_encode(common_code.unwrap()); // normal mode
} else { } else {
code = fast_encode(common_code.unwrap()); // fast mode code_ = fast_encode(common_code.unwrap()); // fast mode
} }
} }
ShortCode::ShortCode(const CommonCode &common_code) noexcept { ShortCode::ShortCode(const CommonCode &common_code) noexcept {
if (ShortCode::mode() == ShortCode::NORMAL) { if (ShortCode::mode() == ShortCode::NORMAL) {
code = tiny_encode(common_code.unwrap()); // normal mode code_ = tiny_encode(common_code.unwrap()); // normal mode
} else { } else {
code = fast_encode(common_code.unwrap()); // fast mode code_ = fast_encode(common_code.unwrap()); // fast mode
} }
} }

6
src/klotski_core/short_code/serialize.cc

@ -7,17 +7,17 @@ using klotski::ShortCodeException;
/// --------------------------- ShortCode to String --------------------------- /// --------------------------- ShortCode to String ---------------------------
std::string ShortCode::to_string() const noexcept { // encode as 5-bits string std::string ShortCode::to_string() const noexcept { // encode as 5-bits string
return string_encode(code); return string_encode(code_);
} }
/// --------------------------- String to ShortCode --------------------------- /// --------------------------- String to ShortCode ---------------------------
ShortCode::ShortCode(std::string &&short_code) { ShortCode::ShortCode(std::string &&short_code) {
code = string_decode(short_code); code_ = string_decode(short_code);
} }
ShortCode::ShortCode(const std::string &short_code) { ShortCode::ShortCode(const std::string &short_code) {
code = string_decode(short_code); code_ = string_decode(short_code);
} }
ShortCode ShortCode::from_string(std::string &&short_code) { ShortCode ShortCode::from_string(std::string &&short_code) {

27
src/klotski_core/short_code/serialize_chars.h

@ -1,22 +1,39 @@
#pragma once #pragma once
/// ShortCode Convert Table
/// -------------------------------------------------
/// | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 |
/// | `1` | `2` | `3` | `4` | `5` | `6` | `7` | `8` |
/// |-----------------------------------------------|
/// | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 |
/// | `9` | `A` | `B` | `C` | `D` | `E` | `F` | `G` |
/// |-----------------------------------------------|
/// | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
/// | `H` | `J` | `K` | `M` | `N` | `P` | `Q` | `R` |
/// |-----------------------------------------------|
/// | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
/// | `S` | `T` | `U` | `V` | `W` | `X` | `Y` | `Z` |
/// -------------------------------------------------
#include <cstdint> #include <cstdint>
namespace klotski { namespace klotski {
const int8_t SHORT_CODE_TABLE[32] = {
const int8_t SHORT_CODE_TABLE[32] = {
'1', '2', '3', '4', '5', '6', '7', '8', '9', // skip `0` '1', '2', '3', '4', '5', '6', '7', '8', '9', // skip `0`
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // skip `I` 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // skip `I`
'J', 'K', // skip `L` 'J', 'K', // skip `L`
'M', 'N', // skip `O` 'M', 'N', // skip `O`
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
}; };
/// `1`(49) ~ `Z`(90) /// `1`(49) ~ `Z`(90)
const int8_t SHORT_CODE_TABLE_REV[42] = { const int8_t SHORT_CODE_TABLE_REV[42] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, // `1`(49) ~ `9`(57) 0, 1, 2, 3, 4, 5, 6, 7, 8, // `1`(49) ~ `9`(57)
-1, -1, -1, -1, -1, -1, -1, // `:`(58) ~ `@`(64) -1, -1, -1, -1, -1, -1, -1, // `:`(58) ~ `@`(64)
9, 10, 11, 12, 13, 14, 15, 16, -1, 17, // `A`(65) ~ `J`(74) 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, // `A`(65) ~ `J`(74)
18, -1, 19, 20, -1, 21, 22, 23, 24, 25, // `K`(75) ~ `T`(84) 18, -1, 19, 20, -1, 21, 22, 23, 24, 25, // `K`(75) ~ `T`(84)
26, 27, 28, 29, 30, 31, // `U`(85) ~ `Z`(90) 26, 27, 28, 29, 30, 31, // `U`(85) ~ `Z`(90)
}; };
} }

76
src/klotski_core/short_code/short_code.cc

@ -1,63 +1,35 @@
#include "all_cases.h" #include "all_cases.h"
#include "short_code.h" #include "short_code.h"
using klotski::ShortCode;
bool ShortCode::fast_mode_available = false;
bool ShortCode::normal_mode_available = false;
namespace std {
template<>
struct hash<klotski::ShortCode> {
std::size_t operator()(const klotski::ShortCode &c) const {
return std::hash<uint64_t>()(c.unwrap());
}
};
template<>
struct equal_to<klotski::ShortCode> {
bool operator()(const klotski::ShortCode &c1, const klotski::ShortCode &c2) const {
return c1.unwrap() == c2.unwrap();
}
};
}
namespace klotski { namespace klotski {
bool ShortCode::operator==(const ShortCode &short_code) const noexcept {
return this->code == short_code.code;
}
bool ShortCode::operator!=(const ShortCode &short_code) const noexcept { bool ShortCode::fast_mode_available_ = false;
return this->code != short_code.code; bool ShortCode::normal_mode_available_ = false;
}
std::ostream& operator<<(std::ostream &out, const ShortCode &self) { bool ShortCode::valid() const noexcept {
out << self.to_string() << "(" << self.code << ")"; // short code info return ShortCode::check(code_);
return out;
}
} }
namespace klotski { ShortCode ShortCode::create(uint32_t short_code) {
bool ShortCode::valid() const noexcept {
return ShortCode::check(code);
}
ShortCode ShortCode::create(uint32_t short_code) {
return ShortCode(short_code); return ShortCode(short_code);
} }
ShortCode ShortCode::unsafe_create(uint32_t short_code) noexcept { // create without check ShortCode ShortCode::unsafe_create(uint32_t short_code) noexcept { // create without check
auto tmp = ShortCode(); // init directly auto tmp = ShortCode(); // init directly
tmp.code = short_code; tmp.code_ = short_code;
return tmp; return tmp;
} }
ShortCode::ShortCode(uint32_t short_code) { ShortCode::ShortCode(uint32_t short_code) {
if (!ShortCode::check(short_code)) { // check input short code if (!ShortCode::check(short_code)) { // check input short code
throw klotski::ShortCodeException("short code invalid"); throw klotski::ShortCodeException("short code invalid");
} }
code = short_code; code_ = short_code;
} }
std::ostream& operator<<(std::ostream &out, const ShortCode &self) {
out << self.to_string() << "(" << self.code_ << ")"; // short code info
return out;
} }
bool ShortCode::check(uint32_t short_code) noexcept { bool ShortCode::check(uint32_t short_code) noexcept {
@ -65,25 +37,27 @@ bool ShortCode::check(uint32_t short_code) noexcept {
} }
ShortCode::Mode ShortCode::mode() { // ensure speed up enabled and return current mode ShortCode::Mode ShortCode::mode() { // ensure speed up enabled and return current mode
if (fast_mode_available) { if (fast_mode_available_) {
return ShortCode::FAST; // fast mode already enabled return ShortCode::FAST; // fast mode already enabled
} }
if (normal_mode_available) { if (normal_mode_available_) {
return ShortCode::NORMAL; // normal mode already enabled return ShortCode::NORMAL; // normal mode already enabled
} }
speed_up(ShortCode::Mode::NORMAL); // uninitialized -> enable normal mode speed_up(ShortCode::Mode::NORMAL); // uninitialized -> enable normal mode
return ShortCode::Mode::NORMAL; // normal mode enabled return ShortCode::Mode::NORMAL;
} }
void ShortCode::speed_up(ShortCode::Mode mode) { void ShortCode::speed_up(ShortCode::Mode mode) {
if (fast_mode_available) { if (fast_mode_available_) {
return; // fast mode already available return; // fast mode already available
} }
if (mode == ShortCode::FAST) { // build fast mode data if (mode == ShortCode::FAST) { // build fast mode data
AllCases::build(); // blocking function AllCases::build(); // blocking function
fast_mode_available = true; fast_mode_available_ = true;
} else if (!normal_mode_available) { // build normal mode data } else if (!normal_mode_available_) { // build normal mode data
BasicRanges::build(); // blocking function BasicRanges::build(); // blocking function
normal_mode_available = true; normal_mode_available_ = true;
} }
} }
} // namespace klotski

74
src/klotski_core/short_code/short_code.h

@ -2,7 +2,7 @@
/// ShortCode is a high-compression encoding scheme based on CommonCode. Since there /// ShortCode is a high-compression encoding scheme based on CommonCode. Since there
/// are a total of 29334498 valid klotski layouts, arrange their CommonCodes from /// are a total of 29334498 valid klotski layouts, arrange their CommonCodes from
/// small to large (36-bits positive integers), and use the index as the ShortCode. /// small to large (36-bit positive integers), and use the index as the ShortCode.
/// Therefore, the valid value of ShortCode is [0, 29334498), stored in `uint32_t`. /// Therefore, the valid value of ShortCode is [0, 29334498), stored in `uint32_t`.
/// The goal of high compression ratio is to facilitate verbal sharing, so it is /// The goal of high compression ratio is to facilitate verbal sharing, so it is
@ -11,21 +11,21 @@
/// and 26 characters, forming a private base32 scheme. /// and 26 characters, forming a private base32 scheme.
/// Coincidentally, log(32, 29334498) is approximately equal to `4.96`, so using /// Coincidentally, log(32, 29334498) is approximately equal to `4.96`, so using
/// 5-bits base32 can make good use of space, so any valid klotski layout can be /// 5-bit base32 can make good use of space, so any valid klotski layout can be
/// represented by a 5-bits length code. As in CommonCode, the characters here are /// represented by a 5-bit length code. As in CommonCode, the characters here are
/// case insensitive, but uppercase is still recommended. /// case insensitive, but uppercase is still recommended.
/// ShortCode Convert Table /// ShortCode Convert Table
/// ------------------------------------------------- /// -------------------------------------------------
/// | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | /// | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 |
/// | `1` | `2` | `3` | `4` | `5` | `6` | `7` | `8` | /// | `1` | `2` | `3` | `4` | `5` | `6` | `7` | `8` |
/// ------------------------------------------------- /// |-----------------------------------------------|
/// | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | /// | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 |
/// | `9` | `A` | `B` | `C` | `D` | `E` | `F` | `G` | /// | `9` | `A` | `B` | `C` | `D` | `E` | `F` | `G` |
/// ------------------------------------------------- /// |-----------------------------------------------|
/// | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | /// | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
/// | `H` | `J` | `K` | `M` | `N` | `P` | `Q` | `R` | /// | `H` | `J` | `K` | `M` | `N` | `P` | `Q` | `R` |
/// ------------------------------------------------- /// |-----------------------------------------------|
/// | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | /// | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 |
/// | `S` | `T` | `U` | `V` | `W` | `X` | `Y` | `Z` | /// | `S` | `T` | `U` | `V` | `W` | `X` | `Y` | `Z` |
/// ------------------------------------------------- /// -------------------------------------------------
@ -51,61 +51,66 @@
#include <string> #include <string>
#include <cstdint> #include <cstdint>
#include <ostream> #include <ostream>
#include <stdexcept>
#include <utility> #include <utility>
#include <stdexcept>
#include "all_cases.h" #include "all_cases.h"
#include "common_code.h" #include "common_code.h"
namespace klotski { namespace klotski {
class CommonCode; // import for convert interface
const uint32_t SHORT_CODE_LIMIT = klotski::ALL_CASES_SIZE_SUM; class CommonCode;
const uint32_t SHORT_CODE_LIMIT = klotski::ALL_CASES_SIZE_SUM;
class ShortCodeException : public std::runtime_error { class ShortCodeException : public std::runtime_error {
public: public:
ShortCodeException() : std::runtime_error("invalid short code") {} ShortCodeException() : std::runtime_error("invalid short code") {}
explicit ShortCodeException(const std::string &msg) : std::runtime_error(msg) {} explicit ShortCodeException(const std::string &msg) : std::runtime_error(msg) {}
~ShortCodeException() noexcept override = default; ~ShortCodeException() noexcept override = default;
}; };
class ShortCode { /// For ShortCode, you must choose at least one mode (NORMAL or FAST) to convert, and
public: /// they all need a certain amount of time to warm up. `NORMAL` warms up quickly, and
/// `FAST` is slower, but the conversion speed of `FAST` is much faster than `NORMAL`.
/// When only converting a small amount of codes, please choose NORMAL mode. Otherwise
/// FAST mode should be used.
class ShortCode {
public:
enum Mode {NORMAL, FAST}; enum Mode {NORMAL, FAST};
private: private:
uint32_t code; uint32_t code_;
ShortCode() = default; // unsafe initialize ShortCode() = default; // unsafe initialize
static Mode mode(); static Mode mode();
static bool fast_mode_available; static bool fast_mode_available_;
static bool normal_mode_available; static bool normal_mode_available_;
static inline uint64_t fast_decode(uint32_t short_code) noexcept; // short code -> common code static inline uint64_t fast_decode(uint32_t short_code) noexcept; // short code -> common code
static inline uint32_t fast_encode(uint64_t common_code) noexcept; // common code -> short code static inline uint32_t fast_encode(uint64_t common_code) noexcept; // common code -> short code
static inline uint64_t tiny_decode(uint32_t short_code) noexcept; // short code -> common code static inline uint64_t tiny_decode(uint32_t short_code) noexcept; // short code -> common code
static inline uint32_t tiny_encode(uint64_t common_code) noexcept; // common code -> short code static inline uint32_t tiny_encode(uint64_t common_code) noexcept; // common code -> short code
static inline std::string string_encode(uint32_t short_code) noexcept; // short code -> string static inline uint32_t string_decode(const std::string &short_code);
static inline uint32_t string_decode(const std::string &short_code); // string -> short code static inline std::string string_encode(uint32_t short_code) noexcept;
public: public:
/// ShortCode validity check /// Validity check
bool valid() const noexcept; bool valid() const noexcept;
static bool check(uint32_t short_code) noexcept; static bool check(uint32_t short_code) noexcept;
/// ShortCode convert mode /// ShortCode convert mode
static void speed_up(Mode mode); static void speed_up(Mode mode); // {} -> {NORMAL} -> {FAST}
/// Operators of ShortCode /// Operators of ShortCode
bool operator==(const ShortCode &short_code) const noexcept; constexpr explicit operator uint32_t() const noexcept { return code_; }
bool operator!=(const ShortCode &short_code) const noexcept;
constexpr explicit operator uint32_t() const noexcept { return code; }
friend std::ostream& operator<<(std::ostream &out, const ShortCode &self); friend std::ostream& operator<<(std::ostream &out, const ShortCode &self);
/// Export functions /// Export functions
std::string to_string() const noexcept; std::string to_string() const noexcept;
CommonCode to_common_code() const noexcept; CommonCode to_common_code() const noexcept;
constexpr uint32_t unwrap() const noexcept { return code; } constexpr uint32_t unwrap() const noexcept { return code_; }
/// ShortCode constructors /// ShortCode constructors
explicit ShortCode(uint32_t short_code); explicit ShortCode(uint32_t short_code);
@ -126,10 +131,13 @@ namespace klotski {
static ShortCode from_common_code(std::string &&common_code); static ShortCode from_common_code(std::string &&common_code);
static ShortCode from_common_code(const CommonCode &common_code) noexcept; static ShortCode from_common_code(const CommonCode &common_code) noexcept;
static ShortCode from_common_code(const std::string &common_code); static ShortCode from_common_code(const std::string &common_code);
}; };
inline bool operator==(uint32_t s1, const ShortCode &s2) noexcept { return s1 == s2.unwrap(); }
inline bool operator!=(uint32_t s1, const ShortCode &s2) noexcept { return s1 != s2.unwrap(); }
inline bool operator==(const ShortCode &s1, uint32_t s2) noexcept { return s1.unwrap() == s2; }
inline bool operator!=(const ShortCode &s1, uint32_t s2) noexcept { return s1.unwrap() != s2; }
inline bool operator==(const ShortCode &s1, const ShortCode &s2) noexcept { return s1.unwrap() == s2.unwrap(); }
inline bool operator!=(const ShortCode &s1, const ShortCode &s2) noexcept { return s1.unwrap() != s2.unwrap(); }
inline bool operator==(uint32_t s1, const ShortCode &s2) noexcept { return s1 == s2.unwrap(); } } // namespace klotski
inline bool operator!=(uint32_t s1, const ShortCode &s2) noexcept { return s1 != s2.unwrap(); }
inline bool operator==(const ShortCode &s1, uint32_t s2) noexcept { return s1.unwrap() == s2; }
inline bool operator!=(const ShortCode &s1, uint32_t s2) noexcept { return s1.unwrap() != s2; }
}

Loading…
Cancel
Save