libwordring
trie.hpp
1 #pragma once
2 
3 #include <wordring/serialize/serialize_iterator.hpp>
4 #include <wordring/trie/stable_trie_base.hpp>
5 #include <wordring/trie/trie_base.hpp>
6 #include <wordring/trie/trie_iterator.hpp>
7 
8 #include <memory>
9 #include <string>
10 #include <type_traits>
11 
12 namespace wordring
13 {
14  // ------------------------------------------------------------------------
15  // basic_trie
16  // ------------------------------------------------------------------------
17 
129  template <typename Label, typename Base>
130  class basic_trie : public Base
131  {
132  template <typename Label1, typename Base1>
133  friend std::ostream& operator<<(std::ostream&, basic_trie<Label1, Base1> const&);
134 
135  template <typename Label1, typename Base1>
136  friend std::istream& operator>>(std::istream&, basic_trie<Label1, Base1>&);
137 
138  protected:
139  using base_type = Base;
140 
141  using typename base_type::container;
142  using typename base_type::label_vector;
143  using typename base_type::index_type;
144  using typename base_type::node_type;
145 
146  using base_type::null_value;
147 
148  public:
149  using label_type = Label;
150  using value_type = std::uint32_t;
151  using size_type = typename container::size_type;
152  using allocator_type = typename base_type::allocator_type;
154  using const_reference = detail::trie_value_proxy const;
156 
157  public:
158  using typename base_type::serialize_iterator;
159 
160  using base_type::get_allocator;
161  using base_type::ibegin;
162  using base_type::iend;
163  using base_type::clear;
164 
165  protected:
166  using base_type::is_tail;
167 
168  using base_type::m_c;
169 
170  static std::uint32_t constexpr coefficient = sizeof(label_type) / sizeof(typename base_type::label_type);
171 
172  static_assert(std::is_integral_v<label_type>);
173  static_assert(1 <= coefficient);
174 
175  public:
184  : base_type()
185  {
186  }
187 
197  explicit basic_trie(allocator_type const& alloc)
198  : base_type(alloc)
199  {
200  }
201 
226  template <typename InputIterator, typename std::enable_if_t<std::is_integral_v<typename std::iterator_traits<InputIterator>::value_type>, std::nullptr_t> = nullptr>
227  basic_trie(InputIterator first, InputIterator last, allocator_type const& alloc = allocator_type())
228  : base_type(alloc)
229  {
230  assign(first, last);
231  }
232 
253  template <typename ForwardIterator, typename std::enable_if_t<std::negation_v<std::is_integral<typename std::iterator_traits<ForwardIterator>::value_type>>, std::nullptr_t> = nullptr>
254  basic_trie(ForwardIterator first, ForwardIterator last, allocator_type const& alloc = allocator_type())
255  : base_type(alloc)
256  {
257  assign(first, last);
258  }
259 
275  basic_trie(std::initializer_list<detail::trie_node> il, allocator_type const& alloc = allocator_type())
276  : base_type(il, alloc)
277  {
278  }
279 
305  template <typename InputIterator, typename std::enable_if_t<std::is_integral_v<typename std::iterator_traits<InputIterator>::value_type>, std::nullptr_t> = nullptr>
306  void assign(InputIterator first, InputIterator last)
307  {
308  base_type::assign(first, last);
309  }
310 
331  template <typename ForwardIterator, typename std::enable_if_t<std::negation_v<std::is_integral<typename std::iterator_traits<ForwardIterator>::value_type>>, std::nullptr_t> = nullptr>
332  void assign(ForwardIterator first, ForwardIterator last)
333  {
334  assert(coefficient == sizeof(typename std::iterator_traits<ForwardIterator>::value_type::value_type));
335 
336  if constexpr (coefficient == 1) base_type::assign(first, last);
337  else
338  {
339  while (first != last)
340  {
341  insert(*first);
342  ++first;
343  }
344  }
345  }
346 
347  // 要素アクセス --------------------------------------------------------
348 
363  reference at(const_iterator pos, index_type& idx)
364  {
365  return base_type::at(static_cast<typename base_type::const_iterator>(pos), idx);
366  }
367 
398  {
399  return base_type::at(static_cast<typename base_type::const_iterator>(pos));
400  }
401 
410  const_reference at(const_iterator pos) const
411  {
412  return const_cast<basic_trie<Label, Base>*>(this)->at(pos);
413  }
414 
444  template <typename InputIterator>
445  reference at(InputIterator first, InputIterator last)
446  {
447  assert(coefficient == sizeof(typename std::iterator_traits<InputIterator>::value_type));
448 
449  reference result;
450 
451  if constexpr (coefficient == 1) result = base_type::at(first, last);
452  else
453  {
454  auto it1 = wordring::serialize_iterator(first);
455  auto it2 = wordring::serialize_iterator(last);
456 
457  result = base_type::at(it1, it2);
458  }
459 
460  return result;
461  }
462 
472  template <typename InputIterator>
473  const_reference at(InputIterator first, InputIterator last) const
474  {
475  return const_cast<basic_trie<Label, Base>*>(this)->at(first, last);
476  }
477 
505  template <typename Key>
506  reference at(Key const& key)
507  {
508  return at(std::begin(key), std::end(key));
509  }
510 
521  template <typename Key>
522  const_reference const at(Key const& key) const
523  {
524  return at(std::begin(key), std::end(key));
525  }
526 
550  template <typename Key>
551  reference operator[](Key const& key)
552  {
553  const_iterator it = find(key);
554  if (it == cend()) it = insert(key);
555 
556  return at(it);
557  }
558 
559  // イテレータ ----------------------------------------------------------
560 
567  const_iterator begin() const noexcept { return const_iterator(m_c, 1); }
568 
575  const_iterator cbegin() const noexcept { return const_iterator(m_c, 1); }
576 
581  const_iterator end() const noexcept { return const_iterator(m_c, 0); }
582 
587  const_iterator cend() const noexcept { return const_iterator(m_c, 0); }
588 
589  // 容量 ---------------------------------------------------------------
590 
595  bool empty() const noexcept { return size() == 0; }
596 
601  size_type size() const noexcept
602  {
603  return base_type::size();
604  }
605 
610  static constexpr size_type max_size() noexcept
611  {
612  return base_type::max_size() / coefficient;
613  }
614 
615  // 変更 ---------------------------------------------------------------
616 
643  template <typename InputIterator>
644  const_iterator insert(InputIterator first, InputIterator last, value_type value = 0)
645  {
646  assert(coefficient == sizeof(typename std::iterator_traits<InputIterator>::value_type));
647 
648  const_iterator result;
649 
650  if constexpr (coefficient == 1) result = base_type::insert(first, last, value);
651  else
652  {
653  auto it1 = wordring::serialize_iterator(first);
654  auto it2 = wordring::serialize_iterator(last);
655 
656  result = base_type::insert(it1, it2, value);
657  }
658 
659  return result;
660  }
661 
686  template <typename Key>
687  const_iterator insert(Key const& key, value_type value = 0)
688  {
689  return insert(std::begin(key), std::end(key), value);
690  }
691 
713  {
714  base_type::erase(static_cast<typename base_type::const_iterator>(pos));
715  }
716 
738  template <typename InputIterator>
739  void erase(InputIterator first, InputIterator last)
740  {
741  assert(coefficient == sizeof(typename std::iterator_traits<InputIterator>::value_type));
742 
743  erase(find(first, last));
744  }
745 
765  template <typename Key>
766  void erase(Key const& key)
767  {
768  erase(std::begin(key), std::end(key));
769  }
770 
771  void swap(basic_trie<Label, Base>& other)
772  {
773  base_type::swap(other);
774  }
775 
776  // 検索 ---------------------------------------------------------------
777 
803  template <typename InputIterator>
804  auto lookup(InputIterator first, InputIterator last) const
805  {
806  assert(coefficient == sizeof(typename std::iterator_traits<InputIterator>::value_type));
807 
808  std::pair<const_iterator, InputIterator> result;
809 
810  if constexpr (coefficient == 1)
811  {
812  auto ret = base_type::lookup(first, last);
813  result.first = ret.first;
814  result.second = ret.second;
815  }
816  else
817  {
818  auto it1 = wordring::serialize_iterator(first);
819  auto it2 = wordring::serialize_iterator(last);
820 
821  std::uint32_t i = 0;
822  auto ret = base_type::lookup(it1, it2, i);
823 
824  i = i % coefficient;
825  if (i != 0) for (; i != 0; --i) ret.first = ret.first.parent();
826 
827  result.first = ret.first;
828  result.second = ret.second.base();
829  }
830 
831  return result;
832  }
833 
842  template <typename InputIterator>
843  const_iterator search(InputIterator first, InputIterator last) const
844  {
845  assert(coefficient == sizeof(typename std::iterator_traits<InputIterator>::value_type));
846 
847  auto pair = lookup(first, last);
848 
849  return (pair.second == last)
850  ? pair.first
851  : cend();
852  }
853 
877  template <typename Key>
878  const_iterator search(Key const& key) const
879  {
880  return search(std::begin(key), std::end(key));
881  }
882 
892  template <typename InputIterator>
893  const_iterator find(InputIterator first, InputIterator last) const
894  {
895  assert(coefficient == sizeof(typename std::iterator_traits<InputIterator>::value_type));
896 
897  auto pair = lookup(first, last);
898 
899  auto it = pair.second;
900  index_type idx = pair.first.m_index;
901 
902  return (it == last && is_tail(idx))
903  ? pair.first
904  : cend();
905  }
906 
930  template <typename Key>
931  const_iterator find(Key const& key) const
932  {
933  return find(std::begin(key), std::end(key));
934  }
935 
943  template <typename InputIterator>
944  bool contains(InputIterator first, InputIterator last) const
945  {
946  assert(coefficient == sizeof(typename std::iterator_traits<InputIterator>::value_type));
947 
948  auto pair = lookup(first, last);
949 
950  auto it = pair.second;
951  index_type idx = pair.first.m_index;
952 
953  return !(it != last || !is_tail(idx));
954  }
955 
974  template <typename Key>
975  bool contains(Key const& key) const
976  {
977  return contains(std::begin(key), std::end(key));
978  }
979  };
980 
1003  template <typename Label1, typename Base1>
1004  inline std::ostream& operator<<(std::ostream& os, basic_trie<Label1, Base1> const& trie)
1005  {
1006  typename basic_trie<Label1, Base1>::base_type const& base = trie;
1007  return os << base;
1008  }
1009 
1014  template <typename Label1, typename Base1>
1015  inline std::istream& operator>>(std::istream& is, basic_trie<Label1, Base1>& trie)
1016  {
1017  typename basic_trie<Label1, Base1>::base_type& base = trie;
1018  return is >> base;
1019  }
1020 
1025  template <typename Label, typename Allocator = std::allocator<detail::trie_node>>
1027 
1033  template <typename Label, typename Allocator = std::allocator<detail::trie_node>>
1035 }
wordring::basic_trie::at
const_reference at(InputIterator first, InputIterator last) const
葉の値への参照を返す
Definition: trie.hpp:473
wordring::serialize_iterator
任意型の整数列に対するイテレータをバイトを返すイテレータへ変換する
Definition: serialize_iterator.hpp:50
wordring::basic_trie::erase
void erase(Key const &key)
キー文字列を削除する
Definition: trie.hpp:766
wordring::operator>>
std::istream & operator>>(std::istream &is, basic_trie< Label1, Base1 > &trie)
ストリームから入力する
Definition: trie.hpp:1015
wordring::basic_trie::cend
const_iterator cend() const noexcept
根の終端を指すイテレータを返す
Definition: trie.hpp:587
wordring::basic_trie::cbegin
const_iterator cbegin() const noexcept
根を指すイテレータを返す
Definition: trie.hpp:575
wordring::basic_trie::assign
void assign(InputIterator first, InputIterator last)
直列化データから割り当てる
Definition: trie.hpp:306
wordring::basic_trie::operator[]
reference operator[](Key const &key)
葉の値への参照を返す
Definition: trie.hpp:551
wordring::basic_trie::contains
bool contains(Key const &key) const
キー文字列が格納されているか調べる
Definition: trie.hpp:975
wordring::basic_trie::operator>>
friend std::istream & operator>>(std::istream &, basic_trie< Label1, Base1 > &)
ストリームから入力する
Definition: trie.hpp:1015
wordring::basic_trie::max_size
static constexpr size_type max_size() noexcept
キー文字列の格納可能な最大数を調べる
Definition: trie.hpp:610
wordring::basic_trie::search
const_iterator search(InputIterator first, InputIterator last) const
前方一致検索
Definition: trie.hpp:843
wordring::trie
basic_trie< Label, detail::trie_base< Allocator > > trie
メモリー使用量削減を目標とする汎用Trie
Definition: trie.hpp:1026
wordring::basic_trie::find
const_iterator find(InputIterator first, InputIterator last) const
完全一致検索
Definition: trie.hpp:893
wordring::basic_trie::assign
void assign(ForwardIterator first, ForwardIterator last)
文字列リストから割り当てる
Definition: trie.hpp:332
wordring::basic_trie::end
const_iterator end() const noexcept
根の終端を指すイテレータを返す
Definition: trie.hpp:581
wordring::basic_trie::at
const_reference at(const_iterator pos) const
葉の値への参照を返す
Definition: trie.hpp:410
wordring::detail::const_trie_iterator
basic_trie のイテレータ
Definition: trie_iterator.hpp:25
wordring
Definition: algorithm_.hpp:10
wordring::operator<<
std::ostream & operator<<(std::ostream &os, basic_trie< Label1, Base1 > const &trie)
ストリームへ出力する
Definition: trie.hpp:1004
wordring::basic_trie::at
reference at(const_iterator pos, index_type &idx)
葉の値への参照を返す
Definition: trie.hpp:363
wordring::basic_trie::basic_trie
basic_trie(allocator_type const &alloc)
アロケータを指定して空のコンテナを構築する
Definition: trie.hpp:197
wordring::basic_trie::size
size_type size() const noexcept
格納しているキー文字列数を調べる
Definition: trie.hpp:601
wordring::basic_trie::erase
void erase(InputIterator first, InputIterator last)
キー文字列を削除する
Definition: trie.hpp:739
wordring::basic_trie::insert
const_iterator insert(Key const &key, value_type value=0)
キー文字列を挿入する
Definition: trie.hpp:687
wordring::basic_trie::contains
bool contains(InputIterator first, InputIterator last) const
キー文字列が格納されているか調べる
Definition: trie.hpp:944
wordring::basic_trie::find
const_iterator find(Key const &key) const
完全一致検索
Definition: trie.hpp:931
wordring::basic_trie::at
reference at(InputIterator first, InputIterator last)
葉の値への参照を返す
Definition: trie.hpp:445
wordring::basic_trie
任意の整数型をラベルとして用いることが出来る汎用Trie
Definition: trie.hpp:130
wordring::basic_trie::at
const const_reference at(Key const &key) const
葉の値への参照を返す
Definition: trie.hpp:522
wordring::basic_trie::basic_trie
basic_trie()
空のコンテナを構築する
Definition: trie.hpp:183
wordring::basic_trie::basic_trie
basic_trie(InputIterator first, InputIterator last, allocator_type const &alloc=allocator_type())
直列化データから構築する
Definition: trie.hpp:227
wordring::basic_trie::begin
const_iterator begin() const noexcept
根を指すイテレータを返す
Definition: trie.hpp:567
wordring::basic_trie::operator<<
friend std::ostream & operator<<(std::ostream &, basic_trie< Label1, Base1 > const &)
ストリームへ出力する
Definition: trie.hpp:1004
wordring::basic_trie::search
const_iterator search(Key const &key) const
前方一致検索
Definition: trie.hpp:878
wordring::basic_trie::at
reference at(const_iterator pos)
葉の値への参照を返す
Definition: trie.hpp:397
wordring::basic_trie::at
reference at(Key const &key)
葉の値への参照を返す
Definition: trie.hpp:506
wordring::basic_trie::basic_trie
basic_trie(ForwardIterator first, ForwardIterator last, allocator_type const &alloc=allocator_type())
文字列のリストから構築する
Definition: trie.hpp:254
wordring::detail::trie_value_proxy
Definition: trie_heap.hpp:40
wordring::basic_trie::insert
const_iterator insert(InputIterator first, InputIterator last, value_type value=0)
キー文字列を挿入する
Definition: trie.hpp:644
wordring::basic_trie::basic_trie
basic_trie(std::initializer_list< detail::trie_node > il, allocator_type const &alloc=allocator_type())
初期化子リストから構築する
Definition: trie.hpp:275
wordring::basic_trie::erase
void erase(const_iterator pos)
キー文字列を削除する
Definition: trie.hpp:712
wordring::basic_trie::empty
bool empty() const noexcept
キー文字列を格納していないことを調べる
Definition: trie.hpp:595
wordring::basic_trie::lookup
auto lookup(InputIterator first, InputIterator last) const
部分一致検索
Definition: trie.hpp:804