From e08b1f82ce68c5e911a24a56baecee4008ab2c56 Mon Sep 17 00:00:00 2001 From: Michele Caini Date: Mon, 21 Feb 2022 08:07:01 +0100 Subject: [PATCH] memory: uses_allocator_construction_args (waiting for C++20) --- src/entt/core/memory.hpp | 30 ++++++++++++++++++++++++++++++ test/entt/core/memory.cpp | 30 ++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/src/entt/core/memory.hpp b/src/entt/core/memory.hpp index 8c323cf11..e6f878dc2 100644 --- a/src/entt/core/memory.hpp +++ b/src/entt/core/memory.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include "../config/config.h" @@ -162,6 +163,35 @@ auto allocate_unique(Allocator &allocator, Args &&...args) { return std::unique_ptr>{ptr, type_allocator}; } +/** + * @brief Uses-allocator construction utility. + * + * Primarily intended for internal use. Unlike the standard version (waiting for + * C++20), this utility does not differentiate between pair and non-pair types. + * + * @tparam Type Type to return arguments for. + * @tparam Allocator Type of allocator used to manage memory and elements. + * @tparam Args Types of arguments to use to construct the object. + * @param allocator The allocator to use. + * @param args Parameters to use to construct the object. + * @return The arguments needed to create an object of the given type. + */ +template +constexpr auto uses_allocator_construction_args(const Allocator &allocator, Args &&...args) ENTT_NOEXCEPT { + if constexpr(!std::uses_allocator_v && std::is_constructible_v) { + return std::forward_as_tuple(std::forward(args)...); + } else { + static_assert(std::uses_allocator_v, "Ill-formed request"); + + if constexpr(std::is_constructible_v) { + return std::tuple(std::allocator_arg, allocator, std::forward(args)...); + } else { + static_assert(std::is_constructible_v, "Ill-formed request"); + return std::forward_as_tuple(std::forward(args)..., allocator); + } + } +} + } // namespace entt #endif diff --git a/test/entt/core/memory.cpp b/test/entt/core/memory.cpp index 58f1c946f..3d6878fef 100644 --- a/test/entt/core/memory.cpp +++ b/test/entt/core/memory.cpp @@ -2,8 +2,10 @@ #include #include #include +#include #include #include +#include #include #include #include "../common/basic_test_allocator.hpp" @@ -115,3 +117,31 @@ TEST(AllocateUnique, UsesAllocatorConstruction) { } #endif + +TEST(UsesAllocatorConstructionArgs, NoUsesAllocatorConstruction) { + const auto args = entt::uses_allocator_construction_args(std::allocator{}, 42); + + static_assert(std::tuple_size_v == 1u); + static_assert(std::is_same_v>); + + ASSERT_EQ(std::get<0>(args), 42); +} + +TEST(UsesAllocatorConstructionArgs, LeadingAllocatorConvetion) { + const auto args = entt::uses_allocator_construction_args>(std::allocator{}, 42, 'c'); + + static_assert(std::tuple_size_v == 4u); + static_assert(std::is_same_v &, int &&, char &&>>); + + ASSERT_EQ(std::get<2>(args), 42); + ASSERT_EQ(std::get<3>(args), 'c'); +} + +TEST(UsesAllocatorConstructionArgs, TrailingAllocatorConvetion) { + const auto args = entt::uses_allocator_construction_args>(std::allocator{}, 42); + + static_assert(std::tuple_size_v == 2u); + static_assert(std::is_same_v &>>); + + ASSERT_EQ(std::get<0>(args), 42); +}