Browse Source

update: enhance ShortCode module

master
Dnomd343 1 year ago
parent
commit
1b11684726
  1. 12
      src/klotski_core/short_code/convert.cc
  2. 6
      src/klotski_core/short_code/serialize.cc
  3. 47
      src/klotski_core/short_code/serialize_chars.h
  4. 84
      src/klotski_core/short_code/short_code.cc
  5. 176
      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 {
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::ShortCode(CommonCode &&common_code) noexcept {
if (ShortCode::mode() == ShortCode::NORMAL) {
code = tiny_encode(common_code.unwrap()); // normal mode
code_ = tiny_encode(common_code.unwrap()); // normal mode
} else {
code = fast_encode(common_code.unwrap()); // fast mode
code_ = fast_encode(common_code.unwrap()); // fast mode
}
}
ShortCode::ShortCode(const CommonCode &common_code) noexcept {
if (ShortCode::mode() == ShortCode::NORMAL) {
code = tiny_encode(common_code.unwrap()); // normal mode
code_ = tiny_encode(common_code.unwrap()); // normal mode
} 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 ---------------------------
std::string ShortCode::to_string() const noexcept { // encode as 5-bits string
return string_encode(code);
return string_encode(code_);
}
/// --------------------------- String to ShortCode ---------------------------
ShortCode::ShortCode(std::string &&short_code) {
code = string_decode(short_code);
code_ = string_decode(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) {

47
src/klotski_core/short_code/serialize_chars.h

@ -1,22 +1,39 @@
#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>
namespace klotski {
const int8_t SHORT_CODE_TABLE[32] = {
'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',
};
/// `1`(49) ~ `Z`(90)
const int8_t SHORT_CODE_TABLE_REV[42] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, // `1`(49) ~ `9`(57)
-1, -1, -1, -1, -1, -1, -1, // `:`(58) ~ `@`(64)
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)
26, 27, 28, 29, 30, 31, // `U`(85) ~ `Z`(90)
};
const int8_t SHORT_CODE_TABLE[32] = {
'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',
};
/// `1`(49) ~ `Z`(90)
const int8_t SHORT_CODE_TABLE_REV[42] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, // `1`(49) ~ `9`(57)
-1, -1, -1, -1, -1, -1, -1, // `:`(58) ~ `@`(64)
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)
26, 27, 28, 29, 30, 31, // `U`(85) ~ `Z`(90)
};
}

84
src/klotski_core/short_code/short_code.cc

@ -1,63 +1,35 @@
#include "all_cases.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 {
bool ShortCode::operator==(const ShortCode &short_code) const noexcept {
return this->code == short_code.code;
}
bool ShortCode::operator!=(const ShortCode &short_code) const noexcept {
return this->code != short_code.code;
}
bool ShortCode::fast_mode_available_ = false;
bool ShortCode::normal_mode_available_ = false;
std::ostream& operator<<(std::ostream &out, const ShortCode &self) {
out << self.to_string() << "(" << self.code << ")"; // short code info
return out;
}
bool ShortCode::valid() const noexcept {
return ShortCode::check(code_);
}
namespace klotski {
bool ShortCode::valid() const noexcept {
return ShortCode::check(code);
}
ShortCode ShortCode::create(uint32_t short_code) {
return ShortCode(short_code);
}
ShortCode ShortCode::create(uint32_t short_code) {
return ShortCode(short_code);
}
ShortCode ShortCode::unsafe_create(uint32_t short_code) noexcept { // create without check
auto tmp = ShortCode(); // init directly
tmp.code_ = short_code;
return tmp;
}
ShortCode ShortCode::unsafe_create(uint32_t short_code) noexcept { // create without check
auto tmp = ShortCode(); // init directly
tmp.code = short_code;
return tmp;
ShortCode::ShortCode(uint32_t short_code) {
if (!ShortCode::check(short_code)) { // check input short code
throw klotski::ShortCodeException("short code invalid");
}
code_ = short_code;
}
ShortCode::ShortCode(uint32_t short_code) {
if (!ShortCode::check(short_code)) { // check input short code
throw klotski::ShortCodeException("short code invalid");
}
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 {
@ -65,25 +37,27 @@ bool ShortCode::check(uint32_t short_code) noexcept {
}
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
}
if (normal_mode_available) {
if (normal_mode_available_) {
return ShortCode::NORMAL; // normal mode already enabled
}
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) {
if (fast_mode_available) {
if (fast_mode_available_) {
return; // fast mode already available
}
if (mode == ShortCode::FAST) { // build fast mode data
AllCases::build(); // blocking function
fast_mode_available = true;
} else if (!normal_mode_available) { // build normal mode data
fast_mode_available_ = true;
} else if (!normal_mode_available_) { // build normal mode data
BasicRanges::build(); // blocking function
normal_mode_available = true;
normal_mode_available_ = true;
}
}
} // namespace klotski

176
src/klotski_core/short_code/short_code.h

@ -2,7 +2,7 @@
/// ShortCode is a high-compression encoding scheme based on CommonCode. Since there
/// 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`.
/// 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.
/// 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
/// represented by a 5-bits length code. As in CommonCode, the characters here are
/// 5-bit base32 can make good use of space, so any valid klotski layout can be
/// represented by a 5-bit length code. As in CommonCode, the characters here are
/// case insensitive, but uppercase is still recommended.
/// ShortCode Convert Table
/// 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` |
/// -------------------------------------------------
@ -51,85 +51,93 @@
#include <string>
#include <cstdint>
#include <ostream>
#include <stdexcept>
#include <utility>
#include <stdexcept>
#include "all_cases.h"
#include "common_code.h"
namespace klotski {
class CommonCode; // import for convert interface
const uint32_t SHORT_CODE_LIMIT = klotski::ALL_CASES_SIZE_SUM;
class ShortCodeException : public std::runtime_error {
public:
ShortCodeException() : std::runtime_error("invalid short code") {}
explicit ShortCodeException(const std::string &msg) : std::runtime_error(msg) {}
~ShortCodeException() noexcept override = default;
};
class ShortCode {
public:
enum Mode {NORMAL, FAST};
private:
uint32_t code;
ShortCode() = default; // unsafe initialize
static Mode mode();
static bool fast_mode_available;
static bool normal_mode_available;
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 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 std::string string_encode(uint32_t short_code) noexcept; // short code -> string
static inline uint32_t string_decode(const std::string &short_code); // string -> short code
public:
/// ShortCode validity check
bool valid() const noexcept;
static bool check(uint32_t short_code) noexcept;
/// ShortCode convert mode
static void speed_up(Mode mode);
/// Operators of ShortCode
bool operator==(const ShortCode &short_code) const noexcept;
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);
/// Export functions
std::string to_string() const noexcept;
CommonCode to_common_code() const noexcept;
constexpr uint32_t unwrap() const noexcept { return code; }
/// ShortCode constructors
explicit ShortCode(uint32_t short_code);
explicit ShortCode(std::string &&short_code);
explicit ShortCode(CommonCode &&common_code) noexcept;
explicit ShortCode(const std::string &short_code);
explicit ShortCode(const CommonCode &common_code) noexcept;
/// Static initialization
static ShortCode create(uint32_t short_code);
static ShortCode unsafe_create(uint32_t short_code) noexcept;
static ShortCode from_string(std::string &&short_code);
static ShortCode from_string(const std::string &short_code);
static ShortCode from_common_code(uint64_t common_code);
static ShortCode from_common_code(CommonCode &&common_code) noexcept;
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 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; }
}
class CommonCode;
const uint32_t SHORT_CODE_LIMIT = klotski::ALL_CASES_SIZE_SUM;
class ShortCodeException : public std::runtime_error {
public:
ShortCodeException() : std::runtime_error("invalid short code") {}
explicit ShortCodeException(const std::string &msg) : std::runtime_error(msg) {}
~ShortCodeException() noexcept override = default;
};
/// For ShortCode, you must choose at least one mode (NORMAL or FAST) to convert, and
/// 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};
private:
uint32_t code_;
ShortCode() = default; // unsafe initialize
static Mode mode();
static bool fast_mode_available_;
static bool normal_mode_available_;
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 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 string_decode(const std::string &short_code);
static inline std::string string_encode(uint32_t short_code) noexcept;
public:
/// Validity check
bool valid() const noexcept;
static bool check(uint32_t short_code) noexcept;
/// ShortCode convert mode
static void speed_up(Mode mode); // {} -> {NORMAL} -> {FAST}
/// Operators of ShortCode
constexpr explicit operator uint32_t() const noexcept { return code_; }
friend std::ostream& operator<<(std::ostream &out, const ShortCode &self);
/// Export functions
std::string to_string() const noexcept;
CommonCode to_common_code() const noexcept;
constexpr uint32_t unwrap() const noexcept { return code_; }
/// ShortCode constructors
explicit ShortCode(uint32_t short_code);
explicit ShortCode(std::string &&short_code);
explicit ShortCode(CommonCode &&common_code) noexcept;
explicit ShortCode(const std::string &short_code);
explicit ShortCode(const CommonCode &common_code) noexcept;
/// Static initialization
static ShortCode create(uint32_t short_code);
static ShortCode unsafe_create(uint32_t short_code) noexcept;
static ShortCode from_string(std::string &&short_code);
static ShortCode from_string(const std::string &short_code);
static ShortCode from_common_code(uint64_t common_code);
static ShortCode from_common_code(CommonCode &&common_code) noexcept;
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 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(); }
} // namespace klotski

Loading…
Cancel
Save