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

memory: uninitialized_construct_using_allocator (waiting for C++20)

Michele Caini 4 лет назад
Родитель
Сommit
b093e82db3
2 измененных файлов с 49 добавлено и 0 удалено
  1. 19 0
      src/entt/core/memory.hpp
  2. 30 0
      test/entt/core/memory.cpp

+ 19 - 0
src/entt/core/memory.hpp

@@ -265,6 +265,25 @@ constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...ar
     return std::make_from_tuple<Type>(internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...));
 }
 
+/**
+ * @brief Uses-allocator construction utility (waiting for C++20).
+ *
+ * Primarily intended for internal use. Creates an object of a given type by
+ * means of uses-allocator construction at an uninitialized memory location.
+ *
+ * @tparam Type Type of object to create.
+ * @tparam Allocator Type of allocator used to manage memory and elements.
+ * @tparam Args Types of arguments to use to construct the object.
+ * @param value Memory location in which to place the object.
+ * @param allocator The allocator to use.
+ * @param args Parameters to use to construct the object.
+ * @return A pointer to the newly created object of the given type.
+ */
+template<typename Type, typename Allocator, typename... Args>
+constexpr Type *uninitialized_construct_using_allocator(Type *value, const Allocator &allocator, Args &&...args) {
+    return std::apply([&](auto &&...curr) { return new(value) Type(std::forward<decltype(curr)>(curr)...); }, internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...));
+}
+
 } // namespace entt
 
 #endif

+ 30 - 0
test/entt/core/memory.cpp

@@ -205,3 +205,33 @@ TEST(MakeObjUsingAllocator, Functionalities) {
     ASSERT_FALSE(vec.empty());
     ASSERT_EQ(vec.size(), size);
 }
+
+TEST(UninitializedConstructUsingAllocator, NoUsesAllocatorConstruction) {
+    std::aligned_storage_t<sizeof(int)> storage;
+    std::allocator<int> allocator{};
+
+    int *value = entt::uninitialized_construct_using_allocator(reinterpret_cast<int *>(&storage), allocator, 42);
+
+    ASSERT_EQ(*value, 42);
+}
+
+#if defined(ENTT_HAS_TRACKED_MEMORY_RESOURCE)
+
+TEST(UninitializedConstructUsingAllocator, UsesAllocatorConstruction) {
+    using string_type = typename test::tracked_memory_resource::string_type;
+
+    test::tracked_memory_resource memory_resource{};
+    std::pmr::polymorphic_allocator<string_type> allocator{&memory_resource};
+    std::aligned_storage_t<sizeof(string_type)> storage;
+
+    string_type *value = entt::uninitialized_construct_using_allocator(reinterpret_cast<string_type *>(&storage), allocator, test::tracked_memory_resource::default_value);
+
+    ASSERT_TRUE(memory_resource.is_equal(memory_resource));
+    ASSERT_GT(memory_resource.do_allocate_counter(), 0u);
+    ASSERT_EQ(memory_resource.do_deallocate_counter(), 0u);
+    ASSERT_EQ(*value, test::tracked_memory_resource::default_value);
+
+    value->~string_type();
+}
+
+#endif