libwordring
trie_iterator.hpp
1 #pragma once
2 
3 #include <array>
4 #include <iterator>
5 #include <type_traits>
6 
7 namespace wordring
8 {
9  template <typename Label, typename Base>
10  class basic_trie;
11 }
12 
13 namespace wordring::detail
14 {
24  template <typename Label, typename Base>
25  class const_trie_iterator : public Base
26  {
27  template <typename Label1, typename Base1>
28  friend class wordring::basic_trie;
29 
30  template <typename Label1, typename Base1>
31  friend bool operator==(const_trie_iterator<Label1, Base1> const&, const_trie_iterator<Label1, Base1> const&);
32 
33  template <typename Label1, typename Base1>
34  friend bool operator!=(const_trie_iterator<Label1, Base1> const&, const_trie_iterator<Label1, Base1> const&);
35 
36  protected:
37  using base_type = Base;
38 
39  using typename base_type::index_type;
40  using typename base_type::node_type;
41  using typename base_type::container;
42 
43  using unsigned_type = std::make_unsigned_t<Label>;
44 
45  public:
46  using difference_type = std::ptrdiff_t;
47  using value_type = Label;
48  using pointer = value_type*;
49  using reference = value_type&;
50  using iterator_category = std::input_iterator_tag;
51 
52  static constexpr std::uint16_t null_value = 256u;
53  static std::uint32_t constexpr coefficient = sizeof(value_type) / sizeof(typename base_type::value_type);
54 
55  static_assert(1 <= coefficient);
56 
57  public:
58  using base_type::operator bool;
59  using base_type::operator!;
60 
61  protected:
62  using base_type::value;
63  using base_type::limit;
64  using base_type::find;
65 
66  using base_type::m_c;
67  using base_type::m_index;
68 
69  public:
71  : base_type()
72  {
73  }
74 
75  protected:
76  const_trie_iterator(container& c, index_type index)
77  : base_type(c, index)
78  {
79  }
80 
81  const_trie_iterator(base_type const& it)
82  : base_type(it)
83  {
84  }
85 
86  public:
87  value_type operator*() const
88  {
89  assert(1 < m_index && m_index < limit());
90 
91  value_type result = 0;
92 
93  if constexpr (coefficient == 1) return base_type::value();
94  else
95  {
96  node_type const* d = m_c->data();
97  index_type idx = m_index;
98 
99  for (std::uint32_t i = 0; i < coefficient; ++i)
100  {
101  index_type parent = (d + idx)->m_check;
102  assert(1 <= parent && parent < limit());
103 
104  index_type base = (d + parent)->m_base;
105  assert(1 <= base && base < limit());
106 
107  result += (idx - base) << (i * 8);
108 
109  idx = parent;
110  }
111  }
112 
113  return result;
114  }
115 
141  const_trie_iterator operator[](value_type label) const
142  {
143  index_type idx = 0;
144 
145  if constexpr (coefficient == 1) idx = base_type::at_index(label);
146  else
147  {
148  index_type parent = m_index;
149  assert(1 <= parent && parent < base_type::limit());
150 
151  node_type const* d = m_c->data();
152  for (std::uint32_t i = 0; i < coefficient; ++i)
153  {
154  std::uint8_t ch = static_cast<unsigned_type>(label) >> (coefficient - i - 1) * 8 & 0xFFu;
155  index_type base = (d + parent)->m_base;
156  if (base <= 0)
157  {
158  idx = 0;
159  break;
160  }
161 
162  idx = base + ch;
163 
164  if ((d + idx)->m_check != parent)
165  {
166  idx = 0;
167  break;
168  }
169 
170  parent = idx;
171  }
172  }
173 
174  return const_trie_iterator(*m_c, idx);
175  }
176 
177  const_trie_iterator& operator++()
178  {
179  if constexpr (coefficient == 1) base_type::advance();
180  else
181  {
182  index_type idx = 0;
183  std::uint32_t lv = 0;
184 
185  node_type const* d = m_c->data();
186 
187  // 右、あるいは右上を探す
188  for (index_type i = m_index; lv < coefficient; ++lv)
189  {
190  index_type parent = (d + i)->m_check;
191  index_type base = (d + parent)->m_base;
192  // 右兄弟を探す
193  i = find(i + 1, base + null_value, parent);
194  if (i != 0)
195  {
196  idx = i;
197  break;
198  }
199  i = parent;
200  }
201 
202  // 足の長さをそろえる
203  if (idx != 0)
204  {
205  for (; 0 < lv; --lv)
206  {
207  index_type parent = idx;
208  index_type base = (d + idx)->m_base;
209  idx = find(base, base + null_value, parent);
210  assert(idx != 0);
211  }
212  }
213 
214  m_index = idx;
215  }
216 
217  return *this;
218  }
219 
220  const_trie_iterator operator++(int)
221  {
222  auto result = *this;
223  operator++();
224  return result;
225  }
226 
251  template <typename String>
252  void string(String& result) const
253  {
254  result.clear();
255  for (auto p = *this; 1 < p.m_index; p = p.parent()) result.push_back(*p);
256  std::reverse(std::begin(result), std::end(result));
257  }
258 
280  {
281  index_type idx = m_index;
282 
283  if constexpr (coefficient == 1) idx = base_type::parent_index();
284  else
285  {
286  for (std::uint32_t lv = 0; lv < coefficient; ++lv)
287  {
288  idx = (m_c->data() + idx)->m_check;
289  assert(1 <= idx && idx < limit());
290  }
291  }
292 
293  return const_trie_iterator(*m_c, idx);
294  }
295 
296  const_trie_iterator begin() const
297  {
298  index_type idx = m_index;
299 
300  if constexpr (coefficient == 1) idx = base_type::begin_index();
301  else
302  {
303  std::uint32_t lv = 0;
304 
305  trie_node const* d = m_c->data();
306  while (lv < coefficient && idx != 0)
307  {
308  index_type base = (d + idx)->m_base;
309  idx = (1 <= base)
310  ? find(base, base + null_value, idx)
311  : 0;
312  ++lv;
313  }
314 
315  idx = (lv == coefficient)
316  ? idx
317  : 0;
318  }
319 
320  return const_trie_iterator(*m_c, idx);
321  }
322 
323  const_trie_iterator end() const
324  {
325  return const_trie_iterator(*m_c, 0);
326  }
327  };
328 
329  template <typename Label1, typename Base1>
330  inline bool operator==(const_trie_iterator<Label1, Base1> const& lhs, const_trie_iterator<Label1, Base1> const& rhs)
331  {
332  assert(lhs.m_c == rhs.m_c);
333  return lhs.m_index == rhs.m_index;
334  }
335 
336  template <typename Label1, typename Base1>
337  inline bool operator!=(const_trie_iterator<Label1, Base1> const& lhs, const_trie_iterator<Label1, Base1> const& rhs)
338  {
339  return !(lhs == rhs);
340  }
341 }
wordring::basic_trie::find
const_iterator find(InputIterator first, InputIterator last) const
完全一致検索
Definition: trie.hpp:893
wordring::basic_trie::end
const_iterator end() const noexcept
根の終端を指すイテレータを返す
Definition: trie.hpp:581
wordring::detail::const_trie_iterator
basic_trie のイテレータ
Definition: trie_iterator.hpp:25
wordring
Definition: algorithm_.hpp:10
wordring::detail::const_trie_iterator::string
void string(String &result) const
根からイテレータが指すノードまでのラベル列を返す
Definition: trie_iterator.hpp:252
wordring::detail::const_trie_iterator::parent
const_trie_iterator parent() const
親を取得する
Definition: trie_iterator.hpp:279
wordring::basic_trie
任意の整数型をラベルとして用いることが出来る汎用Trie
Definition: trie.hpp:130
wordring::detail::trie_node
Definition: trie_heap.hpp:23
wordring::basic_trie::begin
const_iterator begin() const noexcept
根を指すイテレータを返す
Definition: trie.hpp:567
wordring::detail
wordring::detail::const_trie_iterator::operator[]
const_trie_iterator operator[](value_type label) const
ラベルで遷移できる子を返す
Definition: trie_iterator.hpp:141
wordring::html::operator==
bool operator==(simple_attr< String1 > const &lhs, simple_attr< String1 > const &rhs)
名前空間、接頭辞、ローカル名が一致する場合、true を返す
Definition: simple_node.hpp:168