trie.hpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. //
  2. // trie.hpp
  3. // trie
  4. //
  5. // Created by Sam Jaffe on 6/16/17.
  6. //
  7. #pragma once
  8. #include "pointers/const_propogating_ptr.hpp"
  9. #include "pointers/not_null.hpp"
  10. #include "pointers/value_ptr.hpp"
  11. #include <map>
  12. template <typename K, typename V, typename Compare = std::less<K>> class trie;
  13. namespace detail {
  14. template <typename Trie, typename Iter> class trie_iterator_base;
  15. template <typename Iter, typename Trie, typename KS>
  16. Iter find_impl(Trie * tr, KS const & keys);
  17. }
  18. template <typename Trie, typename Iter> class trie_iterator;
  19. template <typename Trie, typename Iter> class trie_reverse_iterator;
  20. /*
  21. * \brief A trie is a type of associative container where each element is
  22. * locatable by a string of keys, including a zero-length string. Sometimes
  23. * known as a prefix-tree.
  24. * \tparam K The key type. The container is indexable by both single keys, and
  25. * iterable collections of keys e.g. std::initializer_list<K>.
  26. * \tparam V The value type of stored data.
  27. * \tparam Compare The comparator function, used by the backing std::map object
  28. * to order this container.
  29. *
  30. * In principle, a trie<K, V> is equal to a std::map<std::vector<K>, V> with the
  31. * additional features of being able to locate all elements whose keys start
  32. * with the key fragment { K1, K2, ..., Kn }.
  33. *
  34. * Because the conceptual structure of a trie is a tree, both pre-order and
  35. * port-order iteration are supported. In-order traversal is not supported,
  36. * because it doesn't translate well with non-binary trees.
  37. */
  38. template <typename K, typename V, typename Compare> class trie {
  39. private:
  40. using impl_value_type = const_propogating_ptr<value_ptr<trie>>;
  41. using backing_t = std::map<K, impl_value_type, Compare>;
  42. template <typename KS>
  43. using element_type = std::decay_t<decltype(*std::begin(std::declval<KS>()))>;
  44. template <typename KS>
  45. using is_collection_t =
  46. std::enable_if_t<std::is_same<K, element_type<KS>>::value>;
  47. public:
  48. using key_type = K;
  49. using mapped_type = V;
  50. using key_compare = Compare;
  51. using local_iterator = typename backing_t::iterator;
  52. using local_const_iterator = typename backing_t::const_iterator;
  53. using local_reverse_iterator = typename backing_t::reverse_iterator;
  54. using local_const_reverse_iterator =
  55. typename backing_t::const_reverse_iterator;
  56. using iterator = trie_iterator<trie, local_iterator>;
  57. using const_iterator = trie_iterator<trie const, local_const_iterator>;
  58. using post_iterator = trie_reverse_iterator<trie, local_iterator>;
  59. using const_post_iterator =
  60. trie_reverse_iterator<trie const, local_const_iterator>;
  61. using reverse_iterator = trie_reverse_iterator<trie, local_reverse_iterator>;
  62. using const_reverse_iterator =
  63. trie_reverse_iterator<trie const, local_const_reverse_iterator>;
  64. private:
  65. using impl_iterator = detail::trie_iterator_base<trie, local_iterator>;
  66. using impl_const_iterator =
  67. detail::trie_iterator_base<trie const, local_const_iterator>;
  68. private:
  69. mapped_type value_{};
  70. backing_t impl_{};
  71. public:
  72. trie() {}
  73. trie(trie const & other);
  74. trie(trie && other) : trie() { swap(*this, other); }
  75. ~trie() { clear(); }
  76. trie & operator=(mapped_type const & value);
  77. trie & operator=(trie const & value);
  78. trie & operator=(trie && value);
  79. operator mapped_type &() { return value(); }
  80. operator mapped_type const &() const { return value(); }
  81. mapped_type & value() { return value_; }
  82. mapped_type const & value() const { return value_; }
  83. template <typename KS, typename = is_collection_t<KS>>
  84. trie & operator[](KS const & keys) {
  85. return *emplace(keys).first.parent_trie_.top();
  86. }
  87. trie & operator[](key_type const & key) {
  88. return *emplace(key).first.parent_trie_.top();
  89. }
  90. trie & operator[](std::initializer_list<key_type> keys) {
  91. return operator[]<>(keys);
  92. }
  93. template <typename KS>
  94. std::pair<iterator, bool> insert(KS const & keys, mapped_type const & value) {
  95. return emplace_impl(keys, value);
  96. }
  97. std::pair<iterator, bool> insert(key_type const & key,
  98. mapped_type const & value) {
  99. return emplace_impl({key}, value);
  100. }
  101. std::pair<iterator, bool> insert(std::initializer_list<key_type> keys,
  102. mapped_type const & value) {
  103. return emplace_impl(keys, value);
  104. }
  105. template <typename KS, typename... Args>
  106. std::pair<iterator, bool> emplace(KS && keys, Args &&... args) {
  107. return emplace_impl(keys, std::forward<Args>(args)...);
  108. }
  109. template <typename... Args>
  110. std::pair<iterator, bool> emplace(key_type const & key, Args &&... args) {
  111. return emplace_impl({key}, std::forward<Args>(args)...);
  112. }
  113. template <typename... Args>
  114. std::pair<iterator, bool> emplace(key_type && key, Args &&... args) {
  115. return emplace_impl({key}, std::forward<Args>(args)...);
  116. }
  117. template <typename... Args>
  118. std::pair<iterator, bool> emplace(std::initializer_list<key_type> keys,
  119. Args &&... args) {
  120. return emplace_impl(keys, std::forward<Args>(args)...);
  121. }
  122. iterator begin() { return {this}; }
  123. iterator end() { return {}; }
  124. const_iterator begin() const { return {this}; }
  125. const_iterator end() const { return {}; }
  126. const_iterator cbegin() const { return begin(); }
  127. const_iterator cend() const { return end(); }
  128. reverse_iterator rbegin() { return {this}; }
  129. reverse_iterator rend() { return {}; }
  130. const_reverse_iterator rbegin() const { return {this}; }
  131. const_reverse_iterator rend() const { return {}; }
  132. const_reverse_iterator crbegin() const { return rbegin(); }
  133. const_reverse_iterator crend() const { return rend(); }
  134. local_iterator local_begin() { return impl_.begin(); }
  135. local_iterator local_end() { return impl_.end(); }
  136. local_const_iterator local_begin() const { return impl_.begin(); }
  137. local_const_iterator local_end() const { return impl_.end(); }
  138. local_reverse_iterator local_rbegin() { return impl_.rbegin(); }
  139. local_reverse_iterator local_rend() { return impl_.rend(); }
  140. local_const_reverse_iterator local_rbegin() const { return impl_.rbegin(); }
  141. local_const_reverse_iterator local_rend() const { return impl_.rend(); }
  142. template <typename KS> iterator find(KS const & keys) {
  143. return detail::find_impl<impl_iterator>(this, keys);
  144. }
  145. iterator find(key_type const & key) {
  146. return find_impl<impl_iterator>(this, {key});
  147. }
  148. iterator find(std::initializer_list<key_type> keys) {
  149. return find_impl<impl_iterator>(this, keys);
  150. }
  151. template <typename KS> const_iterator find(KS const & keys) const {
  152. return detail::find_impl<impl_const_iterator>(this, keys);
  153. }
  154. const_iterator find(key_type const & key) const {
  155. return find_impl<impl_const_iterator>(this, {key});
  156. }
  157. const_iterator find(std::initializer_list<key_type> keys) const {
  158. return find_impl<impl_const_iterator>(this, keys);
  159. }
  160. template <typename KS> void erase(KS const & keys) { drop(find(keys)); }
  161. void erase(key_type const & key) { drop(find(key)); }
  162. void erase(std::initializer_list<key_type> keys) { drop(find(keys)); }
  163. void clear();
  164. private:
  165. void drop(iterator it);
  166. template <typename Iter, typename Trie, typename KS>
  167. friend Iter detail::find_impl(Trie * tr, KS const & keys);
  168. template <typename Iter, typename Trie>
  169. static Iter find_impl(Trie * tr, std::initializer_list<key_type> keys) {
  170. return detail::find_impl<Iter>(tr, keys);
  171. }
  172. template <typename KS, typename... Args>
  173. std::pair<impl_iterator, bool> emplace_impl(KS && keys, Args &&... args);
  174. template <typename... Args>
  175. std::pair<impl_iterator, bool>
  176. emplace_impl(std::initializer_list<key_type> keys, Args &&... args) {
  177. return emplace_impl<std::initializer_list<key_type>>(
  178. std::move(keys), std::forward<Args>(args)...);
  179. }
  180. template <typename Key>
  181. void insert_impl(impl_iterator & out, bool & create, Key && key);
  182. friend bool operator==(trie const & lhs, trie const & rhs) {
  183. const_iterator it1 = lhs.begin(), it2 = rhs.begin();
  184. const_iterator const end1 = lhs.end(), end2 = lhs.end();
  185. for (; it1 != end1 && it2 != end2; ++it1, ++it2) {
  186. if (it1 != it2) { return false; }
  187. }
  188. return it1 == end1 && it2 == end2;
  189. }
  190. friend bool operator!=(trie const & lhs, trie const & rhs) {
  191. return !(lhs == rhs);
  192. }
  193. friend void swap(trie & lhs, trie & rhs) {
  194. using std::swap;
  195. swap(lhs.value_, rhs.value_);
  196. swap(lhs.impl_, rhs.impl_);
  197. }
  198. };
  199. #include "trie.tpp"