halcheck 1.0
Loading...
Searching...
No Matches
trie.hpp
1#ifndef HALCHECK_LIB_TRIE_HPP
2#define HALCHECK_LIB_TRIE_HPP
3
11#include <halcheck/lib/functional.hpp>
12#include <halcheck/lib/iterator.hpp>
13#include <halcheck/lib/memory.hpp>
14#include <halcheck/lib/type_traits.hpp>
15
16#include <cstddef>
17#include <functional>
18#include <iterator>
19#include <memory>
20#include <type_traits>
21#include <unordered_map>
22#include <utility>
23
24namespace halcheck { namespace lib {
25
33template<typename K, typename V, typename Hash = std::hash<K>>
34class trie {
35private:
36 static_assert(lib::is_invocable_r<std::size_t, Hash, const K &>(), "Hash must be a hasher for K");
37 static_assert(std::is_default_constructible<V>(), "V must be default constructible");
38
41
42public:
48 trie() = default;
49
57 template<
58 typename I,
61 explicit trie(V value, I first, I last)
62 : _value(new V(std::move(value))), _children(new std::unordered_map<K, trie>(std::move(first), std::move(last))) {
63 }
64
73 template<
74 typename R,
77 explicit trie(V value, R &&range) : trie(std::move(value), lib::begin(range), lib::end(range)) {}
78
83 const V &operator*() const {
84 static const V fallback;
85 if (_value)
86 return *_value;
87 else
88 return fallback;
89 }
90
97 template<
98 typename R,
101 const V &operator[](const R &range) const {
102 return *drop(range);
103 }
104
111 template<
112 typename R,
115 trie drop(const R &range) const {
116 return drop(lib::begin(range), lib::end(range));
117 }
118
126 template<
127 typename I,
130 trie drop(I first, I last) const {
131 auto output = *this;
132 for (; first != last; ++first) {
133 auto it = output.find(*first);
134 if (it == output.end())
135 return trie();
136 else
137 output = it->second;
138 }
139
140 return output;
141 }
142
148 trie drop(const K &key) const {
149 auto it = find(key);
150 if (it == end())
151 return trie();
152 else
153 return it->second;
154 }
155
164 template<
165 typename I,
168 trie set(I first, I last, V value) const {
169 auto output = *this;
170 auto current = &output;
171
172 for (; first != last; ++first) {
173 current->_children = current->_children ? std::make_shared<std::unordered_map<K, trie, Hash>>(*current->_children)
175 current = &(*current->_children)[*first];
176 }
177
178 current->_value = std::make_shared<V>(std::move(value));
179 return output;
180 }
181
189 template<
190 typename R,
193 trie set(const R &range, V value) const {
194 return set(lib::begin(range), lib::end(range), std::move(value));
195 }
196
200 class iterator : public lib::iterator_interface<iterator> {
201 public:
202 using value_type = typename std::unordered_map<K, trie, Hash>::value_type;
203 using difference_type = typename std::unordered_map<K, trie, Hash>::difference_type;
207
208 using lib::iterator_interface<iterator>::operator++;
209
210 iterator() = default;
211
212 explicit iterator(typename std::unordered_map<K, trie, Hash>::const_iterator base) : _base(std::move(base)) {}
213
214 iterator &operator++() {
215 ++_base;
216 return *this;
217 }
218
219 reference operator*() const { return *_base; }
220
221 pointer operator->() const { return _base.operator->(); }
222
223 private:
224 friend bool operator==(const iterator &lhs, const iterator &rhs) { return lhs._base == rhs._base; }
225
226 typename std::unordered_map<K, trie, Hash>::const_iterator _base;
227 };
228
233 iterator begin() const { return _children ? iterator(_children->begin()) : iterator(); }
234
239 iterator end() const { return _children ? iterator(_children->end()) : iterator(); }
240
245 std::size_t size() const { return _children.size(); }
246
251 bool empty() const { return _children.empty(); }
252
258 iterator find(const K &key) const {
259 if (_children)
260 return iterator(_children->find(key));
261 else
262 return iterator();
263 }
264};
265
266}} // namespace halcheck::lib
267
268#endif
A utility class for easily defining new iterators.
Definition interface.hpp:40
Represents a pointer to a child trie.
Definition trie.hpp:200
iterator begin() const
Returns an iterator to the first child.
Definition trie.hpp:233
trie(V value, I first, I last)
Constructs a trie with a given value and set of children.
Definition trie.hpp:61
iterator find(const K &key) const
Gets an iterator to the child indicated by the given key.
Definition trie.hpp:258
trie set(I first, I last, V value) const
Constructs a new trie with a specific value replaced.
Definition trie.hpp:168
bool empty() const
Determines whether this trie has any children.
Definition trie.hpp:251
trie drop(const R &range) const
Gets a specific subtree.
Definition trie.hpp:115
trie()=default
Constructs a trie where every node is assigned the same value.
const V & operator*() const
Gets the value associated with the root node of this trie.
Definition trie.hpp:83
trie drop(I first, I last) const
Gets a specific subtree.
Definition trie.hpp:130
iterator end() const
Returns an iterator to one past the last child.
Definition trie.hpp:239
const V & operator[](const R &range) const
Gets the value associated with a specific node.
Definition trie.hpp:101
trie(V value, R &&range)
Constructs a trie with a given value and set of children.
Definition trie.hpp:77
std::size_t size() const
Returns the number of children in this trie.
Definition trie.hpp:245
trie set(const R &range, V value) const
Constructs a new trie with a specific value replaced.
Definition trie.hpp:193
trie drop(const K &key) const
Gets a specific subtree.
Definition trie.hpp:148
An implementation of a trie. Semantically, this corresponds to a function .
Definition trie.hpp:34
lib::effect_result_t< T > fallback(T args)
Invokes the fallback behaviour for an effect.
typename std::iterator_traits< I >::reference iter_reference_t
The return type of operator* for an iterator.
Definition base.hpp:24
lib::iter_reference_t< lib::iterator_t< R > > range_reference_t
The type returned by operator* for a range type's iterators.
Definition range.hpp:340
#define HALCHECK_REQUIRE(...)
Expands to a template argument that is only valid if the given argument evaluates to true.
Definition type_traits.hpp:24
T make_shared(T... args)
STL namespace.
Determines whether a type satisfies the LegacyInputIterator concept.
Definition type_traits.hpp:54
Determines whether a type is a range whose iterators satisfy lib::is_input_iterator.
Definition range.hpp:183
An implementation of std::is_invocable_r.
Definition invoke.hpp:54
Determines whether the given type is a range.
Definition range.hpp:158