Browse Source

refactor: forward declaration of range module

master
Dnomd343 1 month ago
parent
commit
4fc9212576
  1. 6
      src/core/all_cases/all_cases.h
  2. 2
      src/core/all_cases/internal/basic_ranges.inl
  3. 9
      src/core/common_code/common_code_fwd.h
  4. 33
      src/core/ranges/internal/check.inl
  5. 56
      src/core/ranges/internal/derive.cc
  6. 32
      src/core/ranges/internal/ranges.cc
  7. 27
      src/core/ranges/internal/ranges.inl
  8. 12
      src/core/ranges/ranges.h
  9. 10
      src/core/ranges/ranges_fwd.h
  10. 1
      src/core/short_code/internal/short_code.inl
  11. 13
      src/core/short_code/short_code.h
  12. 12
      src/core/utils/utility.h

6
src/core/all_cases/all_cases.h

@ -42,9 +42,13 @@
#include <mutex>
#include "utils/utility.h"
#include "ranges/ranges.h"
#include "internal/constant.inl"
namespace klotski::cases {
class Ranges;
class RangesUnion;
} // namespace klotski::cases
namespace klotski::cases {
// ----------------------------------------------------------------------------------------- //

2
src/core/all_cases/internal/basic_ranges.inl

@ -1,5 +1,7 @@
#pragma once
#include "ranges/ranges.h"
namespace klotski::cases {
inline Ranges& BasicRanges::get_ranges() {

9
src/core/common_code/common_code_fwd.h

@ -0,0 +1,9 @@
/// Klotski Engine by Dnomd343 @2024
#pragma once
namespace klotski::codec {
class CommonCode;
} // namespace klotski::codec

33
src/core/ranges/internal/check.inl

@ -0,0 +1,33 @@
#pragma once
namespace klotski::cases {
KLSK_INLINE_CE int Ranges::check(const int head, uint32_t range) {
KLSK_ASSUME(head >= 0 && head < 16 && head % 4 != 3);
uint32_t flags = 0b110011 << head; // fill 2x2 block
for (int addr = 0, offset = 1; range; range >>= 2, ++offset) { // traverse every 2-bit
const auto num = std::countr_one(flags);
addr += num; // next unfilled block
flags >>= num;
switch (range & 0b11) {
case 0b00: // space
case 0b11: // 1x1 block
flags |= 0b1;
continue;
case 0b01: // 1x2 block
if (flags & 0b10 || addr % 4 == 3) { // invalid case
return offset; // broken offset
}
flags |= 0b11;
continue;
case 0b10: // 2x1 block
if (flags & 0b10000 || addr > 15) { // invalid case
return offset; // broken offset
}
flags |= 0b10001;
}
}
return 0; // pass check
}
} // namespace klotski::cases

56
src/core/ranges/internal/derive.cc

@ -1,52 +1,4 @@
#include "utils/utility.h"
#include "ranges/ranges.h"
using klotski::cases::Ranges;
int Ranges::check(const int head, uint32_t range) {
KLSK_ASSUME(head >= 0 && head < 16 && head % 4 != 3);
uint32_t flags = 0b110011 << head; // fill 2x2 block
for (int addr = 0, offset = 1; range; range >>= 2, ++offset) { // traverse every 2-bit
const auto num = std::countr_one(flags);
addr += num; // next unfilled block
flags >>= num;
switch (range & 0b11) {
case 0b00: // space
case 0b11: // 1x1 block
flags |= 0b1;
continue;
case 0b01: // 1x2 block
if (flags & 0b10 || addr % 4 == 3) { // invalid case
return offset; // broken offset
}
flags |= 0b11;
continue;
case 0b10: // 2x1 block
if (flags & 0b10000 || addr > 15) { // invalid case
return offset; // broken offset
}
flags |= 0b10001;
}
}
return 0; // pass check
}
void Ranges::derive(const int head, Ranges &output) const {
const uint32_t max_val = range_reverse(this->back());
for (uint32_t index = 0; index < size(); ++index) {
if (const auto offset = check(head, (*this)[index])) { // invalid case
/// !! <- broken
/// ( xx xx xx ) xx xx xx ... [reversed range]
/// +1 00 00 00 ... (delta)
const uint32_t delta = 1U << (32 - offset * 2); // distance to next possible range
const auto min_next = delta + (range_reverse((*this)[index]) & ~(delta - 1));
if (min_next > max_val) {
break; // index has overflowed
}
while (range_reverse((*this)[++index]) < min_next) {} // located next range
--index;
continue;
}
output.emplace_back(range_reverse((*this)[index])); // release valid case
}
}
// #include "utils/utility.h"
// #include "ranges/ranges.h"
//
// using klotski::cases::Ranges;

32
src/core/ranges/internal/ranges.cc

@ -1,5 +1,3 @@
#include <span>
#include "ranges/ranges.h"
#include "common_code/common_code.h"
@ -19,20 +17,22 @@ std::vector<CommonCode> RangesUnion::codes() const {
return codes;
}
KLSK_INLINE CommonCode RangesUnion::operator[](size_type n) const {
if (n < ranges(0).size()) {
return CommonCode::unsafe_create(ranges(0)[n]);
}
n -= ranges(0).size();
KLSK_UNROLL(Heads.size() - 2)
for (const uint64_t head : std::span {Heads.data() + 1, Heads.size() - 2}) {
if (n < ranges(head).size()) {
return CommonCode::unsafe_create(head << 32 | ranges(head)[n]);
void Ranges::derive(const int head, Ranges &output) const {
const uint32_t max_val = range_reverse(this->back());
for (uint32_t index = 0; index < size(); ++index) {
if (const auto offset = check(head, (*this)[index])) { // invalid case
/// !! <- broken
/// ( xx xx xx ) xx xx xx ... [reversed range]
/// +1 00 00 00 ... (delta)
const uint32_t delta = 1U << (32 - offset * 2); // distance to next possible range
const auto min_next = delta + (range_reverse((*this)[index]) & ~(delta - 1));
if (min_next > max_val) {
break; // index has overflowed
}
while (range_reverse((*this)[++index]) < min_next) {} // located next range
--index;
continue;
}
n -= ranges(head).size();
output.emplace_back(range_reverse((*this)[index])); // release valid case
}
constexpr auto head = static_cast<uint64_t>(0xE);
return CommonCode::unsafe_create(head << 32 | ranges(0xE)[n]);
}

27
src/core/ranges/internal/ranges.inl

@ -1,9 +1,14 @@
#pragma once
#include <span>
#include "utils/utility.h"
#include "common_code/common_code.h"
namespace klotski::cases {
KLSK_INLINE_H void Ranges::reverse() {
#pragma clang loop vectorize(enable)
KLSK_IVDEP
for (auto &x : *this) {
x = range_reverse(x);
}
@ -22,7 +27,7 @@ inline Ranges& Ranges::operator+=(const Ranges &ranges) {
return *this;
}
inline RangesUnion& RangesUnion::operator+=(const RangesUnion &ranges_union) {
KLSK_INLINE_H RangesUnion& RangesUnion::operator+=(const RangesUnion &ranges_union) {
for (const auto head : Heads) {
ranges(head) += ranges_union.ranges(head);
}
@ -38,4 +43,22 @@ KLSK_INLINE_H size_t RangesUnion::size() const {
return size;
}
KLSK_INLINE_H codec::CommonCode RangesUnion::operator[](size_type n) const {
if (n < ranges(0).size()) {
return codec::CommonCode::unsafe_create(ranges(0)[n]);
}
n -= ranges(0).size();
KLSK_UNROLL(Heads.size() - 2)
for (const uint64_t head : std::span {Heads.data() + 1, Heads.size() - 2}) {
if (n < ranges(head).size()) {
return codec::CommonCode::unsafe_create(head << 32 | ranges(head)[n]);
}
n -= ranges(head).size();
}
constexpr auto head = static_cast<uint64_t>(0xE);
return codec::CommonCode::unsafe_create(head << 32 | ranges(0xE)[n]);
}
} // namespace klotski::cases

12
src/core/ranges/ranges.h

@ -12,7 +12,7 @@
/// 3. n_space >= 2
///
/// That is:
/// n_1x1 + (n_2x1 + n_1x2) * 2 <= 14 (n_2x1 != 7)
/// n_1x1 + (n_2x1 + n_1x2) * 2 <= 14 (n_2x1 != 7)
///
/// In the above inequality, the variables are all positive integers, so we can
/// get 203 combinations. In each combination, four kinds of 2-bit items can be
@ -38,10 +38,7 @@
#include <cstdint>
#include "utils/utility.h"
namespace klotski::codec {
class CommonCode;
} // namespace klotski::codec
#include "common_code/common_code_fwd.h"
namespace klotski::cases {
@ -62,7 +59,7 @@ public:
void derive(int head, Ranges &output) const;
/// Check whether the combination of head and reversed range is valid.
static KLSK_INLINE int check(int head, uint32_t range);
static KLSK_INLINE_CE int check(int head, uint32_t range);
// ------------------------------------------------------------------------------------- //
};
@ -95,10 +92,11 @@ public:
private:
static constexpr auto Heads = std::to_array<uint64_t>({
0x0, 0x1, 0x2, 0x4, 0x5, 0x6, 0x8, 0x9, 0xA, 0xC, 0xD, 0xE,
0x0, 0x1, 0x2, 0x4, 0x5, 0x6, 0x8, 0x9, 0xA, 0xC, 0xD, 0xE
});
};
} // namespace klotski::cases
#include "internal/ranges.inl"
#include "internal/check.inl"

10
src/core/ranges/ranges_fwd.h

@ -0,0 +1,10 @@
/// Klotski Engine by Dnomd343 @2024
#pragma once
namespace klotski::cases {
class Ranges;
class RangesUnion;
} // namespace klotski::cases

1
src/core/short_code/internal/short_code.inl

@ -1,5 +1,6 @@
#pragma once
#include "all_cases/all_cases.h"
#include "common_code/common_code.h"
namespace klotski::codec {

13
src/core/short_code/short_code.h

@ -60,16 +60,25 @@
#pragma once
#include <mutex>
#include <string>
#include <cstdint>
#include <ostream>
#include <optional>
#include "all_cases/all_cases.h"
#include "utils/utility.h"
// #include "all_cases/all_cases.h"
namespace klotski::cases {
class AllCases;
class Ranges;
class RangesUnion;
} // namespace klotski::cases
namespace klotski::codec {
constexpr uint32_t SHORT_CODE_LIMIT = cases::ALL_CASES_NUM_;
constexpr uint32_t SHORT_CODE_LIMIT = 29334498;
// constexpr uint32_t SHORT_CODE_LIMIT = cases::ALL_CASES_NUM_;
class CommonCode;

12
src/core/utils/utility.h

@ -25,9 +25,9 @@
/// Marking compiler assumptions.
#if defined(__clang__)
#define KLSK_ASSUME(expr) __builtin_assume(expr)
#define KLSK_ASSUME(expr) __builtin_assume(expr)
#elif defined(__GNUC__)
#define KLSK_ASSUME(expr) [[assume(expr)]]
#define KLSK_ASSUME(expr) [[assume(expr)]]
#endif
#define KLSK_UNREACHABLE __builtin_unreachable() // TODO: using `std::unreachable`
@ -47,8 +47,12 @@
#define KLSK_UNROLL(N) _Pragma(KLSK_STRING(unroll N))
#elif defined(__GNUC__)
#define KLSK_UNROLL(N) _Pragma(KLSK_STRING(GCC unroll N))
#else
#define KLSK_UNROLL(N)
#endif
#if defined(__clang__)
#define KLSK_IVDEP _Pragma("clang loop vectorize(enable)")
#elif defined(__GNUC__)
#define KLSK_IVDEP _Pragma("GCC ivdep")
#endif
/// Prevent reordering for both compiler and processor.

Loading…
Cancel
Save