瀏覽代碼

feat(concept): add concept Hasher and Allocator

greatbridf 2 年之前
父節點
當前提交
03b2aadd9f
共有 3 個文件被更改,包括 82 次插入36 次删除
  1. 18 5
      include/types/allocator.hpp
  2. 41 7
      include/types/cplusplus.hpp
  3. 23 24
      include/types/hash_map.hpp

+ 18 - 5
include/types/allocator.hpp

@@ -1,6 +1,7 @@
 #pragma once
 #include <kernel/mem.h>
 #include <types/cplusplus.hpp>
+#include <types/stdint.h>
 #include <types/types.h>
 
 inline void* operator new(size_t, void* ptr)
@@ -10,7 +11,19 @@ inline void* operator new(size_t, void* ptr)
 
 namespace types {
 
-template <typename Allocator>
+template <typename T>
+concept Allocator = requires(size_t size, typename T::value_type* ptr)
+{
+    typename T::value_type;
+    {
+        T::allocate_memory(size)
+        } -> same_as<typename T::value_type*>;
+    {
+        T::deallocate_memory(ptr)
+        } -> same_as<void>;
+};
+
+template <Allocator T>
 class allocator_traits;
 
 template <typename T>
@@ -57,16 +70,16 @@ T* kernel_ident_allocator_new(Args&&... args)
     return allocator_traits<kernel_ident_allocator<T>>::allocate_and_construct(forward<Args>(args)...);
 }
 
-template <typename Allocator>
+template <Allocator _allocator>
 class allocator_traits {
 public:
-    using value_type = typename Allocator::value_type;
+    using value_type = typename _allocator::value_type;
 
     static value_type* allocate(size_t count)
     {
         if (count == 0)
             return nullptr;
-        return Allocator::allocate_memory(sizeof(value_type) * count);
+        return _allocator::allocate_memory(sizeof(value_type) * count);
     }
 
     template <typename... Args>
@@ -95,7 +108,7 @@ public:
     {
         if (!ptr)
             return;
-        Allocator::deallocate_memory(ptr);
+        _allocator::deallocate_memory(ptr);
     }
 
     static void deconstruct_and_deallocate(value_type* ptr)

+ 41 - 7
include/types/cplusplus.hpp

@@ -1,7 +1,20 @@
 #pragma once
 
+#include <types/stdint.h>
+
 #ifdef __cplusplus
 
+namespace types {
+
+template <typename T, T _value>
+struct constant_value {
+    static constexpr T value = _value;
+};
+using true_type = constant_value<bool, true>;
+using false_type = constant_value<bool, false>;
+
+};
+
 namespace types::traits::inner {
 
 template <typename Tp, typename>
@@ -65,6 +78,14 @@ struct remove_cv<const volatile T> {
     using type = T;
 };
 
+template <typename T>
+struct is_pointer : false_type {
+};
+
+template <typename T>
+struct is_pointer<T*> : true_type {
+};
+
 template <typename T>
 struct decay {
 private:
@@ -88,13 +109,6 @@ T&& forward(typename traits::remove_reference<T>::type& val)
     return static_cast<T&&>(val);
 }
 
-template <typename T, T _value>
-struct constant_value {
-    static constexpr T value = _value;
-};
-using true_type = constant_value<bool, true>;
-using false_type = constant_value<bool, false>;
-
 template <typename>
 struct template_true_type : public true_type {
 };
@@ -110,6 +124,26 @@ template <typename T>
 struct is_same<T, T> : true_type {
 };
 
+template <typename T>
+struct add_rvalue_reference {
+    using type = T&&;
+};
+template <>
+struct add_rvalue_reference<void> {
+    using type = void;
+};
+
+template <typename Src, typename Dst>
+concept convertible_to = (traits::is_pointer<Src>::value && is_same<Dst, uint32_t>::value)
+    || (traits::is_pointer<Dst>::value && is_same<Src, uint32_t>::value)
+    || requires(Src _src)
+{
+    { static_cast<Dst>(_src) };
+};
+
+template <typename A, typename B>
+concept same_as = is_same<A, B>::value;
+
 } // namespace types
 
 #endif

+ 23 - 24
include/types/hash_map.hpp

@@ -14,28 +14,29 @@ namespace types {
 constexpr uint32_t GOLDEN_RATIO_32 = 0x61C88647;
 // constexpr uint64_t GOLDEN_RATIO_64 = 0x61C8864680B583EBull;
 
-static constexpr uint32_t _hash32(uint32_t val)
+using hash_t = size_t;
+
+static inline constexpr hash_t _hash32(uint32_t val)
 {
     return val * GOLDEN_RATIO_32;
 }
 
-static constexpr uint32_t hash32(uint32_t val, uint32_t bits)
+static inline constexpr hash_t hash32(uint32_t val, uint32_t bits)
 {
     // higher bits are more random
     return _hash32(val) >> (32 - bits);
 }
 
-template <typename T>
+template <convertible_to<uint32_t> T>
 struct linux_hasher {
-    static constexpr uint32_t hash(const T& val, uint32_t bits)
+    static inline constexpr hash_t hash(T val, uint32_t bits)
     {
-        return hash32(val, bits);
+        return hash32(static_cast<uint32_t>(val), bits);
     }
 };
-
 template <typename T>
 struct linux_hasher<T*> {
-    static constexpr uint32_t hash(T* val, uint32_t bits)
+    static inline constexpr hash_t hash(T* val, uint32_t bits)
     {
         return hash32(reinterpret_cast<uint32_t>(val), bits);
     }
@@ -43,15 +44,15 @@ struct linux_hasher<T*> {
 
 template <typename T>
 struct string_hasher {
-    static constexpr uint32_t hash(T, uint32_t)
+    static inline constexpr hash_t hash(T, uint32_t)
     {
         static_assert(types::template_false_type<T>::value, "string hasher does not support this type");
-        return (uint32_t)0;
+        return (hash_t)0;
     }
 };
 template <>
 struct string_hasher<const char*> {
-    static constexpr uint32_t hash(const char* str, uint32_t bits)
+    static inline constexpr hash_t hash(const char* str, uint32_t bits)
     {
         constexpr uint32_t seed = 131;
         uint32_t hash = 0;
@@ -64,7 +65,7 @@ struct string_hasher<const char*> {
 };
 template <template <typename> class Allocator>
 struct string_hasher<const types::string<Allocator>&> {
-    static inline constexpr uint32_t hash(const types::string<Allocator>& str, uint32_t bits)
+    static inline constexpr hash_t hash(const types::string<Allocator>& str, uint32_t bits)
     {
         return string_hasher<const char*>::hash(str.c_str(), bits);
     }
@@ -77,17 +78,15 @@ struct string_hasher<types::string<Allocator>&&> {
     }
 };
 
-template <class Hasher, typename Value>
-struct hasher_traits {
-    using hash_t = size_t;
-    using length_t = size_t;
-    static constexpr hash_t hash(Value val, length_t bits)
+template <typename _Hasher, typename Value>
+concept Hasher = requires(Value&& val, uint32_t bits)
+{
     {
-        return Hasher::hash(val, bits);
-    }
+        _Hasher::hash(val, bits)
+        } -> convertible_to<size_t>;
 };
 
-template <typename Key, typename Value, typename Hasher, template <typename _T> class Allocator = types::kernel_allocator>
+template <typename Key, typename Value, Hasher<Key> _Hasher, template <typename _T> class Allocator = types::kernel_allocator>
 class hash_map {
 public:
     struct pair;
@@ -227,12 +226,12 @@ public:
 
     void insert(const pair& p)
     {
-        auto hash_value = hasher_traits<Hasher, key_type>::hash(p.key, hash_length());
+        auto hash_value = _Hasher::hash(p.key, hash_length());
         buckets.at(hash_value).push_back(p);
     }
     void insert(pair&& p)
     {
-        auto hash_value = hasher_traits<Hasher, key_type>::hash(p.key, hash_length());
+        auto hash_value = _Hasher::hash(p.key, hash_length());
         buckets.at(hash_value).push_back(move(p));
     }
     void insert(const key_type& key, const value_type& val)
@@ -242,7 +241,7 @@ public:
 
     void remove(const key_type& key)
     {
-        auto hash_value = hasher_traits<Hasher, key_type>::hash(key, hash_length());
+        auto hash_value = _Hasher::hash(key, hash_length());
         auto& bucket = buckets.at(hash_value);
         for (auto iter = bucket.begin(); iter != bucket.end(); ++iter) {
             if (iter->key == key) {
@@ -254,7 +253,7 @@ public:
 
     iterator_type find(const key_type& key)
     {
-        auto hash_value = hasher_traits<Hasher, key_type>::hash(key, hash_length());
+        auto hash_value = _Hasher::hash(key, hash_length());
         auto& bucket = buckets.at(hash_value);
         for (auto& item : bucket) {
             if (key == item.key)
@@ -265,7 +264,7 @@ public:
 
     const_iterator_type find(const key_type& key) const
     {
-        auto hash_value = hasher_traits<Hasher, key_type>::hash(key, hash_length());
+        auto hash_value = _Hasher::hash(key, hash_length());
         const auto& bucket = buckets.at(hash_value);
         for (const auto& item : bucket) {
             if (key == item.key)