WPILibC++ 2025.1.1
Loading...
Searching...
No Matches
smart_ptr.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_SMART_PTR_HPP_INCLUDED
5#define WPI_MEMORY_SMART_PTR_HPP_INCLUDED
6
7/// \file
8/// \c std::make_unique() / \c std::make_shared() replacement allocating memory through a RawAllocator.
9/// \note Only available on a hosted implementation.
10
11#include "config.hpp"
12#if !WPI_HOSTED_IMPLEMENTATION
13#error "This header is only available for a hosted implementation."
14#endif
15
16#include <memory>
17#include <type_traits>
18
19#include "detail/utility.hpp"
20#include "deleter.hpp"
21#include "std_allocator.hpp"
22
23namespace wpi
24{
25 namespace memory
26 {
27 namespace detail
28 {
29 template <typename T, class RawAllocator, typename... Args>
31 -> std::unique_ptr<T, allocator_deleter<T, RawAllocator>>
32 {
33 using raw_ptr = std::unique_ptr<T, allocator_deallocator<T, RawAllocator>>;
34
35 auto memory = alloc.allocate_node(sizeof(T), alignof(T));
36 // raw_ptr deallocates memory in case of constructor exception
37 raw_ptr result(static_cast<T*>(memory), {alloc});
38 // call constructor
39 ::new (memory) T(detail::forward<Args>(args)...);
40 // pass ownership to return value using a deleter that calls destructor
41 return {result.release(), {alloc}};
42 }
43
44 template <typename T, typename... Args>
45 void construct(std::true_type, T* cur, T* end, Args&&... args)
46 {
47 for (; cur != end; ++cur)
48 ::new (static_cast<void*>(cur)) T(detail::forward<Args>(args)...);
49 }
50
51 template <typename T, typename... Args>
52 void construct(std::false_type, T* begin, T* end, Args&&... args)
53 {
54#if WPI_HAS_EXCEPTION_SUPPORT
55 auto cur = begin;
56 try
57 {
58 for (; cur != end; ++cur)
59 ::new (static_cast<void*>(cur)) T(detail::forward<Args>(args)...);
60 }
61 catch (...)
62 {
63 for (auto el = begin; el != cur; ++el)
64 el->~T();
65 throw;
66 }
67#else
68 construct(std::true_type{}, begin, end, detail::forward<Args>(args)...);
69#endif
70 }
71
72 template <typename T, class RawAllocator>
74 -> std::unique_ptr<T[], allocator_deleter<T[], RawAllocator>>
75 {
76 using raw_ptr = std::unique_ptr<T[], allocator_deallocator<T[], RawAllocator>>;
77
78 auto memory = alloc.allocate_array(size, sizeof(T), alignof(T));
79 // raw_ptr deallocates memory in case of constructor exception
80 raw_ptr result(static_cast<T*>(memory), {alloc, size});
81 construct(std::integral_constant<bool, noexcept(T())>{}, result.get(),
82 result.get() + size);
83 // pass ownership to return value using a deleter that calls destructor
84 return {result.release(), {alloc, size}};
85 }
86 } // namespace detail
87
88 /// A \c std::unique_ptr that deletes using a RawAllocator.
89 ///
90 /// It is an alias template using \ref allocator_deleter as \c Deleter class.
91 /// \ingroup memory_adapter
92 template <typename T, class RawAllocator>
93 WPI_ALIAS_TEMPLATE(unique_ptr,
95
96 /// A \c std::unique_ptr that deletes using a RawAllocator and allows polymorphic types.
97 ///
98 /// It can only be created by converting a regular unique pointer to a pointer to a derived class,
99 /// and is meant to be used inside containers.
100 /// It is an alias template using \ref allocator_polymorphic_deleter as \c Deleter class.
101 /// \note It has a relatively high overhead, so only use it if you have to.
102 /// \ingroup memory_adapter
103 template <class BaseType, class RawAllocator>
107
108 /// Creates a \c std::unique_ptr using a RawAllocator for the allocation.
109 /// \effects Allocates memory for the given type using the allocator
110 /// and creates a new object inside it passing the given arguments to its constructor.
111 /// \returns A \c std::unique_ptr owning that memory.
112 /// \note If the allocator is stateful a reference to the \c RawAllocator will be stored inside the deleter,
113 /// the caller has to ensure that the object lives as long as the smart pointer.
114 /// \ingroup memory_adapter
115 template <typename T, class RawAllocator, typename... Args>
116 auto allocate_unique(RawAllocator&& alloc, Args&&... args) -> WPI_REQUIRES_RET(
117 !std::is_array<T>::value,
118 std::unique_ptr<T, allocator_deleter<T, typename std::decay<RawAllocator>::type>>)
119 {
122 detail::forward<Args>(args)...);
123 }
124
125 /// Creates a \c std::unique_ptr using a type-erased RawAllocator for the allocation.
126 /// It is the same as the other overload but stores the reference to the allocator type-erased inside the \c std::unique_ptr.
127 /// \effects Allocates memory for the given type using the allocator
128 /// and creates a new object inside it passing the given arguments to its constructor.
129 /// \returns A \c std::unique_ptr with a type-erased allocator reference owning that memory.
130 /// \note If the allocator is stateful a reference to the \c RawAllocator will be stored inside the deleter,
131 /// the caller has to ensure that the object lives as long as the smart pointer.
132 /// \ingroup memory_adapter
133 template <typename T, class RawAllocator, typename... Args>
134 auto allocate_unique(any_allocator, RawAllocator&& alloc, Args&&... args)
135 -> WPI_REQUIRES_RET(!std::is_array<T>::value,
136 std::unique_ptr<T, allocator_deleter<T, any_allocator>>)
137 {
140 alloc)),
141 detail::forward<Args>(args)...);
142 }
143
144 /// Creates a \c std::unique_ptr owning an array using a RawAllocator for the allocation.
145 /// \effects Allocates memory for an array of given size and value initializes each element inside of it.
146 /// \returns A \c std::unique_ptr owning that array.
147 /// \note If the allocator is stateful a reference to the \c RawAllocator will be stored inside the deleter,
148 /// the caller has to ensure that the object lives as long as the smart pointer.
149 /// \ingroup memory_adapter
150 template <typename T, class RawAllocator>
151 auto allocate_unique(RawAllocator&& alloc, std::size_t size) -> WPI_REQUIRES_RET(
152 std::is_array<T>::value,
153 std::unique_ptr<T, allocator_deleter<T, typename std::decay<RawAllocator>::type>>)
154 {
156 typename std::remove_extent<T>::type>(size,
159 }
160
161 /// Creates a \c std::unique_ptr owning an array using a type-erased RawAllocator for the allocation.
162 /// It is the same as the other overload but stores the reference to the allocator type-erased inside the \c std::unique_ptr.
163 /// \effects Allocates memory for an array of given size and value initializes each element inside of it.
164 /// \returns A \c std::unique_ptr with a type-erased allocator reference owning that array.
165 /// \note If the allocator is stateful a reference to the \c RawAllocator will be stored inside the deleter,
166 /// the caller has to ensure that the object lives as long as the smart pointer.
167 /// \ingroup memory_adapter
168 template <typename T, class RawAllocator>
169 auto allocate_unique(any_allocator, RawAllocator&& alloc, std::size_t size)
170 -> WPI_REQUIRES_RET(std::is_array<T>::value,
171 std::unique_ptr<T, allocator_deleter<T, any_allocator>>)
172 {
173 return detail::allocate_array_unique<typename std::remove_extent<T>::type,
174 any_allocator>(size,
177 alloc)));
178 }
179
180 /// Creates a \c std::shared_ptr using a RawAllocator for the allocation.
181 /// It is similar to \c std::allocate_shared but uses a \c RawAllocator (and thus also supports any \c Allocator).
182 /// \effects Calls \ref std_allocator::make_std_allocator to wrap the allocator and forwards to \c std::allocate_shared.
183 /// \returns A \c std::shared_ptr created using \c std::allocate_shared.
184 /// \note If the allocator is stateful a reference to the \c RawAllocator will be stored inside the shared pointer,
185 /// the caller has to ensure that the object lives as long as the smart pointer.
186 /// \ingroup memory_adapter
187 template <typename T, class RawAllocator, typename... Args>
188 std::shared_ptr<T> allocate_shared(RawAllocator&& alloc, Args&&... args)
189 {
190 return std::allocate_shared<T>(make_std_allocator<T>(
192 detail::forward<Args>(args)...);
193 }
194 } // namespace memory
195} // namespace wpi
196
197#endif // WPI_MEMORY_SMART_PTR_HPP_INCLUDED
Similar to allocator_deallocator but calls the destructors of the object.
Definition deleter.hpp:165
Similar to allocator_polymorphic_deallocator but calls the destructors of the object.
Definition deleter.hpp:266
An alias template for allocator_storage using the reference_storage policy.
Definition allocator_storage.hpp:900
auto make_allocator_reference(RawAllocator &&allocator) noexcept -> allocator_reference< typename std::decay< RawAllocator >::type >
Definition allocator_storage.hpp:905
auto make_std_allocator(RawAllocator &&allocator) noexcept -> std_allocator< T, typename std::decay< RawAllocator >::type >
Definition std_allocator.hpp:338
A std::unique_ptr that deletes using a RawAllocator and allows polymorphic types.
Definition smart_ptr.hpp:106
Configuration macros.
#define WPI_ALIAS_TEMPLATE(Name,...)
Definition config.hpp:73
Deleter classes using a RawAllocator.
std::shared_ptr< T > allocate_shared(RawAllocator &&alloc, Args &&... args)
Creates a std::shared_ptr using a RawAllocator for the allocation.
Definition smart_ptr.hpp:188
auto allocate_unique(RawAllocator &&alloc, Args &&... args) ->
Creates a std::unique_ptr using a RawAllocator for the allocation.
Definition smart_ptr.hpp:116
detail namespace with internal helper functions
Definition input_adapters.h:32
void construct(std::true_type, T *cur, T *end, Args &&... args)
Definition smart_ptr.hpp:45
auto allocate_array_unique(std::size_t size, allocator_reference< RawAllocator > alloc) -> std::unique_ptr< T[], allocator_deleter< T[], RawAllocator > >
Definition smart_ptr.hpp:73
auto allocate_unique(allocator_reference< RawAllocator > alloc, Args &&... args) -> std::unique_ptr< T, allocator_deleter< T, RawAllocator > >
Definition smart_ptr.hpp:30
T && forward(typename std::remove_reference< T >::type &t) noexcept
Definition utility.hpp:31
Memory namespace.
Definition heap_allocator.hpp:20
Foonathan namespace.
Definition ntcore_cpp.h:26
Class wpi::memory::std_allocator and related classes and functions.
Tag type that enables type-erasure in reference_storage.
Definition allocator_storage.hpp:322
#define WPI_REQUIRES_RET(Expr,...)
Definition utility.hpp:75