EnTT 4.0.0
Loading...
Searching...
No Matches
memory.hpp
1#ifndef ENTT_CORE_MEMORY_HPP
2#define ENTT_CORE_MEMORY_HPP
3
4#include "../config/config.h"
5#include "../stl/cstddef.hpp"
6#include "../stl/memory.hpp"
7#include "../stl/tuple.hpp"
8#include "../stl/type_traits.hpp"
9#include "../stl/utility.hpp"
10
11namespace entt {
12
19template<typename Allocator>
20constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
21 if constexpr(stl::allocator_traits<Allocator>::propagate_on_container_copy_assignment::value) {
22 lhs = rhs;
23 }
24}
25
32template<typename Allocator>
33constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
34 if constexpr(stl::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) {
35 lhs = stl::move(rhs);
36 }
37}
38
45template<typename Allocator>
46constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
47 if constexpr(stl::allocator_traits<Allocator>::propagate_on_container_swap::value) {
48 using stl::swap;
49 swap(lhs, rhs);
50 } else {
51 ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers");
52 }
53}
54
59template<typename Allocator>
60struct allocation_deleter: private Allocator {
62 using allocator_type = Allocator;
64 using pointer = stl::allocator_traits<Allocator>::pointer;
65
70 constexpr allocation_deleter(const allocator_type &alloc) noexcept(stl::is_nothrow_copy_constructible_v<allocator_type>)
71 : Allocator{alloc} {}
72
77 constexpr void operator()(pointer ptr) noexcept(stl::is_nothrow_destructible_v<typename allocator_type::value_type>) {
78 using alloc_traits = stl::allocator_traits<Allocator>;
79 alloc_traits::destroy(*this, stl::to_address(ptr));
80 alloc_traits::deallocate(*this, ptr, 1u);
81 }
82};
83
93template<typename Type, typename Allocator, typename... Args>
94constexpr auto allocate_unique(Allocator &allocator, Args &&...args) {
95 static_assert(!stl::is_array_v<Type>, "Array types are not supported");
96
97 using alloc_traits = stl::allocator_traits<Allocator>::template rebind_traits<Type>;
98 using allocator_type = alloc_traits::allocator_type;
99
100 allocator_type alloc{allocator};
101 auto ptr = alloc_traits::allocate(alloc, 1u);
102
103 ENTT_TRY {
104 alloc_traits::construct(alloc, stl::to_address(ptr), stl::forward<Args>(args)...);
105 }
106 ENTT_CATCH {
107 alloc_traits::deallocate(alloc, ptr, 1u);
108 ENTT_THROW;
109 }
110
111 return stl::unique_ptr<Type, allocation_deleter<allocator_type>>{ptr, alloc};
112}
113
115namespace internal {
116
117template<typename Type>
118struct uses_allocator_construction {
119 template<typename Allocator, typename... Params>
120 static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept {
121 if constexpr(!stl::uses_allocator_v<Type, Allocator> && stl::is_constructible_v<Type, Params...>) {
122 return stl::forward_as_tuple(stl::forward<Params>(params)...);
123 } else {
124 static_assert(stl::uses_allocator_v<Type, Allocator>, "Ill-formed request");
125
126 if constexpr(stl::is_constructible_v<Type, stl::allocator_arg_t, const Allocator &, Params...>) {
127 return stl::tuple<stl::allocator_arg_t, const Allocator &, Params &&...>{stl::allocator_arg, allocator, stl::forward<Params>(params)...};
128 } else {
129 static_assert(stl::is_constructible_v<Type, Params..., const Allocator &>, "Ill-formed request");
130 return stl::forward_as_tuple(stl::forward<Params>(params)..., allocator);
131 }
132 }
133 }
134};
135
136template<typename Type, typename Other>
137struct uses_allocator_construction<stl::pair<Type, Other>> {
138 using type = stl::pair<Type, Other>;
139
140 template<typename First, typename Second>
141 static constexpr auto args(const auto &allocator, stl::piecewise_construct_t, First &&first, Second &&second) noexcept {
142 return stl::make_tuple(
143 stl::piecewise_construct,
144 stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Type>::args(allocator, stl::forward<decltype(curr)>(curr)...); }, stl::forward<First>(first)),
145 stl::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Other>::args(allocator, stl::forward<decltype(curr)>(curr)...); }, stl::forward<Second>(second)));
146 }
147
148 static constexpr auto args(const auto &allocator) noexcept {
149 return uses_allocator_construction<type>::args(allocator, stl::piecewise_construct, stl::tuple<>{}, stl::tuple<>{});
150 }
151
152 template<typename First, typename Second>
153 static constexpr auto args(const auto &allocator, First &&first, Second &&second) noexcept {
154 return uses_allocator_construction<type>::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::forward<First>(first)), stl::forward_as_tuple(stl::forward<Second>(second)));
155 }
156
157 template<typename First, typename Second>
158 static constexpr auto args(const auto &allocator, const stl::pair<First, Second> &value) noexcept {
159 return uses_allocator_construction<type>::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(value.first), stl::forward_as_tuple(value.second));
160 }
161
162 template<typename First, typename Second>
163 static constexpr auto args(const auto &allocator, stl::pair<First, Second> &&value) noexcept {
164 return uses_allocator_construction<type>::args(allocator, stl::piecewise_construct, stl::forward_as_tuple(stl::move(value.first)), stl::forward_as_tuple(stl::move(value.second)));
165 }
166};
167
168} // namespace internal
170
183template<typename Type, typename... Args>
184constexpr auto uses_allocator_construction_args(const auto &allocator, Args &&...args) noexcept {
185 return internal::uses_allocator_construction<Type>::args(allocator, stl::forward<Args>(args)...);
186}
187
200template<typename Type, typename... Args>
201constexpr Type make_obj_using_allocator(const auto &allocator, Args &&...args) {
202 return stl::make_from_tuple<Type>(internal::uses_allocator_construction<Type>::args(allocator, stl::forward<Args>(args)...));
203}
204
218template<typename Type, typename... Args>
219constexpr Type *uninitialized_construct_using_allocator(Type *value, const auto &allocator, Args &&...args) {
220 return stl::apply([value](auto &&...curr) { return ::new(value) Type(stl::forward<decltype(curr)>(curr)...); }, internal::uses_allocator_construction<Type>::args(allocator, stl::forward<Args>(args)...));
221}
222
223} // namespace entt
224
225#endif
EnTT default namespace.
Definition dense_map.hpp:25
constexpr void propagate_on_container_swap(Allocator &lhs, Allocator &rhs) noexcept
Utility function to design allocation-aware containers.
Definition memory.hpp:46
constexpr auto uses_allocator_construction_args(const auto &allocator, Args &&...args) noexcept
Uses-allocator construction utility (waiting for C++20).
Definition memory.hpp:184
constexpr Type make_obj_using_allocator(const auto &allocator, Args &&...args)
Uses-allocator construction utility (waiting for C++20).
Definition memory.hpp:201
constexpr void swap(compressed_pair< First, Second > &lhs, compressed_pair< First, Second > &rhs) noexcept
Swaps two compressed pair objects.
constexpr void propagate_on_container_move_assignment(Allocator &lhs, Allocator &rhs) noexcept
Utility function to design allocation-aware containers.
Definition memory.hpp:33
constexpr Type * uninitialized_construct_using_allocator(Type *value, const auto &allocator, Args &&...args)
Uses-allocator construction utility (waiting for C++20).
Definition memory.hpp:219
constexpr auto allocate_unique(Allocator &allocator, Args &&...args)
Allows stl::unique_ptr to use allocators (waiting for C++20).
Definition memory.hpp:94
constexpr void propagate_on_container_copy_assignment(Allocator &lhs, Allocator &rhs) noexcept
Utility function to design allocation-aware containers.
Definition memory.hpp:20
stl::allocator_traits< Allocator >::pointer pointer
Pointer type.
Definition memory.hpp:64
constexpr void operator()(pointer ptr) noexcept(stl::is_nothrow_destructible_v< typename allocator_type::value_type >)
Destroys the pointed object and deallocates its memory.
Definition memory.hpp:77
Allocator allocator_type
Allocator type.
Definition memory.hpp:62
constexpr allocation_deleter(const allocator_type &alloc) noexcept(stl::is_nothrow_copy_constructible_v< allocator_type >)
Inherited constructors.
Definition memory.hpp:70