Wordsearch Solver
full_node_view.hpp
1 #ifndef FULL_NODE_VIEW_HPP
2 #define FULL_NODE_VIEW_HPP
3 
4 #include "wordsearch_solver/compact_trie2/compact_trie2_iterator_typedefs.hpp"
5 #include "wordsearch_solver/compact_trie2/mini_offsets.hpp"
6 
7 #include <fmt/format.h>
8 #include <range/v3/iterator/access.hpp>
9 #include <range/v3/view/subrange.hpp>
10 #include <range/v3/view/transform.hpp>
11 
12 #include <bitset>
13 #include <cstddef>
14 #include <cstdint>
15 #include <cstring>
16 #include <ostream>
17 #include <type_traits>
18 #include <vector>
19 
20 namespace compact_trie2 {
21 
25 template <class Iterator> class FullNodeView_ {
26 public:
27  explicit FullNodeView_(Iterator it) : it_(it) {}
28 
30  auto base() const { return it_; }
31 
33  std::size_t size() const {
34  return this->data_size() * 3 + 2;
35  }
36 
37  bool is_only_end_of_word() const {
38  return false;
39  // return this->data_size() == 0;
40  }
41 
43  std::uint8_t data_size() const { return *it_; }
44 
46  bool is_end_of_word() const {
47  // fmt::print("THIS IS THE DROID YOU'RE LOOKING FOR\n");
48  // fmt::print("it_ + 1: {:#08x}\n", uint(*(it_ + 1)));
49  // fmt::print("it_ + 2: {:#08x}\n", uint(*(it_ + 2)));
50  // fmt::print("it_ + 3: {:#08x}\n", uint(*(it_ + 3)));
51 
52  // Return the highest bit of the "3 byte integer offset"
53  // Would be nice not have to this hard coded to 3
54  return *(it_ + 3) & 0x80;
55  }
56 
58  std::uint_fast32_t next_row_offset() const {
59  assert(!this->is_only_end_of_word());
60  std::uint_fast32_t n{};
61  std::memcpy(&n, &*(it_ + 1), 3);
62  // Where's my c++20 std::bit_cast
63 
64  // In the 3 byte (24 bit) next row offset, we use the highest bit as an
65  // end_of_word flag. Therefore it must be zeroed to read the offset.
66  n &= ~(1UL << 23);
67  return n;
68  }
69 
71  auto data() const {
72  const auto offset = it_ + 4;
73  return ranges::subrange(offset, offset + this->data_size());
74  }
75 
78  auto mini_offsets() const {
79  assert(!this->is_only_end_of_word());
80  const auto offset = it_ + 4 + this->data_size();
81  assert(this->data_size() > 0);
82  return make_mini_offsets(
83  ranges::subrange(offset, offset + 2 * (this->data_size() - 1)));
84  }
85 
89  template <class = std::enable_if_t<std::is_convertible_v<
90  std::add_pointer_t<ranges::iter_value_t<Iterator>>, void*>>>
91  void set_next_row_offset(const std::uint_fast32_t next_row_offset) {
92  auto it = it_ + 1;
93  assert(next_row_offset < 1 << 23);
94  // Mask off top byte and also end_of_word bit
95 
96  std::bitset<24> bits{next_row_offset};
97  bits[23] = this->is_end_of_word();
98  const auto n = bits.to_ulong();
99  // next_row_offset |= this->is_end_of_word() << 7;
100  // next_row_offset <<= 8;
101  std::memcpy(&*it, &n, 3);
102  }
103 
104  // template<class Range>
105  // void set_mini_offsets(Range&& mini_offsets)
106  // {
107  // assert(!this->is_only_end_of_word());
108  // assert(mini_offsets.size() == this->data_size() - 1);
109  // auto offset = it_ + 4 + this->data_size();
110  // // const auto offset_end = offset + this->data_size() - 1;
111  // for (const auto val: mini_offsets)
112  // {
113  // *offset++ = val;
114  // }
115  // }
116 
117  friend std::ostream& operator<<(std::ostream& os, const FullNodeView_& nv) {
118  auto to_uint = ranges::views::transform(
119  [](const auto val) { return static_cast<std::size_t>(val); });
120  auto to_char = ranges::views::transform(
121  [](const auto val) { return static_cast<char>(val); });
122 
123  const auto size = nv.size();
124  const bool is_end_of_word = nv.is_end_of_word();
125  const auto next_row_offset = nv.next_row_offset();
126  const auto data = nv.data() | to_char;
127 
128  // fmt::print(">>>>>>>>> About to print mini_offsets <<<<<<<<\n");
129  const auto mini_offsets = nv.mini_offsets() | to_uint;
130  // fmt::print("mini_offsets: {}\n", mini_offsets);
131 
132  // return os << fmt::format("FullNode: {{Size: {}, EndOfWord: {}, "
133  // "next_row_offset: {}, data: {}, mini_offsets: {}}}",
134  // size, is_end_of_word, next_row_offset, data, mini_offsets);
135  return os << fmt::format("FullNode: {{Size: {}, EndOfWord: {}, "
136  "next_row_offset: {}, data: {}, mini_offsets {}}}",
138  mini_offsets);
139  }
140 
141  Iterator it_;
142 };
143 
144 using FullNodeViewMut = FullNodeView_<DataIteratorMut>;
145 using FullNodeView = FullNodeView_<DataIterator>;
146 
147 } // namespace compact_trie2
148 
149 #endif // FULL_NODE_VIEW_HPP
Class representing a full node, a view into a contiguous array.
Definition: full_node_view.hpp:25
std::uint_fast32_t next_row_offset() const
Definition: full_node_view.hpp:58
auto base() const
Definition: full_node_view.hpp:30
void set_next_row_offset(const std::uint_fast32_t next_row_offset)
Set the 23 bit next_row_offset from a 4byte unsigned int.
Definition: full_node_view.hpp:91
auto mini_offsets() const
Definition: full_node_view.hpp:78
bool is_end_of_word() const
Definition: full_node_view.hpp:46
std::uint8_t data_size() const
Number of letters stored in this node.
Definition: full_node_view.hpp:43
std::size_t size() const
Definition: full_node_view.hpp:33
auto data() const
Definition: full_node_view.hpp:71
namespace compact_trie2
Definition: compact_trie2.hpp:19