|
|
@@ -10,12 +10,6 @@
|
|
|
#include "trie.hpp"
|
|
|
#include "trie_iterator.hpp"
|
|
|
|
|
|
-template <typename K, typename V, typename C>
|
|
|
-trie<K, V, C>::trie(mapped_type const & value)
|
|
|
-: value_(value) {
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
// n := total elements
|
|
|
// d := average depth
|
|
|
// Stack: O(1)
|
|
|
@@ -30,11 +24,6 @@ trie<K, V, C>::trie(trie const & other) : value_(other.value_) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-template <typename K, typename V, typename C>
|
|
|
-trie<K, V, C>::~trie() {
|
|
|
- clear();
|
|
|
-}
|
|
|
-
|
|
|
template <typename K, typename V, typename C>
|
|
|
auto trie<K, V, C>::operator=(mapped_type const & value) -> self_t & {
|
|
|
value_ = value;
|
|
|
@@ -48,39 +37,15 @@ auto trie<K, V, C>::operator=(trie const & other) -> self_t & {
|
|
|
return *this;
|
|
|
}
|
|
|
|
|
|
-// n := total elements
|
|
|
-// d := average depth
|
|
|
-// Operations: O(d*log(n/d))
|
|
|
template <typename K, typename V, typename C>
|
|
|
-template <typename KS, typename>
|
|
|
-auto trie<K, V, C>::operator[](KS const & keys) -> self_t & {
|
|
|
- self_t * rec = this;
|
|
|
- for ( key_type const & key : keys ) {
|
|
|
- rec = &(*rec)[key];
|
|
|
- }
|
|
|
- return *rec;
|
|
|
-}
|
|
|
-
|
|
|
-// n := total elements
|
|
|
-// d := average depth
|
|
|
-// Operations: O(log(n))
|
|
|
-template <typename K, typename V, typename C>
|
|
|
-auto trie<K, V, C>::operator[](key_type const & key) -> self_t & {
|
|
|
- auto it = impl_.lower_bound(key);
|
|
|
- if ( it == impl_.end() || key_compare()(key, it->first) ) {
|
|
|
- it = impl_.emplace_hint(it, key, make_value<self_t>());
|
|
|
- }
|
|
|
- return *(it->second);
|
|
|
+auto trie<K, V, C>::operator=(trie && other) -> self_t & {
|
|
|
+ swap(*this, other);
|
|
|
+ return *this;
|
|
|
}
|
|
|
|
|
|
// n := total elements
|
|
|
// d := average depth
|
|
|
-// Operations: O(d*log(n/d))
|
|
|
-template <typename K, typename V, typename C>
|
|
|
-auto trie<K, V, C>::operator[](std::initializer_list<key_type> keys) -> self_t & {
|
|
|
- return operator[]<std::initializer_list<key_type>>(keys);
|
|
|
-}
|
|
|
-
|
|
|
+// Operations: O(log(n)/d)
|
|
|
template <typename K, typename V, typename C>
|
|
|
template <typename... Args>
|
|
|
void trie<K, V, C>::insert_impl(std::pair<iterator, bool> & out, key_type const & key, Args &&... args) {
|
|
|
@@ -92,30 +57,53 @@ void trie<K, V, C>::insert_impl(std::pair<iterator, bool> & out, key_type const
|
|
|
out.first.push(make_end_aware_iterator(it, impl_.end()));
|
|
|
}
|
|
|
|
|
|
+// n := total elements
|
|
|
+// d := average depth
|
|
|
+// Operations: O(log(n))
|
|
|
template <typename K, typename V, typename C>
|
|
|
template <typename KS>
|
|
|
auto trie<K, V, C>::insert(KS const & keys, mapped_type const & value) -> std::pair<iterator, bool> {
|
|
|
std::pair<iterator, bool> rval{this, false};
|
|
|
- auto size = std::distance(std::begin(keys), std::end(keys));
|
|
|
for ( key_type const & key : keys ) {
|
|
|
- if (size-- == 1) { insert_impl(rval, key, value); }
|
|
|
- else { insert_impl(rval, key); }
|
|
|
+ rval.first.stk.top()->insert_impl(rval, key);
|
|
|
}
|
|
|
+ if (rval.second) { *rval.first.stk.top() = value; }
|
|
|
return rval;
|
|
|
}
|
|
|
|
|
|
-template <typename K, typename V, typename C>
|
|
|
-auto trie<K, V, C>::insert(std::initializer_list<key_type> keys, mapped_type const & value) -> std::pair<iterator, bool> {
|
|
|
- return insert<std::initializer_list<key_type>>(keys, value);
|
|
|
-}
|
|
|
-
|
|
|
// n := total elements
|
|
|
// d := average depth
|
|
|
// Operations: O(log(n))
|
|
|
template <typename K, typename V, typename C>
|
|
|
-auto trie<K, V, C>::insert(key_type const & key, mapped_type const & value) -> std::pair<iterator, bool> {
|
|
|
+template <typename KS, typename... Args>
|
|
|
+auto trie<K, V, C>::emplace(KS const & keys, Args &&... args) -> std::pair<iterator, bool> {
|
|
|
std::pair<iterator, bool> rval{this, false};
|
|
|
- insert_impl(rval, key, value);
|
|
|
+ for ( key_type const & key : keys ) {
|
|
|
+ rval.first.stk.top()->insert_impl(rval, key);
|
|
|
+ }
|
|
|
+ if (rval.second) { rval.first.stk.top()->value() = {std::forward<Args>(args)...}; }
|
|
|
+ return rval;
|
|
|
+}
|
|
|
+
|
|
|
+template <typename K, typename V, typename C>
|
|
|
+template <typename KS>
|
|
|
+auto trie<K, V, C>::find(KS const & keys) -> iterator {
|
|
|
+ iterator rval{this};
|
|
|
+ for (auto & key : keys) {
|
|
|
+ auto & top = rval.stk.top()->impl_;
|
|
|
+ auto it = top.find(key), end = top.end();
|
|
|
+ if ( it == end ) { return {}; }
|
|
|
+ rval.push({it, end});
|
|
|
+ }
|
|
|
+ return rval;
|
|
|
+}
|
|
|
+
|
|
|
+template <typename K, typename V, typename C>
|
|
|
+auto trie<K, V, C>::find(key_type const & key) -> iterator {
|
|
|
+ auto it = impl_.find(key), end = impl_.end();
|
|
|
+ if ( it == end ) { return {}; }
|
|
|
+ iterator rval{this};
|
|
|
+ rval.push({it, end});
|
|
|
return rval;
|
|
|
}
|
|
|
|
|
|
@@ -132,3 +120,14 @@ void trie<K, V, C>::clear() {
|
|
|
value_ = mapped_type{};
|
|
|
impl_.clear();
|
|
|
}
|
|
|
+
|
|
|
+template <typename K, typename V, typename C>
|
|
|
+void trie<K, V, C>::drop(iterator it) {
|
|
|
+ if (it == end()) return;
|
|
|
+ it.stk.top()->clear();
|
|
|
+ if (!it.iters.empty()) {
|
|
|
+ auto to_erase = it.iters.top().current();
|
|
|
+ it.pop();
|
|
|
+ it.stk.top()->impl_.erase(to_erase);
|
|
|
+ }
|
|
|
+}
|