Browse Source

Cherry picking good change fragments from optional branch

Samuel Jaffe 8 years ago
parent
commit
9ae406f017
3 changed files with 66 additions and 68 deletions
  1. 41 25
      trie.hpp
  2. 16 37
      trie_impl.hpp
  3. 9 6
      trie_iterator.hpp

+ 41 - 25
trie.hpp

@@ -15,6 +15,11 @@
 template <typename K, typename V, typename Compare = std::less<K>>
 class trie;
 
+namespace detail {
+  template <typename Trie, typename Iter>
+  class trie_iterator_base;
+}
+
 template <typename Trie, typename Iter>
 class trie_iterator;
 template <typename Trie, typename Iter>
@@ -45,9 +50,10 @@ public:
   using const_post_iterator = trie_iterator<self_t const, local_const_reverse_iterator>;
   using reverse_iterator = trie_reverse_iterator<self_t, local_reverse_iterator>;
   using const_reverse_iterator = trie_reverse_iterator<self_t const,  local_const_reverse_iterator>;
+private:
+  using impl_iterator = detail::trie_iterator_base<self_t, local_iterator>;
 public:
-  trie() : value_() {}
-  trie(mapped_type const & value) : value_(value) {}
+  trie() {}
   trie(trie const & other);
   trie(trie && other) { swap(other); }
   ~trie() { clear(); }
@@ -55,8 +61,8 @@ public:
   self_t & operator=(trie const & value);
   self_t & operator=(trie && value);
 
-  operator mapped_type &() { return value_; }
-  operator mapped_type const &() const { return value_; }
+  operator mapped_type &() { return value(); }
+  operator mapped_type const &() const { return value(); }
   mapped_type & value() { return value_; }
   mapped_type const & value() const { return value_; }
   
@@ -72,22 +78,26 @@ public:
   }
   
   template <typename KS>
-  std::pair<iterator, bool> insert(KS const & keys, mapped_type const & value);
+  std::pair<iterator, bool> insert(KS const & keys, mapped_type const & value) {
+    return emplace_impl(keys, value);
+  }
   std::pair<iterator, bool> insert(key_type const & key, mapped_type const & value) {
-    return insert({key}, value);
+    return emplace_impl({key}, value);
   }
   std::pair<iterator, bool> insert(std::initializer_list<key_type> keys, mapped_type const & value) {
-    return insert<std::initializer_list<key_type>>(keys, value);
+    return emplace_impl(keys, value);
   }
   template <typename KS, typename... Args>
-  std::pair<iterator, bool> emplace(KS const & keys, Args &&... args);
+  std::pair<iterator, bool> emplace(KS const & keys, Args &&... args) {
+    return emplace_impl(keys, std::forward<Args>(args)...);
+  }
   template <typename... Args>
   std::pair<iterator, bool> emplace(key_type const & key, Args &&... args) {
-    return emplace({key}, std::forward<Args>(args)...);
+    return emplace_impl({key}, std::forward<Args>(args)...);
   }
   template <typename... Args>
   std::pair<iterator, bool> emplace(std::initializer_list<key_type> keys, Args &&... args) {
-    return emplace<std::initializer_list<key_type>>(keys, std::forward<Args>(args)...);
+    return emplace_impl(keys, std::forward<Args>(args)...);
   }
   
   iterator begin() { return {this}; }
@@ -115,31 +125,36 @@ public:
   
   
   template <typename KS>
-  iterator find(KS const & keys);
-  iterator find(key_type const & key);
-  iterator find(std::initializer_list<key_type> keys) {
-    return find<std::initializer_list<key_type>>(keys);
-  }
+  iterator find(KS const & keys) { return find_impl(keys); }
+  iterator find(key_type const & key) { return find_impl({key}); }
+  iterator find(std::initializer_list<key_type> keys) { return find_impl(keys); }
   
   template <typename KS>
   void erase(KS const & keys) { drop(find(keys)); }
   void erase(key_type const & key) { drop(find(key)); }
-  void erase(std::initializer_list<key_type> keys) {
-    erase<std::initializer_list<key_type>>(keys);
-  }
+  void erase(std::initializer_list<key_type> keys) { drop(find(keys)); }
   
   void clear();
 private:
   void drop(iterator it);
+  template <typename KS>
+  impl_iterator find_impl(KS const & keys);
+  impl_iterator find_impl(std::initializer_list<key_type> keys) {
+    return find_impl<std::initializer_list<key_type>>(keys);
+  }
+  template <typename KS, typename... Args>
+  std::pair<impl_iterator, bool> emplace_impl(KS const & keys, Args &&... args);
   template <typename... Args>
-  void insert_impl(std::pair<iterator, bool> & out, key_type const & key, Args &&... args);
+  std::pair<impl_iterator, bool> emplace_impl(std::initializer_list<key_type> key, Args &&... args) {
+    return emplace_impl<std::initializer_list<key_type>>(key, std::forward<Args>(args)...);
+  }
+  void insert_impl(impl_iterator & out, bool & create, key_type const & key);
   
   friend bool operator==(trie const & lhs, trie const & rhs) {
-    if (lhs.value() != rhs.value()) { return false; }
-    auto it1 = ++lhs.begin(), it2 = ++rhs.begin(), end1 = lhs.end(), end2 = lhs.end();
+    auto it1 = lhs.begin(), it2 = rhs.begin(), end1 = lhs.end(), end2 = lhs.end();
     for ( ; it1 != end1 && it2 != end2; ++it1, ++it2 ) {
-      if (it1.keys.back() != it2.keys.back()) { return false; }
-      else if (*it1 != *it2) { return false; }
+      if (!it1.keys.empty() && !it2.keys.empty() && it1.keys.back() != it2.keys.back()) { return false; }
+      else if (it1.stk.top()->value_ != it2.stk.top()->value_) { return false; }
     }
     return it1 == end1 && it2 == end2;
   }
@@ -148,8 +163,9 @@ private:
     swap(lhs.value_, rhs.value_);
     swap(lhs.impl_, rhs.impl_);
   }
-  mapped_type value_;
-  backing_t impl_;
+  
+  mapped_type value_{};
+  backing_t impl_{};
 };
 
 #include "trie_impl.hpp"

+ 16 - 37
trie_impl.hpp

@@ -16,8 +16,8 @@
 // Operations: O(n)
 template <typename K, typename V, typename C>
 trie<K, V, C>::trie(trie const & other) : value_(other.value_) {
-  iterator current{this};
-  for (const_iterator it = ++other.begin(), end = other.end(); it != end; ++it) {
+  impl_iterator current{this};
+  for (const_iterator it = ++const_iterator{&other}, end = {}; it != end; ++it) {
     while (current.keys.size() >= it.keys.size()) { current.pop(); }
     auto tmp = current.stk.top()->insert(it.keys.back(), *it).first;
     current.push(tmp.iters.top());
@@ -47,28 +47,13 @@ auto trie<K, V, C>::operator=(trie && other) -> self_t & {
 // d := average depth
 // 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) {
+void trie<K, V, C>::insert_impl(impl_iterator & out, bool & create, key_type const & key) {
   auto it = impl_.lower_bound(key);
   if ( it == impl_.end() || key_compare()(key, it->first) ) {
-    out.second = true;
-    it = impl_.emplace_hint(it, key, make_value<self_t>(std::forward<Args>(args)...));
+    create = true;
+    it = impl_.emplace_hint(it, key, make_value<self_t>());
   }
-  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};
-  for ( key_type const & key : keys ) {
-    rval.first.stk.top()->insert_impl(rval, key);
-  }
-  if (rval.second) { *rval.first.stk.top() = value; }
-  return rval;
+  out.push({ it, impl_.end() });
 }
 
 // n := total elements
@@ -76,19 +61,22 @@ auto trie<K, V, C>::insert(KS const & keys, mapped_type const & value) -> std::p
 // Operations: O(log(n))
 template <typename K, typename V, typename C>
 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};
+auto trie<K, V, C>::emplace_impl(KS const & keys, Args &&... args) -> std::pair<impl_iterator, bool> {
+  impl_iterator it{this};
+  bool create{false};
   for ( key_type const & key : keys ) {
-    rval.first.stk.top()->insert_impl(rval, key);
+    it.stk.top()->insert_impl(it, create, key);
   }
-  if (rval.second) { rval.first.stk.top()->value() = {std::forward<Args>(args)...}; }
-  return rval;
+  if (create) {
+    it.stk.top()->value_ = { std::forward<Args>(args)... };
+  }
+  return { std::move(it) , create };
 }
 
 template <typename K, typename V, typename C>
 template <typename KS>
-auto trie<K, V, C>::find(KS const & keys) -> iterator {
-  iterator rval{this};
+auto trie<K, V, C>::find_impl(KS const & keys) -> impl_iterator {
+  impl_iterator rval{this};
   for (auto & key : keys) {
     auto & top = rval.stk.top()->impl_;
     auto it = top.find(key), end = top.end();
@@ -98,15 +86,6 @@ auto trie<K, V, C>::find(KS const & keys) -> iterator {
   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;
-}
-
 // n := total elements
 // d := average depth
 // Stack: O(1)

+ 9 - 6
trie_iterator.hpp

@@ -15,16 +15,16 @@
 namespace detail {
   template <typename Iter>
   struct trie_iterator_next {
-    template <typename Trie>
-    ::iterator::end_aware_iterator<Iter> operator()(Trie & tr) {
+    using iter_t = ::iterator::end_aware_iterator<Iter>;
+    template <typename Trie> iter_t operator()(Trie & tr) {
       return { tr.local_begin(), tr.local_end() };
     }
   };
 
   template <typename Iter>
   struct trie_iterator_next<std::reverse_iterator<Iter>> {
-    template <typename Trie>
-    ::iterator::end_aware_iterator<std::reverse_iterator<Iter>> operator()(Trie & tr) {
+    using iter_t = ::iterator::end_aware_iterator<std::reverse_iterator<Iter>>;
+    template <typename Trie> iter_t operator()(Trie & tr) {
       return { tr.local_rbegin(), tr.local_rend() };
     }
   };
@@ -32,7 +32,8 @@ namespace detail {
   template <typename Trie, typename Iter>
   class trie_iterator_base {
   protected:
-    using impl_t = ::iterator::end_aware_iterator<Iter>;
+    using helper = trie_iterator_next<Iter>;
+    using impl_t = typename helper::iter_t;
     std::stack<Trie *> stk;
     std::list<typename Trie::key_type> keys;
     std::stack<impl_t> iters;
@@ -64,7 +65,7 @@ namespace detail {
     }
     bool can_recurse() { return !next().done(); }
     void recurse() { push(next()); }
-    impl_t next() { return detail::trie_iterator_next<Iter>()(*stk.top()); }
+    impl_t next() { return helper()(*stk.top()); }
     friend bool operator!=(trie_iterator_base const & lhs, trie_iterator_base const & rhs) {
       return !(lhs == rhs);
     }
@@ -74,6 +75,7 @@ namespace detail {
       else if ( lhs.done != rhs.done ) return false;
       else return *lhs == *rhs;
     }
+    friend Trie;
   };
 }
 
@@ -90,6 +92,7 @@ public:
 public:
   trie_iterator() : super() {}
   trie_iterator(Trie * tr) : super(tr) { }
+  trie_iterator(super && take) : super(std::move(take)) { }
   trie_iterator & operator++() {
     if (super::done) return *this;
     if ( super::iters.empty() || super::can_recurse() ) { super::recurse(); }