Просмотр исходного кода

*: allocator aware classes fail to compile if allocator's value type and container's value type differ

Michele Caini 4 лет назад
Родитель
Сommit
2efaa7af7b

+ 5 - 6
src/entt/container/dense_hash_map.hpp

@@ -241,9 +241,8 @@ class dense_hash_map final {
     static constexpr float default_threshold = 0.875f;
     static constexpr std::size_t minimum_capacity = 8u;
 
-    using allocator_traits = std::allocator_traits<Allocator>;
-    using alloc = typename allocator_traits::template rebind_alloc<std::pair<const Key, Type>>;
-    using alloc_traits = typename std::allocator_traits<alloc>;
+    using alloc_traits = std::allocator_traits<Allocator>;
+    static_assert(std::is_same_v<typename alloc_traits::value_type, std::pair<const Key, Type>>);
 
     using node_type = internal::dense_hash_map_node<const Key, Type>;
     using sparse_container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;
@@ -302,14 +301,14 @@ class dense_hash_map final {
             for(; *curr != last; curr = &packed.first()[*curr].next) {}
             *curr = pos;
 
-            using node_allocator_traits = typename alloc_traits::template rebind_traits<decltype(node_type::element)>;
-            typename node_allocator_traits::allocator_type allocator = packed.first().get_allocator();
+            using node_alloc_traits = typename alloc_traits::template rebind_traits<decltype(node_type::element)>;
+            typename node_alloc_traits::allocator_type allocator = packed.first().get_allocator();
             auto *ptr = std::addressof(packed.first()[pos].element);
 
             std::destroy_at(ptr);
             packed.first()[pos].next = packed.first().back().next;
             // no exception guarantees when mapped type has a throwing move constructor (we're technically doomed)
-            node_allocator_traits::construct(allocator, ptr, std::move(packed.first().back().element));
+            node_alloc_traits::construct(allocator, ptr, std::move(packed.first().back().element));
         }
 
         packed.first().pop_back();

+ 2 - 3
src/entt/container/dense_hash_set.hpp

@@ -240,9 +240,8 @@ class dense_hash_set final {
     static constexpr float default_threshold = 0.875f;
     static constexpr std::size_t minimum_capacity = 8u;
 
-    using allocator_traits = std::allocator_traits<Allocator>;
-    using alloc = typename allocator_traits::template rebind_alloc<Type>;
-    using alloc_traits = typename std::allocator_traits<alloc>;
+    using alloc_traits = std::allocator_traits<Allocator>;
+    static_assert(std::is_same_v<typename alloc_traits::value_type, Type>);
 
     using node_type = internal::dense_hash_set_node<Type>;
     using sparse_container_type = std::vector<std::size_t, typename alloc_traits::template rebind_alloc<std::size_t>>;

+ 3 - 4
src/entt/entity/sparse_set.hpp

@@ -172,13 +172,12 @@ enum class deletion_policy : std::uint8_t {
  */
 template<typename Entity, typename Allocator>
 class basic_sparse_set {
-    using allocator_traits = std::allocator_traits<Allocator>;
-    using alloc = typename allocator_traits::template rebind_alloc<Entity>;
-    using alloc_traits = typename std::allocator_traits<alloc>;
+    using alloc_traits = std::allocator_traits<Allocator>;
+    static_assert(std::is_same_v<typename alloc_traits::value_type, Entity>);
 
     using entity_traits = entt_traits<Entity>;
     using sparse_container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
-    using packed_container_type = std::vector<Entity, alloc>;
+    using packed_container_type = std::vector<Entity, Allocator>;
 
     [[nodiscard]] auto sparse_ptr(const Entity entt) const {
         const auto pos = static_cast<size_type>(entity_traits::to_entity(entt));

+ 13 - 11
src/entt/entity/storage.hpp

@@ -36,13 +36,13 @@ class storage_iterator final {
     friend storage_iterator<const Container>;
 
     using container_type = std::remove_const_t<Container>;
-    using allocator_traits = std::allocator_traits<typename container_type::allocator_type>;
+    using alloc_traits = std::allocator_traits<typename container_type::allocator_type>;
     using comp_traits = component_traits<typename container_type::value_type>;
 
     using iterator_traits = std::iterator_traits<std::conditional_t<
         std::is_const_v<Container>,
-        typename allocator_traits::template rebind_traits<typename std::pointer_traits<typename container_type::value_type>::element_type>::const_pointer,
-        typename allocator_traits::template rebind_traits<typename std::pointer_traits<typename container_type::value_type>::element_type>::pointer>>;
+        typename alloc_traits::template rebind_traits<typename std::pointer_traits<typename container_type::value_type>::element_type>::const_pointer,
+        typename alloc_traits::template rebind_traits<typename std::pointer_traits<typename container_type::value_type>::element_type>::pointer>>;
 
 public:
     using difference_type = typename iterator_traits::difference_type;
@@ -235,12 +235,11 @@ template<typename... CLhs, typename... CRhs>
  */
 template<typename Entity, typename Type, typename Allocator, typename>
 class basic_storage: public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
-    using allocator_traits = std::allocator_traits<Allocator>;
-    using alloc = typename allocator_traits::template rebind_alloc<Type>;
-    using alloc_traits = typename std::allocator_traits<alloc>;
+    using alloc_traits = std::allocator_traits<Allocator>;
+    static_assert(std::is_same_v<typename alloc_traits::value_type, Type>);
 
     using comp_traits = component_traits<Type>;
-    using underlying_type = basic_sparse_set<Entity, typename allocator_traits::template rebind_alloc<Entity>>;
+    using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
     using container_type = std::vector<typename alloc_traits::pointer, typename alloc_traits::template rebind_alloc<typename alloc_traits::pointer>>;
 
     [[nodiscard]] auto &element_at(const std::size_t pos) const {
@@ -424,7 +423,7 @@ public:
      * @return This storage.
      */
     basic_storage &operator=(basic_storage &&other) ENTT_NOEXCEPT {
-        ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.second() == other.packed.second(), "Copying a sparse set is not allowed");
+        ENTT_ASSERT(alloc_traits::is_always_equal::value || packed.second() == other.packed.second(), "Copying a storage is not allowed");
 
         shrink_to_size(0u);
         base_type::operator=(std::move(other));
@@ -716,19 +715,22 @@ public:
     }
 
 private:
-    compressed_pair<container_type, alloc> packed;
+    compressed_pair<container_type, allocator_type> packed;
 };
 
 /*! @copydoc basic_storage */
 template<typename Entity, typename Type, typename Allocator>
 class basic_storage<Entity, Type, Allocator, std::enable_if_t<ignore_as_empty_v<Type>>>
     : public basic_sparse_set<Entity, typename std::allocator_traits<Allocator>::template rebind_alloc<Entity>> {
-    using allocator_traits = std::allocator_traits<Allocator>;
+    using alloc_traits = std::allocator_traits<Allocator>;
+    static_assert(std::is_same_v<typename alloc_traits::value_type, Type>);
+
     using comp_traits = component_traits<Type>;
+    using underlying_type = basic_sparse_set<Entity, typename alloc_traits::template rebind_alloc<Entity>>;
 
 public:
     /*! @brief Base type. */
-    using base_type = basic_sparse_set<Entity, typename allocator_traits::template rebind_alloc<Entity>>;
+    using base_type = underlying_type;
     /*! @brief Allocator type. */
     using allocator_type = Allocator;
     /*! @brief Type of the objects assigned to entities. */

+ 1 - 7
src/entt/signal/sigh.hpp

@@ -57,12 +57,6 @@ class sigh<Ret(Args...), Allocator> {
     /*! @brief A sink is allowed to modify a signal. */
     friend class sink<sigh<Ret(Args...), Allocator>>;
 
-    using allocator_traits = std::allocator_traits<Allocator>;
-    using alloc = typename allocator_traits::template rebind_alloc<delegate<Ret(Args...)>>;
-    using alloc_traits = typename std::allocator_traits<alloc>;
-
-    using container_type = std::vector<delegate<Ret(Args...)>, alloc>;
-
 public:
     /*! @brief Allocator type. */
     using allocator_type = Allocator;
@@ -221,7 +215,7 @@ public:
     }
 
 private:
-    container_type calls;
+    std::vector<delegate<Ret(Args...)>, Allocator> calls;
 };
 
 /**

+ 2 - 5
test/entt/entity/storage.cpp

@@ -1581,9 +1581,6 @@ TEST(Storage, CreateFromConstructor) {
 
 TEST(Storage, CustomAllocator) {
     auto test = [](auto pool, auto alloc) {
-        ASSERT_EQ(pool.get_allocator(), alloc);
-        ASSERT_FALSE(pool.get_allocator() != alloc);
-
         pool.reserve(1u);
 
         ASSERT_NE(pool.capacity(), 0u);
@@ -1628,8 +1625,8 @@ TEST(Storage, CustomAllocator) {
 
     test::throwing_allocator<entt::entity> allocator{};
 
-    test(entt::basic_storage<entt::entity, int, test::throwing_allocator<entt::entity>>{allocator}, allocator);
-    test(entt::basic_storage<entt::entity, std::true_type, test::throwing_allocator<entt::entity>>{allocator}, allocator);
+    test(entt::basic_storage<entt::entity, int, test::throwing_allocator<int>>{allocator}, allocator);
+    test(entt::basic_storage<entt::entity, std::true_type, test::throwing_allocator<std::true_type>>{allocator}, allocator);
 }
 
 TEST(Storage, ThrowingAllocator) {