Browse Source

storage: store aside a compressed allocator to avoid frequent conversions

Michele Caini 4 years ago
parent
commit
6d45ac942d
1 changed files with 30 additions and 28 deletions
  1. 30 28
      src/entt/entity/storage.hpp

+ 30 - 28
src/entt/entity/storage.hpp

@@ -10,6 +10,7 @@
 #include <utility>
 #include "../config/config.h"
 #include "../core/algorithm.hpp"
+#include "../core/compressed_pair.hpp"
 #include "../core/fwd.hpp"
 #include "../core/type_traits.hpp"
 #include "../signal/sigh.hpp"
@@ -179,38 +180,38 @@ class basic_storage_impl: public basic_sparse_set<Entity, typename std::allocato
 
     void release_memory() {
         if(packed) {
-            alloc allocator{get_allocator()};
+            auto &&[allocator, len] = bucket;
             alloc_ptr ptr_allocator{allocator};
 
             // no-throw stable erase iteration
             underlying_type::clear();
 
-            for(size_type pos{}; pos < bucket; ++pos) {
+            for(size_type pos{}; pos < len; ++pos) {
                 alloc_traits::deallocate(allocator, packed[pos], packed_page);
                 alloc_ptr_traits::destroy(ptr_allocator, std::addressof(packed[pos]));
             }
 
-            alloc_ptr_traits::deallocate(ptr_allocator, packed, bucket);
+            alloc_ptr_traits::deallocate(ptr_allocator, packed, len);
         }
     }
 
     void assure_at_least(const std::size_t last) {
-        if(const auto idx = page(last - 1u); !(idx < bucket)) {
-            alloc allocator{get_allocator()};
+        if(const auto idx = page(last - 1u); !(idx < bucket.second())) {
+            auto &&[allocator, len] = bucket;
             alloc_ptr ptr_allocator{allocator};
 
             const size_type sz = idx + 1u;
             const auto mem = alloc_ptr_traits::allocate(ptr_allocator, sz);
-            std::uninitialized_copy(packed, packed + bucket, mem);
+            std::uninitialized_copy(packed, packed + len, mem);
             size_type pos{};
 
             ENTT_TRY {
-                for(pos = bucket; pos < sz; ++pos) {
+                for(pos = len; pos < sz; ++pos) {
                     auto pg = alloc_traits::allocate(allocator, packed_page);
                     alloc_ptr_traits::construct(ptr_allocator, std::addressof(mem[pos]), pg);
                 }
             } ENTT_CATCH {
-                for(auto next = bucket; next < pos; ++next) {
+                for(auto next = len; next < pos; ++next) {
                     alloc_traits::deallocate(allocator, mem[next], packed_page);
                 }
 
@@ -219,50 +220,51 @@ class basic_storage_impl: public basic_sparse_set<Entity, typename std::allocato
                 ENTT_THROW;
             }
 
-            std::destroy(packed, packed + bucket);
-            alloc_ptr_traits::deallocate(ptr_allocator, packed, bucket);
+            std::destroy(packed, packed + len);
+            alloc_ptr_traits::deallocate(ptr_allocator, packed, len);
 
             packed = mem;
-            bucket = sz;
+            len = sz;
         }
     }
 
     void release_unused_pages() {
-        if(const auto length = underlying_type::size() / packed_page; length < bucket) {
-            alloc allocator{get_allocator()};
+        if(const auto length = underlying_type::size() / packed_page; length < bucket.second()) {
+            auto &&[allocator, len] = bucket;
             alloc_ptr ptr_allocator{allocator};
 
             const auto mem = alloc_ptr_traits::allocate(ptr_allocator, length);
             std::uninitialized_copy(packed, packed + length, mem);
 
-            for(auto pos = length; pos < bucket; ++pos) {
+            for(auto pos = length; pos < len; ++pos) {
                 alloc_traits::deallocate(allocator, packed[pos], packed_page);
                 alloc_ptr_traits::destroy(ptr_allocator, std::addressof(packed[pos]));
             }
 
-            alloc_ptr_traits::deallocate(ptr_allocator, packed, bucket);
+            alloc_ptr_traits::deallocate(ptr_allocator, packed, len);
 
             packed = mem;
-            bucket = length;
+            len = length;
         }
     }
 
     template<typename... Args>
     auto & push_at(const std::size_t pos, Args &&... args) {
-        ENTT_ASSERT(pos < (bucket * packed_page), "Out of bounds index");
+        auto &&[allocator, len] = bucket;
+        ENTT_ASSERT(pos < (len * packed_page), "Out of bounds index");
         auto *elem = std::addressof(packed[page(pos)][offset(pos)]);
 
         if constexpr(std::is_aggregate_v<value_type>) {
-            alloc_traits::construct(alloc{get_allocator()}, elem, Type{std::forward<Args>(args)...});
+            alloc_traits::construct(allocator, elem, Type{std::forward<Args>(args)...});
         } else {
-            alloc_traits::construct(alloc{get_allocator()}, elem, std::forward<Args>(args)...);
+            alloc_traits::construct(allocator, elem, std::forward<Args>(args)...);
         }
 
         return *elem;
     }
 
     void pop_at(const std::size_t pos) {
-        alloc_traits::destroy(alloc{get_allocator()}, std::addressof(packed[page(pos)][offset(pos)]));
+        alloc_traits::destroy(alloc{bucket.first()}, std::addressof(packed[page(pos)][offset(pos)]));
     }
 
 protected:
@@ -327,8 +329,8 @@ public:
      */
     explicit basic_storage_impl(const allocator_type &allocator = {})
         : underlying_type{deletion_policy{comp_traits::in_place_delete::value}, allocator},
-          packed{alloc_ptr_traits::allocate(alloc_ptr{get_allocator()}, 0u)},
-          bucket{}
+          bucket{allocator, 0u},
+          packed{alloc_ptr_traits::allocate(alloc_ptr{bucket.first()}, 0u)}
     {}
 
     /**
@@ -337,8 +339,8 @@ public:
      */
     basic_storage_impl(basic_storage_impl &&other) ENTT_NOEXCEPT
         : underlying_type{std::move(other)},
-          packed{std::exchange(other.packed, alloc_ptr_pointer{})},
-          bucket{std::exchange(other.bucket, 0u)}
+          bucket{std::move(other.bucket)},
+          packed{std::exchange(other.packed, alloc_ptr_pointer{})}
     {}
 
     /*! @brief Default destructor. */
@@ -356,8 +358,8 @@ public:
 
         underlying_type::operator=(std::move(other));
 
+        bucket = std::move(other.bucket);
         packed = std::exchange(other.packed, alloc_ptr_pointer{});
-        bucket = std::exchange(other.bucket, 0u);
 
         return *this;
     }
@@ -367,7 +369,7 @@ public:
      * @return The associated allocator.
      */
     [[nodiscard]] constexpr allocator_type get_allocator() const ENTT_NOEXCEPT {
-        return allocator_type{underlying_type::get_allocator()};
+        return allocator_type{bucket.first()};
     }
 
     /**
@@ -392,7 +394,7 @@ public:
      * @return Capacity of the storage.
      */
     [[nodiscard]] size_type capacity() const ENTT_NOEXCEPT {
-        return bucket * packed_page;
+        return bucket.second() * packed_page;
     }
 
     /*! @brief Requests the removal of unused capacity. */
@@ -704,8 +706,8 @@ public:
     }
 
 private:
+    compressed_pair<alloc, size_type> bucket;
     alloc_ptr_pointer packed;
-    size_type bucket;
 };