src/zserio/AllocatorPropagatingCopy.h
Line | Count | Source |
1 | | #ifndef ZSERIO_ALLOCATOR_PROPAGATING_COPY_H_INC |
2 | | #define ZSERIO_ALLOCATOR_PROPAGATING_COPY_H_INC |
3 | | |
4 | | #include <algorithm> |
5 | | #include <iterator> |
6 | | #include <memory> |
7 | | #include <type_traits> |
8 | | #include <vector> |
9 | | |
10 | | #include "zserio/AnyHolder.h" |
11 | | #include "zserio/NoInit.h" |
12 | | #include "zserio/OptionalHolder.h" |
13 | | |
14 | | namespace zserio |
15 | | { |
16 | | |
17 | | /** |
18 | | * Helper type for specification of allocator propagation. |
19 | | */ |
20 | | struct PropagateAllocatorT |
21 | | { |
22 | | constexpr explicit PropagateAllocatorT() = default; |
23 | | }; |
24 | | |
25 | | /** |
26 | | * Constant used to convenient specification of allocator propagation. |
27 | | */ |
28 | | constexpr PropagateAllocatorT PropagateAllocator; |
29 | | |
30 | | template <typename T, typename ALLOC> |
31 | | T allocatorPropagatingCopy(const T& source, const ALLOC& allocator); |
32 | | |
33 | | template <typename T, typename ALLOC, typename ALLOC2> |
34 | | AnyHolder<ALLOC> allocatorPropagatingCopy(const AnyHolder<ALLOC>& source, const ALLOC2& allocator); |
35 | | |
36 | | template <typename T, typename ALLOC> |
37 | | T allocatorPropagatingCopy(NoInitT, const T& source, const ALLOC& allocator); |
38 | | |
39 | | template <typename T, typename ALLOC, typename ALLOC2> |
40 | | AnyHolder<ALLOC> allocatorPropagatingCopy(NoInitT, const AnyHolder<ALLOC>& source, const ALLOC2& allocator); |
41 | | |
42 | | namespace detail |
43 | | { |
44 | | |
45 | | // implementation for std::basic_string from old std. libs, that does not fully conform |
46 | | // to C++11. [old-compiler-support] |
47 | | template <typename CharT, typename Traits, typename ALLOC1, typename ALLOC2> |
48 | | std::basic_string<CharT, Traits, ALLOC1> allocatorPropagatingCopyDefault( |
49 | | std::true_type, const std::basic_string<CharT, Traits, ALLOC1>& source, const ALLOC2& allocator) |
50 | 97 | { |
51 | 97 | return std::basic_string<CharT, Traits, ALLOC1>(source.c_str(), source.length(), allocator); |
52 | 97 | } |
53 | | |
54 | | // implementation of copy for vectors of bool from old std. libs, that does not fully |
55 | | // conform to C++11. [old-compiler-support] |
56 | | template <typename ALLOC, typename ALLOC2> |
57 | | std::vector<bool, ALLOC> allocatorPropagatingCopyVec( |
58 | | std::false_type, const std::vector<bool, ALLOC>& source, const ALLOC2& allocator) |
59 | 64 | { |
60 | 64 | std::vector<bool, ALLOC> ret(allocator); |
61 | 64 | ret.reserve(source.size()); |
62 | 64 | ret.assign(source.begin(), source.end()); |
63 | 64 | return ret; |
64 | 64 | } |
65 | | |
66 | | // implementation of copy for "regular" classes that supports allocator |
67 | | template <typename T, typename ALLOC> |
68 | | T allocatorPropagatingCopyDefault(std::true_type, const T& source, const ALLOC& allocator) |
69 | 97 | { |
70 | 97 | return T(source, allocator); |
71 | 97 | } |
72 | | |
73 | | // implementation of copy for "regular" classes that does not support allocator |
74 | | template <typename T, typename ALLOC> |
75 | | T allocatorPropagatingCopyDefault(std::false_type, const T& source, const ALLOC&) |
76 | 577 | { |
77 | 577 | return source; |
78 | 577 | } |
79 | | |
80 | | // implementation of copy for "regular" classes that supports "PropagateAllocator" copy |
81 | | template <typename T, typename ALLOC> |
82 | | T allocatorPropagatingCopyPropagating(std::true_type, const T& source, const ALLOC& allocator) |
83 | 390 | { |
84 | 390 | return T(PropagateAllocator, source, allocator); |
85 | 390 | } |
86 | | |
87 | | // implementation of copy for "regular" classes that supports "PropagateAllocator" copy |
88 | | template <typename T, typename ALLOC> |
89 | | T allocatorPropagatingCopyPropagating(std::true_type, NoInitT, const T& source, const ALLOC& allocator) |
90 | 196 | { |
91 | 196 | return T(PropagateAllocator, NoInit, source, allocator); |
92 | 196 | } |
93 | | |
94 | | // implementation of copy for "regular" classes that does not support "PropagateAllocator" copy |
95 | | template <typename T, typename ALLOC> |
96 | | T allocatorPropagatingCopyPropagating(std::false_type, const T& source, const ALLOC& allocator) |
97 | 771 | { |
98 | 771 | return allocatorPropagatingCopyDefault(std::uses_allocator<T, ALLOC>(), source, allocator); |
99 | 771 | } |
100 | | |
101 | | // implementation of copy for vectors containing type that supports allocator |
102 | | template <typename T, typename ALLOC, typename ALLOC2> |
103 | | std::vector<T, ALLOC> allocatorPropagatingCopyVec( |
104 | | std::true_type, const std::vector<T, ALLOC>& source, const ALLOC2& allocator) |
105 | 354 | { |
106 | 354 | std::vector<T, ALLOC> result(allocator); |
107 | 354 | result.reserve(source.size()); |
108 | 642 | std::transform(source.begin(), source.end(), std::back_inserter(result), [&](const T& value) { |
109 | 642 | return allocatorPropagatingCopy(value, allocator); |
110 | 642 | }); |
111 | 354 | return result; |
112 | 354 | } |
113 | | |
114 | | // implementation of copy for vectors containing type that supports allocator |
115 | | template <typename T, typename ALLOC, typename ALLOC2> |
116 | | std::vector<T, ALLOC> allocatorPropagatingCopyVec( |
117 | | std::true_type, NoInitT, const std::vector<T, ALLOC>& source, const ALLOC2& allocator) |
118 | 64 | { |
119 | 64 | std::vector<T, ALLOC> result(allocator); |
120 | 64 | result.reserve(source.size()); |
121 | 192 | std::transform(source.begin(), source.end(), std::back_inserter(result), [&](const T& value) { |
122 | 192 | return allocatorPropagatingCopy(NoInit, value, allocator); |
123 | 192 | }); |
124 | 64 | return result; |
125 | 64 | } |
126 | | |
127 | | // implementation of copy for vectors containing type that does not support allocator |
128 | | template <typename T, typename ALLOC, typename ALLOC2> |
129 | | std::vector<T, ALLOC> allocatorPropagatingCopyVec( |
130 | | std::false_type, const std::vector<T, ALLOC>& source, const ALLOC2& allocator) |
131 | 2.96k | { |
132 | 2.96k | return std::vector<T, ALLOC>(source, allocator); |
133 | 2.96k | } |
134 | | |
135 | | template <typename T, typename ALLOC> |
136 | | T allocatorPropagatingCopyImpl(const T& source, const ALLOC& allocator) |
137 | 1.16k | { |
138 | 1.16k | return allocatorPropagatingCopyPropagating( |
139 | 1.16k | std::is_constructible<T, PropagateAllocatorT, T, ALLOC>(), source, allocator); |
140 | 1.16k | } |
141 | | |
142 | | template <typename T, typename ALLOC> |
143 | | T allocatorPropagatingCopyImpl(NoInitT, const T& source, const ALLOC& allocator) |
144 | 196 | { |
145 | 196 | static_assert(std::is_constructible<T, NoInitT, T>::value, "Can be used only for parameterized compounds!"); |
146 | | |
147 | 196 | return allocatorPropagatingCopyPropagating( |
148 | 196 | std::is_constructible<T, PropagateAllocatorT, NoInitT, T, ALLOC>(), NoInit, source, allocator); |
149 | 196 | } |
150 | | |
151 | | template <typename T, typename ALLOC, typename ALLOC2> |
152 | | HeapOptionalHolder<T, ALLOC> allocatorPropagatingCopyImpl( |
153 | | const HeapOptionalHolder<T, ALLOC>& source, const ALLOC2& allocator) |
154 | 2 | { |
155 | 2 | if (source.hasValue()) |
156 | 1 | return HeapOptionalHolder<T, ALLOC>(allocatorPropagatingCopy(*source, allocator), allocator); |
157 | 1 | else |
158 | 1 | return HeapOptionalHolder<T, ALLOC>(allocator); |
159 | 2 | } |
160 | | |
161 | | template <typename T, typename ALLOC, typename ALLOC2> |
162 | | HeapOptionalHolder<T, ALLOC> allocatorPropagatingCopyImpl( |
163 | | NoInitT, const HeapOptionalHolder<T, ALLOC>& source, const ALLOC2& allocator) |
164 | 2 | { |
165 | 2 | static_assert(std::is_constructible<T, NoInitT, T>::value, "Can be used only for parameterized compounds!"); |
166 | | |
167 | 2 | if (source.hasValue()) |
168 | 1 | { |
169 | 1 | return HeapOptionalHolder<T, ALLOC>( |
170 | 1 | NoInit, allocatorPropagatingCopy(NoInit, *source, allocator), allocator); |
171 | 1 | } |
172 | 1 | else |
173 | 1 | return HeapOptionalHolder<T, ALLOC>(allocator); |
174 | 2 | } |
175 | | |
176 | | template <typename T, typename ALLOC> |
177 | | InplaceOptionalHolder<T> allocatorPropagatingCopyImpl( |
178 | | const InplaceOptionalHolder<T>& source, const ALLOC& allocator) |
179 | 2 | { |
180 | 2 | if (source.hasValue()) |
181 | 1 | return InplaceOptionalHolder<T>(allocatorPropagatingCopy(*source, allocator)); |
182 | 1 | else |
183 | 1 | return InplaceOptionalHolder<T>(); |
184 | 2 | } |
185 | | |
186 | | template <typename T, typename ALLOC> |
187 | | InplaceOptionalHolder<T> allocatorPropagatingCopyImpl( |
188 | | NoInitT, const InplaceOptionalHolder<T>& source, const ALLOC& allocator) |
189 | 2 | { |
190 | 2 | static_assert(std::is_constructible<T, NoInitT, T>::value, "Can be used only for parameterized compounds!"); |
191 | | |
192 | 2 | if (source.hasValue()) |
193 | 1 | return InplaceOptionalHolder<T>(NoInit, allocatorPropagatingCopy(NoInit, *source, allocator)); |
194 | 1 | else |
195 | 1 | return InplaceOptionalHolder<T>(); |
196 | 2 | } |
197 | | |
198 | | template <typename T, typename ALLOC, typename ALLOC2> |
199 | | AnyHolder<ALLOC> allocatorPropagatingCopyImpl(const AnyHolder<ALLOC>& source, const ALLOC2& allocator) |
200 | 2 | { |
201 | 2 | if (source.hasValue()) |
202 | 1 | { |
203 | 1 | return AnyHolder<ALLOC>(allocatorPropagatingCopy(source.template get<T>(), allocator), allocator); |
204 | 1 | } |
205 | 1 | else |
206 | 1 | { |
207 | 1 | return AnyHolder<ALLOC>(allocator); |
208 | 1 | } |
209 | 2 | } |
210 | | |
211 | | template <typename T, typename ALLOC, typename ALLOC2> |
212 | | AnyHolder<ALLOC> allocatorPropagatingCopyImpl(NoInitT, const AnyHolder<ALLOC>& source, const ALLOC2& allocator) |
213 | 2 | { |
214 | 2 | if (source.hasValue()) |
215 | 1 | { |
216 | 1 | return AnyHolder<ALLOC>( |
217 | 1 | NoInit, allocatorPropagatingCopy(NoInit, source.template get<T>(), allocator), allocator); |
218 | 1 | } |
219 | 1 | else |
220 | 1 | { |
221 | 1 | return AnyHolder<ALLOC>(allocator); |
222 | 1 | } |
223 | 2 | } |
224 | | |
225 | | template <typename T, typename ALLOC, typename ALLOC2> |
226 | | std::vector<T, ALLOC> allocatorPropagatingCopyImpl(const std::vector<T, ALLOC>& source, const ALLOC2& allocator) |
227 | 3.37k | { |
228 | 3.37k | return allocatorPropagatingCopyVec(std::uses_allocator<T, ALLOC>(), source, allocator); |
229 | 3.37k | } |
230 | | |
231 | | template <typename T, typename ALLOC, typename ALLOC2> |
232 | | std::vector<T, ALLOC> allocatorPropagatingCopyImpl( |
233 | | NoInitT, const std::vector<T, ALLOC>& source, const ALLOC2& allocator) |
234 | 64 | { |
235 | 64 | static_assert(std::is_constructible<T, NoInitT, T>::value, "Can be used only for parameterized compounds!"); |
236 | | |
237 | 64 | return allocatorPropagatingCopyVec(std::uses_allocator<T, ALLOC>(), NoInit, source, allocator); |
238 | 64 | } |
239 | | |
240 | | } // namespace detail |
241 | | |
242 | | /** |
243 | | * Copy the input object, propagating the allocator where needed. |
244 | | * |
245 | | * \param source Object to copy. |
246 | | * \param allocator Allocator to be propagated to the target object type constructor. |
247 | | * |
248 | | * \return Object copy. |
249 | | */ |
250 | | template <typename T, typename ALLOC> |
251 | | T allocatorPropagatingCopy(const T& source, const ALLOC& allocator) |
252 | 4.54k | { |
253 | 4.54k | static_assert(!std::is_same<AnyHolder<ALLOC>, T>::value, "Cannot be used for AnyHolder!"); |
254 | | |
255 | 4.54k | return detail::allocatorPropagatingCopyImpl(source, allocator); |
256 | 4.54k | } |
257 | | |
258 | | /** |
259 | | * Copy the input object, propagating the allocator where needed and prevents initialization. |
260 | | * |
261 | | * \param source Object to copy. |
262 | | * \param allocator Allocator to be propagated to the target object type constructor. |
263 | | * |
264 | | * \return Object copy. |
265 | | */ |
266 | | template <typename T, typename ALLOC> |
267 | | T allocatorPropagatingCopy(NoInitT, const T& source, const ALLOC& allocator) |
268 | 264 | { |
269 | 264 | static_assert(!std::is_same<AnyHolder<ALLOC>, T>::value, "Cannot be used for AnyHolder!"); |
270 | | |
271 | 264 | return detail::allocatorPropagatingCopyImpl(NoInit, source, allocator); |
272 | 264 | } |
273 | | |
274 | | /** |
275 | | * Copy the input any holder, propagating the allocator where needed. |
276 | | * |
277 | | * \param source Any holder to copy. |
278 | | * \param allocator Allocator to be propagated to the target object type constructor. |
279 | | * |
280 | | * \return Copy of any holder. |
281 | | */ |
282 | | template <typename T, typename ALLOC, typename ALLOC2> |
283 | | AnyHolder<ALLOC> allocatorPropagatingCopy(const AnyHolder<ALLOC>& source, const ALLOC2& allocator) |
284 | 2 | { |
285 | 2 | return detail::allocatorPropagatingCopyImpl<T>(source, allocator); |
286 | 2 | } |
287 | | |
288 | | /** |
289 | | * Copy the input any holder, propagating the allocator where needed and prevents initialization. |
290 | | * |
291 | | * \param source Any holder to copy. |
292 | | * \param allocator Allocator to be propagated to the target object type constructor. |
293 | | * |
294 | | * \return Copy of any holder. |
295 | | */ |
296 | | template <typename T, typename ALLOC, typename ALLOC2> |
297 | | AnyHolder<ALLOC> allocatorPropagatingCopy(NoInitT, const AnyHolder<ALLOC>& source, const ALLOC2& allocator) |
298 | 2 | { |
299 | 2 | static_assert(std::is_constructible<T, NoInitT, T>::value, "Can be used only for parameterized compounds!"); |
300 | | |
301 | 2 | return detail::allocatorPropagatingCopyImpl<T>(NoInit, source, allocator); |
302 | 2 | } |
303 | | |
304 | | } // namespace zserio |
305 | | |
306 | | #endif // ZSERIO_ALLOCATOR_PROPAGATING_COPY_H_INC |