EnTT 3.14.0
Loading...
Searching...
No Matches
memory.hpp
1#ifndef ENTT_CORE_MEMORY_HPP
2#define ENTT_CORE_MEMORY_HPP
3
4#include <cstddef>
5#include <memory>
6#include <tuple>
7#include <type_traits>
8#include <utility>
9#include "../config/config.h"
10
11namespace entt {
12
19template<typename Type>
20[[nodiscard]] constexpr auto to_address(Type &&ptr) noexcept {
21 if constexpr(std::is_pointer_v<std::decay_t<Type>>) {
22 return ptr;
23 } else {
24 return to_address(std::forward<Type>(ptr).operator->());
25 }
26}
27
34template<typename Allocator>
35constexpr void propagate_on_container_copy_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
36 if constexpr(std::allocator_traits<Allocator>::propagate_on_container_copy_assignment::value) {
37 lhs = rhs;
38 }
39}
40
47template<typename Allocator>
48constexpr void propagate_on_container_move_assignment([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
49 if constexpr(std::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) {
50 lhs = std::move(rhs);
51 }
52}
53
60template<typename Allocator>
61constexpr void propagate_on_container_swap([[maybe_unused]] Allocator &lhs, [[maybe_unused]] Allocator &rhs) noexcept {
62 if constexpr(std::allocator_traits<Allocator>::propagate_on_container_swap::value) {
63 using std::swap;
64 swap(lhs, rhs);
65 } else {
66 ENTT_ASSERT_CONSTEXPR(lhs == rhs, "Cannot swap the containers");
67 }
68}
69
74template<typename Allocator>
75struct allocation_deleter: private Allocator {
77 using allocator_type = Allocator;
79 using pointer = typename std::allocator_traits<Allocator>::pointer;
80
85 constexpr allocation_deleter(const allocator_type &alloc) noexcept(std::is_nothrow_copy_constructible_v<allocator_type>)
86 : Allocator{alloc} {}
87
92 constexpr void operator()(pointer ptr) noexcept(std::is_nothrow_destructible_v<typename allocator_type::value_type>) {
93 using alloc_traits = std::allocator_traits<Allocator>;
94 alloc_traits::destroy(*this, to_address(ptr));
95 alloc_traits::deallocate(*this, ptr, 1u);
96 }
97};
98
108template<typename Type, typename Allocator, typename... Args>
109ENTT_CONSTEXPR auto allocate_unique(Allocator &allocator, Args &&...args) {
110 static_assert(!std::is_array_v<Type>, "Array types are not supported");
111
112 using alloc_traits = typename std::allocator_traits<Allocator>::template rebind_traits<Type>;
113 using allocator_type = typename alloc_traits::allocator_type;
114
115 allocator_type alloc{allocator};
116 auto ptr = alloc_traits::allocate(alloc, 1u);
117
118 ENTT_TRY {
119 alloc_traits::construct(alloc, to_address(ptr), std::forward<Args>(args)...);
120 }
121 ENTT_CATCH {
122 alloc_traits::deallocate(alloc, ptr, 1u);
123 ENTT_THROW;
124 }
125
126 return std::unique_ptr<Type, allocation_deleter<allocator_type>>{ptr, alloc};
127}
128
130namespace internal {
131
132template<typename Type>
133struct uses_allocator_construction {
134 template<typename Allocator, typename... Params>
135 static constexpr auto args([[maybe_unused]] const Allocator &allocator, Params &&...params) noexcept {
136 if constexpr(!std::uses_allocator_v<Type, Allocator> && std::is_constructible_v<Type, Params...>) {
137 return std::forward_as_tuple(std::forward<Params>(params)...);
138 } else {
139 static_assert(std::uses_allocator_v<Type, Allocator>, "Ill-formed request");
140
141 if constexpr(std::is_constructible_v<Type, std::allocator_arg_t, const Allocator &, Params...>) {
142 return std::tuple<std::allocator_arg_t, const Allocator &, Params &&...>{std::allocator_arg, allocator, std::forward<Params>(params)...};
143 } else {
144 static_assert(std::is_constructible_v<Type, Params..., const Allocator &>, "Ill-formed request");
145 return std::forward_as_tuple(std::forward<Params>(params)..., allocator);
146 }
147 }
148 }
149};
150
151template<typename Type, typename Other>
152struct uses_allocator_construction<std::pair<Type, Other>> {
153 using type = std::pair<Type, Other>;
154
155 template<typename Allocator, typename First, typename Second>
156 static constexpr auto args(const Allocator &allocator, std::piecewise_construct_t, First &&first, Second &&second) noexcept {
157 return std::make_tuple(
158 std::piecewise_construct,
159 std::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Type>::args(allocator, std::forward<decltype(curr)>(curr)...); }, std::forward<First>(first)),
160 std::apply([&allocator](auto &&...curr) { return uses_allocator_construction<Other>::args(allocator, std::forward<decltype(curr)>(curr)...); }, std::forward<Second>(second)));
161 }
162
163 template<typename Allocator>
164 static constexpr auto args(const Allocator &allocator) noexcept {
165 return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::tuple<>{}, std::tuple<>{});
166 }
167
168 template<typename Allocator, typename First, typename Second>
169 static constexpr auto args(const Allocator &allocator, First &&first, Second &&second) noexcept {
170 return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(std::forward<First>(first)), std::forward_as_tuple(std::forward<Second>(second)));
171 }
172
173 template<typename Allocator, typename First, typename Second>
174 static constexpr auto args(const Allocator &allocator, const std::pair<First, Second> &value) noexcept {
175 return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(value.first), std::forward_as_tuple(value.second));
176 }
177
178 template<typename Allocator, typename First, typename Second>
179 static constexpr auto args(const Allocator &allocator, std::pair<First, Second> &&value) noexcept {
180 return uses_allocator_construction<type>::args(allocator, std::piecewise_construct, std::forward_as_tuple(std::move(value.first)), std::forward_as_tuple(std::move(value.second)));
181 }
182};
183
184} // namespace internal
200template<typename Type, typename Allocator, typename... Args>
201constexpr auto uses_allocator_construction_args(const Allocator &allocator, Args &&...args) noexcept {
202 return internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...);
203}
204
218template<typename Type, typename Allocator, typename... Args>
219constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args) {
220 return std::make_from_tuple<Type>(internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...));
221}
222
237template<typename Type, typename Allocator, typename... Args>
238constexpr Type *uninitialized_construct_using_allocator(Type *value, const Allocator &allocator, Args &&...args) {
239 return std::apply([value](auto &&...curr) { return ::new(value) Type(std::forward<decltype(curr)>(curr)...); }, internal::uses_allocator_construction<Type>::args(allocator, std::forward<Args>(args)...));
240}
241
242} // namespace entt
243
244#endif
EnTT default namespace.
Definition dense_map.hpp:22
constexpr void propagate_on_container_swap(Allocator &lhs, Allocator &rhs) noexcept
Utility function to design allocation-aware containers.
Definition memory.hpp:61
constexpr Type make_obj_using_allocator(const Allocator &allocator, Args &&...args)
Uses-allocator construction utility (waiting for C++20).
Definition memory.hpp:219
constexpr void propagate_on_container_move_assignment(Allocator &lhs, Allocator &rhs) noexcept
Utility function to design allocation-aware containers.
Definition memory.hpp:48
constexpr Type * uninitialized_construct_using_allocator(Type *value, const Allocator &allocator, Args &&...args)
Uses-allocator construction utility (waiting for C++20).
Definition memory.hpp:238
constexpr void swap(compressed_pair< First, Second > &lhs, compressed_pair< First, Second > &rhs)
Swaps two compressed pair objects.
constexpr auto uses_allocator_construction_args(const Allocator &allocator, Args &&...args) noexcept
Uses-allocator construction utility (waiting for C++20).
Definition memory.hpp:201
constexpr auto allocate_unique(Allocator &allocator, Args &&...args)
Allows std::unique_ptr to use allocators (waiting for C++20).
Definition memory.hpp:109
constexpr void propagate_on_container_copy_assignment(Allocator &lhs, Allocator &rhs) noexcept
Utility function to design allocation-aware containers.
Definition memory.hpp:35
constexpr auto to_address(Type &&ptr) noexcept
Unwraps fancy pointers, does nothing otherwise (waiting for C++20).
Definition memory.hpp:20
Deleter for allocator-aware unique pointers (waiting for C++20).
Definition memory.hpp:75
typename std::allocator_traits< Allocator >::pointer pointer
Pointer type.
Definition memory.hpp:79
constexpr allocation_deleter(const allocator_type &alloc) noexcept(std::is_nothrow_copy_constructible_v< allocator_type >)
Inherited constructors.
Definition memory.hpp:85
constexpr void operator()(pointer ptr) noexcept(std::is_nothrow_destructible_v< typename allocator_type::value_type >)
Destroys the pointed object and deallocates its memory.
Definition memory.hpp:92
Allocator allocator_type
Allocator type.
Definition memory.hpp:77