WPILibC++ 2025.1.1
Loading...
Searching...
No Matches
std_allocator.hpp
Go to the documentation of this file.
1// Copyright (C) 2015-2023 Jonathan Müller and foonathan/memory contributors
2// SPDX-License-Identifier: Zlib
3
4#ifndef WPI_MEMORY_STD_ALLOCATOR_HPP_INCLUDED
5#define WPI_MEMORY_STD_ALLOCATOR_HPP_INCLUDED
6
7/// \file
8/// Class \ref wpi::memory::std_allocator and related classes and functions.
9
10#include <new>
11#include <type_traits>
12
13#include "detail/utility.hpp"
14#include "config.hpp"
15#include "allocator_storage.hpp"
16#include "threading.hpp"
17
18namespace wpi
19{
20 namespace memory
21 {
22 namespace traits_detail
23 {
24 template <class RawAllocator>
26 typename RawAllocator::propagate_on_container_swap;
27
28 template <class RawAllocator>
30
31 template <class RawAllocator>
33 typename RawAllocator::propagate_on_container_move_assignment;
34
35 template <class RawAllocator>
37
38 template <class RawAllocator>
40 typename RawAllocator::propagate_on_container_copy_assignment;
41
42 template <class RawAllocator>
44 } // namespace traits_detail
45
46 /// Controls the propagation of a \ref std_allocator for a certain RawAllocator.
47 /// \ingroup memory_adapter
48 template <class RawAllocator>
69
70 /// Wraps a RawAllocator and makes it a "normal" \c Allocator.
71 /// It allows using a \c RawAllocator anywhere a \c Allocator is required.
72 /// \ingroup memory_adapter
73 template <typename T, class RawAllocator>
75#if defined _MSC_VER && defined __clang__
76 WPI_EBO(protected allocator_reference<RawAllocator>)
77#else
78 WPI_EBO(allocator_reference<RawAllocator>)
79#endif
80 {
82 // if it is any_allocator_reference an optimized implementation can be used
83 using is_any = std::is_same<alloc_reference, any_allocator_reference>;
84
86
87 public:
88 //=== typedefs ===//
89 using value_type = T;
90 using pointer = T*;
91 using const_pointer = const T*;
92 using reference = T&;
93 using const_reference = const T&;
94 using size_type = std::size_t;
95 using difference_type = std::ptrdiff_t;
96
102
103 template <typename U>
104 struct rebind
105 {
107 };
108
110
111 //=== constructor ===//
112 /// \effects Default constructs it by storing a default constructed, stateless \c RawAllocator inside the reference.
113 /// \requires The \c RawAllocator type is stateless, otherwise the body of this function will not compile.
115 {
116#if !defined(__GNUC__) || (defined(_GLIBCXX_USE_CXX11_ABI) && _GLIBCXX_USE_CXX11_ABI != 0)
117 // std::string requires default constructor for the small string optimization when using gcc's old ABI
118 // so don't assert then to allow joint allocator
119 static_assert(!alloc_reference::is_stateful::value,
120 "default constructor must not be used for stateful allocators");
121#endif
122 }
123
124 /// \effects Creates it from a reference to a \c RawAllocator.
125 /// It will store an \ref allocator_reference to it.
126 /// \requires The expression <tt>allocator_reference<RawAllocator>(alloc)</tt> is well-formed,
127 /// that is either \c RawAlloc is the same as \c RawAllocator or \c RawAllocator is the tag type \ref any_allocator.
128 /// If the requirement is not fulfilled this function does not participate in overload resolution.
129 /// \note The caller has to ensure that the lifetime of the \c RawAllocator is at least as long as the lifetime
130 /// of this \ref std_allocator object.
131 template <
132 class RawAlloc,
133 // MSVC seems to ignore access rights in decltype SFINAE below
134 // use this to prevent this constructor being chosen instead of move/copy for types inheriting from it
135 WPI_REQUIRES((!std::is_base_of<std_allocator, RawAlloc>::value))>
136 std_allocator(RawAlloc& alloc,
137 WPI_SFINAE(alloc_reference(std::declval<RawAlloc&>()))) noexcept
138 : alloc_reference(alloc)
139 {
140 }
141
142 /// \effects Creates it from a stateless, temporary \c RawAllocator object.
143 /// It will not store a reference but create it on the fly.
144 /// \requires The \c RawAllocator is stateless
145 /// and the expression <tt>allocator_reference<RawAllocator>(alloc)</tt> is well-formed as above,
146 /// otherwise this function does not participate in overload resolution.
147 template <
148 class RawAlloc,
149 // MSVC seems to ignore access rights in decltype SFINAE below
150 // use this to prevent this constructor being chosen instead of move/copy for types inheriting from it
151 WPI_REQUIRES((!std::is_base_of<std_allocator, RawAlloc>::value))>
153 std::declval<const RawAlloc&>()))) noexcept
154 : alloc_reference(alloc)
155 {
156 }
157
158 /// \effects Creates it from another \ref allocator_reference using the same allocator type.
159 std_allocator(const alloc_reference& alloc) noexcept : alloc_reference(alloc) {}
160
161 /// \details Implicit conversion from any other \ref allocator_storage is forbidden
162 /// to prevent accidentally wrapping another \ref allocator_storage inside a \ref allocator_reference.
163 template <class StoragePolicy, class OtherMut>
165
166 /// @{
167 /// \effects Creates it from another \ref std_allocator allocating a different type.
168 /// This is required by the \c Allcoator concept and simply takes the same \ref allocator_reference.
169 template <typename U>
171 : alloc_reference(alloc)
172 {
173 }
174
175 template <typename U>
177 {
178 }
179 /// @}
180
181 /// \returns A copy of the allocator.
182 /// This is required by the \c Allocator concept and forwards to the \ref propagation_traits.
187
188 //=== allocation/deallocation ===//
189 /// \effects Allocates memory using the underlying RawAllocator.
190 /// If \c n is \c 1, it will call <tt>allocate_node(sizeof(T), alignof(T))</tt>,
191 /// otherwise <tt>allocate_array(n, sizeof(T), alignof(T))</tt>.
192 /// \returns A pointer to a memory block suitable for \c n objects of type \c T.
193 /// \throws Anything thrown by the \c RawAllocator.
194 pointer allocate(size_type n, void* = nullptr)
195 {
196 return static_cast<pointer>(allocate_impl(is_any{}, n));
197 }
198
199 /// \effects Deallcoates memory using the underlying RawAllocator.
200 /// It will forward to the deallocation function in the same way as in \ref allocate().
201 /// \requires The pointer must come from a previous call to \ref allocate() with the same \c n on this object or any copy of it.
202 void deallocate(pointer p, size_type n) noexcept
203 {
204 deallocate_impl(is_any{}, p, n);
205 }
206
207 //=== construction/destruction ===//
208 /// \effects Creates an object of type \c U at given address using the passed arguments.
209 template <typename U, typename... Args>
210 void construct(U* p, Args&&... args)
211 {
212 void* mem = p;
213 ::new (mem) U(detail::forward<Args>(args)...);
214 }
215
216 /// \effects Calls the destructor for an object of type \c U at given address.
217 template <typename U>
218 void destroy(U* p) noexcept
219 {
220 // This is to avoid a MSVS 2015 'unreferenced formal parameter' warning
221 (void)p;
222 p->~U();
223 }
224
225 //=== getter ===//
226 /// \returns The maximum size for an allocation which is <tt>max_array_size() / sizeof(value_type)</tt>.
227 /// This is only an upper bound, not the exact maximum.
228 size_type max_size() const noexcept
229 {
230 return this->max_array_size() / sizeof(value_type);
231 }
232
233 /// @{
234 /// \effects Returns a reference to the referenced allocator.
235 /// \returns For stateful allocators: A (\c const) reference to the stored allocator.
236 /// For stateless allocators: A temporary constructed allocator.
237 auto get_allocator() noexcept
238 -> decltype(std::declval<alloc_reference>().get_allocator())
239 {
241 }
242
243 auto get_allocator() const noexcept
244 -> decltype(std::declval<const alloc_reference>().get_allocator())
245 {
247 }
248 /// @}
249
250 private:
251 // any_allocator_reference: use virtual function which already does a dispatch on node/array
252 void* allocate_impl(std::true_type, size_type n)
253 {
254 return get_allocator().allocate_impl(n, sizeof(T), alignof(T));
255 }
256
257 void deallocate_impl(std::true_type, void* ptr, size_type n)
258 {
259 get_allocator().deallocate_impl(ptr, n, sizeof(T), alignof(T));
260 }
261
262 // alloc_reference: decide between node/array
263 void* allocate_impl(std::false_type, size_type n)
264 {
265 if (n == 1)
266 return this->allocate_node(sizeof(T), alignof(T));
267 else
268 return this->allocate_array(n, sizeof(T), alignof(T));
269 }
270
271 void deallocate_impl(std::false_type, void* ptr, size_type n)
272 {
273 if (n == 1)
274 this->deallocate_node(ptr, sizeof(T), alignof(T));
275 else
276 this->deallocate_array(ptr, n, sizeof(T), alignof(T));
277 }
278
279 template <typename U> // stateful
280 bool equal_to_impl(std::true_type,
281 const std_allocator<U, RawAllocator>& other) const noexcept
282 {
283 return &get_allocator() == &other.get_allocator();
284 }
285
286 template <typename U> // non-stateful
287 bool equal_to_impl(std::false_type,
288 const std_allocator<U, RawAllocator>&) const noexcept
289 {
290 return true;
291 }
292
293 template <typename U> // shared
294 bool equal_to(std::true_type,
295 const std_allocator<U, RawAllocator>& other) const noexcept
296 {
297 return get_allocator() == other.get_allocator();
298 }
299
300 template <typename U> // not shared
301 bool equal_to(std::false_type,
302 const std_allocator<U, RawAllocator>& other) const noexcept
303 {
304 return equal_to_impl(typename allocator_traits<RawAllocator>::is_stateful{}, other);
305 }
306
307 template <typename T1, typename T2, class Impl>
308 friend bool operator==(const std_allocator<T1, Impl>& lhs,
309 const std_allocator<T2, Impl>& rhs) noexcept;
310
311 template <typename U, class OtherRawAllocator>
312 friend class std_allocator;
313 };
314
315 /// \effects Compares two \ref std_allocator object, they are equal if either stateless or reference the same allocator.
316 /// \returns The result of the comparision for equality.
317 /// \relates std_allocator
318 template <typename T, typename U, class Impl>
320 const std_allocator<U, Impl>& rhs) noexcept
321 {
322 return lhs.equal_to(is_shared_allocator<Impl>{}, rhs);
323 }
324
325 /// \effects Compares two \ref std_allocator object, they are equal if either stateless or reference the same allocator.
326 /// \returns The result of the comparision for inequality.
327 /// \relates std_allocator
328 template <typename T, typename U, class Impl>
330 const std_allocator<U, Impl>& rhs) noexcept
331 {
332 return !(lhs == rhs);
333 }
334
335 /// \returns A new \ref std_allocator for a given type using a certain allocator object.
336 /// \relates std_allocator
337 template <typename T, class RawAllocator>
338 auto make_std_allocator(RawAllocator&& allocator) noexcept
340 {
341 return {detail::forward<RawAllocator>(allocator)};
342 }
343
344 /// An alias template for \ref std_allocator using a type-erased RawAllocator.
345 /// This is the same as using a \ref std_allocator with the tag type \ref any_allocator.
346 /// The implementation is optimized to call fewer virtual functions.
347 /// \ingroup memory_adapter
348 template <typename T>
350
351 /// \returns A new \ref any_std_allocator for a given type using a certain allocator object.
352 /// \relates any_std_allocator
353 template <typename T, class RawAllocator>
354 any_std_allocator<T> make_any_std_allocator(RawAllocator&& allocator) noexcept
355 {
356 return {detail::forward<RawAllocator>(allocator)};
357 }
358 } // namespace memory
359} // namespace wpi
360
361#endif // WPI_MEMORY_STD_ALLOCATOR_HPP_INCLUDED
Class template wpi::memory::allocator_storage, some policies and resulting typedefs.
An alias template for allocator_storage using the reference_storage policy.
Definition allocator_storage.hpp:900
A RawAllocator that stores another allocator.
Definition allocator_storage.hpp:97
typename reference_storage< RawAllocator >::allocator_type allocator_type
Definition allocator_storage.hpp:106
auto get_allocator() noexcept -> decltype(std::declval< storage_policy >().get_allocator())
Definition allocator_storage.hpp:277
decltype(traits_detail::is_stateful< Allocator >(traits_detail::full_concept{})) is_stateful
Definition allocator_traits.hpp:295
An alias template for std_allocator using a type-erased RawAllocator.
Definition std_allocator.hpp:349
any_std_allocator< T > make_any_std_allocator(RawAllocator &&allocator) noexcept
Definition std_allocator.hpp:354
Wraps a RawAllocator and makes it a "normal" Allocator.
Definition std_allocator.hpp:80
void deallocate(pointer p, size_type n) noexcept
Definition std_allocator.hpp:202
T value_type
Definition std_allocator.hpp:89
auto get_allocator() noexcept -> decltype(std::declval< alloc_reference >().get_allocator())
Definition std_allocator.hpp:237
std::ptrdiff_t difference_type
Definition std_allocator.hpp:95
std_allocator() noexcept
Definition std_allocator.hpp:114
const T * const_pointer
Definition std_allocator.hpp:91
typename prop_traits::propagate_on_container_copy_assignment propagate_on_container_copy_assignment
Definition std_allocator.hpp:100
void construct(U *p, Args &&... args)
Definition std_allocator.hpp:210
std_allocator(const RawAlloc &alloc,) noexcept
Definition std_allocator.hpp:152
std_allocator(const allocator_storage< StoragePolicy, OtherMut > &)=delete
auto get_allocator() const noexcept -> decltype(std::declval< const alloc_reference >().get_allocator())
Definition std_allocator.hpp:243
friend class std_allocator
Definition std_allocator.hpp:312
typename prop_traits::propagate_on_container_move_assignment propagate_on_container_move_assignment
Definition std_allocator.hpp:98
std_allocator(const std_allocator< U, RawAllocator > &alloc) noexcept
Definition std_allocator.hpp:170
std_allocator(RawAlloc &alloc,) noexcept
Definition std_allocator.hpp:136
size_type max_size() const noexcept
Definition std_allocator.hpp:228
typename prop_traits::propagate_on_container_swap propagate_on_container_swap
Definition std_allocator.hpp:97
std_allocator(std_allocator< U, RawAllocator > &alloc) noexcept
Definition std_allocator.hpp:176
void destroy(U *p) noexcept
Definition std_allocator.hpp:218
std_allocator< T, RawAllocator > select_on_container_copy_construction() const
Definition std_allocator.hpp:183
std_allocator(const alloc_reference &alloc) noexcept
Definition std_allocator.hpp:159
const T & const_reference
Definition std_allocator.hpp:93
T & reference
Definition std_allocator.hpp:92
T * pointer
Definition std_allocator.hpp:90
bool operator==(const std_allocator< T, Impl > &lhs, const std_allocator< U, Impl > &rhs) noexcept
Definition std_allocator.hpp:319
auto make_std_allocator(RawAllocator &&allocator) noexcept -> std_allocator< T, typename std::decay< RawAllocator >::type >
Definition std_allocator.hpp:338
bool operator!=(const std_allocator< T, Impl > &lhs, const std_allocator< U, Impl > &rhs) noexcept
Definition std_allocator.hpp:329
std::size_t size_type
Definition std_allocator.hpp:94
friend bool operator==(const std_allocator< T1, Impl > &lhs, const std_allocator< T2, Impl > &rhs) noexcept
pointer allocate(size_type n, void *=nullptr)
Definition std_allocator.hpp:194
typename alloc_reference::allocator_type allocator_type
Definition std_allocator.hpp:109
Configuration macros.
#define WPI_ALIAS_TEMPLATE(Name,...)
Definition config.hpp:73
auto ptr(T p) -> const void *
Converts p to const void* for pointer formatting.
Definition format.h:3821
Implement std::hash so that hash_code can be used in STL containers.
Definition PointerIntPair.h:280
T && forward(typename std::remove_reference< T >::type &t) noexcept
Definition utility.hpp:31
auto propagate_on_container_copy_assignment(std_concept) -> typename RawAllocator::propagate_on_container_copy_assignment
auto propagate_on_container_swap(std_concept) -> typename RawAllocator::propagate_on_container_swap
auto propagate_on_container_move_assignment(std_concept) -> typename RawAllocator::propagate_on_container_move_assignment
auto deallocate_array(full_concept, Allocator &alloc, void *ptr, std::size_t count, std::size_t size, std::size_t alignment) noexcept -> WPI_AUTO_RETURN_TYPE(alloc.deallocate_array(ptr, count, size, alignment), void) template< class Allocator > void deallocate_array(min_concept, Allocator &alloc, void *ptr, std::size_t count, std::size_t size, std::size_t alignment) noexcept
Definition allocator_traits.hpp:233
auto deallocate_node(full_concept, Allocator &alloc, void *ptr, std::size_t size, std::size_t alignment) noexcept -> WPI_AUTO_RETURN_TYPE(alloc.deallocate_node(ptr, size, alignment), void) template< class Allocator > auto deallocate_node(std_concept, Allocator &alloc, void *ptr, std::size_t size, std::size_t) noexcept -> WPI_AUTO_RETURN_TYPE(alloc.deallocate(static_cast< char * >(ptr), size), void) template< class Allocator > error deallocate_node(error, Allocator &, void *, std::size_t, std::size_t)
Definition allocator_traits.hpp:195
Memory namespace.
Definition heap_allocator.hpp:20
Foonathan namespace.
Definition ntcore_cpp.h:26
Specifies whether or not a RawAllocator has shared semantics.
Definition allocator_storage.hpp:534
Controls the propagation of a std_allocator for a certain RawAllocator.
Definition std_allocator.hpp:50
static AllocReference select_on_container_copy_construction(const AllocReference &alloc)
Definition std_allocator.hpp:64
decltype(traits_detail::propagate_on_container_copy_assignment< RawAllocator >( traits_detail::full_concept{})) propagate_on_container_copy_assignment
Definition std_allocator.hpp:59
decltype(traits_detail::propagate_on_container_move_assignment< RawAllocator >( traits_detail::full_concept{})) propagate_on_container_move_assignment
Definition std_allocator.hpp:55
decltype(traits_detail::propagate_on_container_swap< RawAllocator >( traits_detail::full_concept{})) propagate_on_container_swap
Definition std_allocator.hpp:51
Definition std_allocator.hpp:105
Definition allocator_traits.hpp:91
Definition allocator_traits.hpp:88
Definition allocator_traits.hpp:85
The mutex types.
#define WPI_SFINAE(Expr)
Definition utility.hpp:85
#define WPI_REQUIRES(Expr)
Definition utility.hpp:70