瀏覽代碼

feature(hash_map): add begin() and end()

greatbridf 11 月之前
父節點
當前提交
059465cfd5
共有 2 個文件被更改,包括 121 次插入41 次删除
  1. 2 2
      gblibstdc++/include/list
  2. 119 39
      include/types/hash_map.hpp

+ 2 - 2
gblibstdc++/include/list

@@ -104,8 +104,8 @@ public:
         { p = p->prev; return *this; }
         constexpr _iterator operator--(int) noexcept
         { _iterator ret(p); (void)this->operator--(); return ret; }
-        constexpr operator bool() { return p; }
-        constexpr operator _iterator<true>() { return _iterator<true> { p }; }
+        constexpr operator bool() const { return p; }
+        constexpr operator _iterator<true>() const { return _iterator<true> { p }; }
     };
 
 private:

+ 119 - 39
include/types/hash_map.hpp

@@ -1,4 +1,5 @@
 #pragma once
+#include <assert.h>
 #include <list>
 #include <vector>
 #include <bit>
@@ -92,7 +93,7 @@ template <typename Key, typename Value,
     )>, bool> = true>
 class hash_map {
 public:
-    template <typename Pointer>
+    template <bool Const>
     class iterator;
 
     using key_type = std::add_const_t<Key>;
@@ -100,8 +101,8 @@ public:
     using pair_type = std::pair<key_type, value_type>;
     using size_type = size_t;
     using difference_type = ssize_t;
-    using iterator_type = iterator<pair_type*>;
-    using const_iterator_type = iterator<const pair_type*>;
+    using iterator_type = iterator<false>;
+    using const_iterator_type = iterator<true>;
 
     using bucket_type = std::list<pair_type, Allocator>;
     using bucket_array_type = std::vector<bucket_type, typename
@@ -112,40 +113,50 @@ public:
     static constexpr size_type INITIAL_BUCKETS_ALLOCATED = 64;
 
 public:
-    template <typename Pointer>
+    template <bool Const>
     class iterator {
     public:
-        using _Value = std::remove_pointer_t<Pointer>;
-        using Reference = std::add_lvalue_reference_t<_Value>;
+        using bucket_iterator = std::conditional_t<Const,
+              typename bucket_type::const_iterator,
+              typename bucket_type::iterator>;
+        using _Value = typename bucket_iterator::value_type;
+        using Pointer = typename bucket_iterator::pointer;
+        using Reference = typename bucket_iterator::reference;
+        using hash_map_pointer = std::conditional_t<Const,
+              const hash_map*, hash_map*>;
 
         friend class hash_map;
 
     public:
         constexpr iterator(const iterator& iter) noexcept
-            : p(iter.p)
+            : n(iter.n), iter(iter.iter), hmap(iter.hmap)
         {
         }
 
         constexpr iterator(iterator&& iter) noexcept
-            : p(iter.p)
+            : n(std::exchange(iter.n, 0))
+            , iter(std::move(iter.iter))
+            , hmap(std::exchange(iter.hmap, nullptr))
         {
-            iter.p = nullptr;
         }
 
         constexpr iterator& operator=(const iterator& iter)
         {
-            p = iter.p;
+            n = iter.n;
+            this->iter = iter.iter;
+            hmap = iter.hmap;
             return *this;
         }
 
-        explicit constexpr iterator(Pointer p) noexcept
-            : p(p)
+        explicit constexpr iterator(std::size_t n, bucket_iterator iter,
+                hash_map_pointer hmap) noexcept
+            : n(n), iter(iter), hmap(hmap)
         {
         }
 
         constexpr bool operator==(const iterator& iter) const noexcept
         {
-            return this->p == iter.p;
+            return (!*this && !iter) || (hmap == iter.hmap && n == iter.n && this->iter == iter.iter);
         }
 
         constexpr bool operator!=(const iterator& iter) const noexcept
@@ -153,22 +164,54 @@ public:
             return !(*this == iter);
         }
 
-        constexpr operator bool(void)
+        constexpr iterator operator++()
         {
-            return p != nullptr;
+            assert((bool)*this);
+
+            ++iter;
+            while (iter == hmap->buckets[n].end()) {
+                ++n;
+                if (n < hmap->buckets.size())
+                    iter = hmap->buckets[n].begin();
+                else
+                    break;
+            }
+
+            return *this;
+        }
+
+        constexpr iterator operator++(int)
+        {
+            iterator ret { *this };
+
+            (void)this->operator++();
+
+            return ret;
+        }
+
+        constexpr operator bool(void) const
+        {
+            return hmap && n < hmap->buckets.size() && !!iter;
         }
 
         constexpr Reference operator*(void) const noexcept
         {
-            return *p;
+            return *iter;
         }
         constexpr Pointer operator->(void) const noexcept
         {
-            return p;
+            return &*iter;
+        }
+
+        constexpr operator const_iterator_type() const noexcept
+        {
+            return const_iterator_type(n, iter, hmap);
         }
 
     protected:
-        Pointer p;
+        std::size_t n;
+        bucket_iterator iter;
+        hash_map_pointer hmap;
     };
 
 private:
@@ -219,38 +262,35 @@ public:
         emplace(std::make_pair(std::forward<_key_type>(key), std::forward<_value_type>(value)));
     }
 
-    constexpr void remove(const key_type& key)
+    constexpr void remove(const_iterator_type iter)
     {
-        auto hash_value = hasher_type::hash(key, hash_length());
-        auto& bucket = buckets.at(hash_value);
-        for (auto iter = bucket.begin(); iter != bucket.end(); ++iter) {
-            if (iter->first == key) {
-                bucket.erase(iter);
-                return;
-            }
-        }
+        auto& bucket = buckets[iter.n];
+        bucket.erase(iter.iter);
     }
 
     constexpr void remove(iterator_type iter)
     {
-        remove(iter->first);
-        iter.p = nullptr;
+        return remove((const_iterator_type)iter);
     }
-    constexpr void remove(const_iterator_type iter)
+
+    constexpr void remove(const key_type& key)
     {
-        remove(iter->first);
-        iter.p = nullptr;
+        const_iterator_type iter = find(key);
+        if (!iter)
+            return;
+
+        remove(iter);
     }
 
     constexpr iterator_type find(const key_type& key)
     {
         auto hash_value = hasher_type::hash(key, hash_length());
         auto& bucket = buckets.at(hash_value);
-        for (auto& item : bucket) {
-            if (key == item.first)
-                return iterator_type(&item);
+        for (auto iter = bucket.begin(); iter != bucket.end(); ++iter) {
+            if (key == iter->first)
+                return iterator_type(hash_value, iter, this);
         }
-        return iterator_type(nullptr);
+        return this->end();
     }
 
     constexpr const_iterator_type find(const key_type& key) const
@@ -258,10 +298,10 @@ public:
         auto hash_value = hasher_type::hash(key, hash_length());
         const auto& bucket = buckets.at(hash_value);
         for (auto iter = bucket.cbegin(); iter != bucket.cend(); ++iter) {
-            if (key == iter->key)
-                return const_iterator_type(&iter);
+            if (key == iter->first)
+                return const_iterator_type(hash_value, iter, this);
         }
-        return const_iterator_type(nullptr);
+        return this->cend();
     }
 
     constexpr void clear(void)
@@ -269,6 +309,46 @@ public:
         for (auto& bucket : buckets)
             bucket.clear();
     }
+
+    constexpr const_iterator_type cend() const noexcept
+    {
+        return const_iterator_type(buckets.size(), buckets[0].end(), this);
+    }
+
+    constexpr const_iterator_type end() const noexcept
+    {
+        return cend();
+    }
+
+    constexpr iterator_type end() noexcept
+    {
+        return iterator_type(buckets.size(), buckets[0].end(), this);
+    }
+
+    constexpr const_iterator_type cbegin() const noexcept
+    {
+        for (std::size_t i = 0; i < buckets.size(); ++i) {
+            if (buckets[i].empty())
+                continue;
+            return const_iterator_type(i, buckets[i].begin(), this);
+        }
+        return cend();
+    }
+
+    constexpr const_iterator_type begin() const noexcept
+    {
+        return cbegin();
+    }
+
+    constexpr iterator_type begin() noexcept
+    {
+        for (std::size_t i = 0; i < buckets.size(); ++i) {
+            if (buckets[i].empty())
+                continue;
+            return iterator_type(i, buckets[i].begin(), this);
+        }
+        return end();
+    }
 };
 
 } // namespace types