memory: uses_allocator_construction_args (waiting for C++20)

This commit is contained in:
Michele Caini
2022-02-21 08:07:01 +01:00
parent c2196149ee
commit e08b1f82ce
2 changed files with 60 additions and 0 deletions

View File

@@ -4,6 +4,7 @@
#include <cstddef>
#include <limits>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include "../config/config.h"
@@ -162,6 +163,35 @@ auto allocate_unique(Allocator &allocator, Args &&...args) {
return std::unique_ptr<Type, allocation_deleter<alloc>>{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<typename Type, typename Allocator, typename... Args>
constexpr auto uses_allocator_construction_args(const Allocator &allocator, Args &&...args) ENTT_NOEXCEPT {
if constexpr(!std::uses_allocator_v<Type, Allocator> && std::is_constructible_v<Type, Args...>) {
return std::forward_as_tuple(std::forward<Args>(args)...);
} else {
static_assert(std::uses_allocator_v<Type, Allocator>, "Ill-formed request");
if constexpr(std::is_constructible_v<Type, std::allocator_arg_t, const Allocator &, Args...>) {
return std::tuple<std::allocator_arg_t, const Allocator &, Args &&...>(std::allocator_arg, allocator, std::forward<Args>(args)...);
} else {
static_assert(std::is_constructible_v<Type, Args..., const Allocator &>, "Ill-formed request");
return std::forward_as_tuple(std::forward<Args>(args)..., allocator);
}
}
}
} // namespace entt
#endif

View File

@@ -2,8 +2,10 @@
#include <cstddef>
#include <limits>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include <gtest/gtest.h>
#include <entt/core/memory.hpp>
#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<int>(std::allocator<int>{}, 42);
static_assert(std::tuple_size_v<decltype(args)> == 1u);
static_assert(std::is_same_v<decltype(args), const std::tuple<int &&>>);
ASSERT_EQ(std::get<0>(args), 42);
}
TEST(UsesAllocatorConstructionArgs, LeadingAllocatorConvetion) {
const auto args = entt::uses_allocator_construction_args<std::tuple<int, char>>(std::allocator<int>{}, 42, 'c');
static_assert(std::tuple_size_v<decltype(args)> == 4u);
static_assert(std::is_same_v<decltype(args), const std::tuple<std::allocator_arg_t, const std::allocator<int> &, 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::vector<int>>(std::allocator<int>{}, 42);
static_assert(std::tuple_size_v<decltype(args)> == 2u);
static_assert(std::is_same_v<decltype(args), const std::tuple<int &&, const std::allocator<int> &>>);
ASSERT_EQ(std::get<0>(args), 42);
}