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 | { |
157 | 1 | return HeapOptionalHolder<T, ALLOC>(allocatorPropagatingCopy(*source, allocator), allocator); |
158 | 1 | } |
159 | 1 | else |
160 | 1 | { |
161 | 1 | return HeapOptionalHolder<T, ALLOC>(allocator); |
162 | 1 | } |
163 | 2 | } |
164 | | |
165 | | template <typename T, typename ALLOC, typename ALLOC2> |
166 | | HeapOptionalHolder<T, ALLOC> allocatorPropagatingCopyImpl( |
167 | | NoInitT, const HeapOptionalHolder<T, ALLOC>& source, const ALLOC2& allocator) |
168 | 2 | { |
169 | 2 | static_assert(std::is_constructible<T, NoInitT, T>::value, "Can be used only for parameterized compounds!"); |
170 | | |
171 | 2 | if (source.hasValue()) |
172 | 1 | { |
173 | 1 | return HeapOptionalHolder<T, ALLOC>( |
174 | 1 | NoInit, allocatorPropagatingCopy(NoInit, *source, allocator), allocator); |
175 | 1 | } |
176 | 1 | else |
177 | 1 | { |
178 | 1 | return HeapOptionalHolder<T, ALLOC>(allocator); |
179 | 1 | } |
180 | 2 | } |
181 | | |
182 | | template <typename T, typename ALLOC> |
183 | | InplaceOptionalHolder<T> allocatorPropagatingCopyImpl( |
184 | | const InplaceOptionalHolder<T>& source, const ALLOC& allocator) |
185 | 2 | { |
186 | 2 | if (source.hasValue()) |
187 | 1 | { |
188 | 1 | return InplaceOptionalHolder<T>(allocatorPropagatingCopy(*source, allocator)); |
189 | 1 | } |
190 | 1 | else |
191 | 1 | { |
192 | 1 | return InplaceOptionalHolder<T>(); |
193 | 1 | } |
194 | 2 | } |
195 | | |
196 | | template <typename T, typename ALLOC> |
197 | | InplaceOptionalHolder<T> allocatorPropagatingCopyImpl( |
198 | | NoInitT, const InplaceOptionalHolder<T>& source, const ALLOC& allocator) |
199 | 2 | { |
200 | 2 | static_assert(std::is_constructible<T, NoInitT, T>::value, "Can be used only for parameterized compounds!"); |
201 | | |
202 | 2 | if (source.hasValue()) |
203 | 1 | { |
204 | 1 | return InplaceOptionalHolder<T>(NoInit, allocatorPropagatingCopy(NoInit, *source, allocator)); |
205 | 1 | } |
206 | 1 | else |
207 | 1 | { |
208 | 1 | return InplaceOptionalHolder<T>(); |
209 | 1 | } |
210 | 2 | } |
211 | | |
212 | | template <typename T, typename ALLOC, typename ALLOC2> |
213 | | AnyHolder<ALLOC> allocatorPropagatingCopyImpl(const AnyHolder<ALLOC>& source, const ALLOC2& allocator) |
214 | 2 | { |
215 | 2 | if (source.hasValue()) |
216 | 1 | { |
217 | 1 | return AnyHolder<ALLOC>(allocatorPropagatingCopy(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 | | AnyHolder<ALLOC> allocatorPropagatingCopyImpl(NoInitT, const AnyHolder<ALLOC>& source, const ALLOC2& allocator) |
227 | 2 | { |
228 | 2 | if (source.hasValue()) |
229 | 1 | { |
230 | 1 | return AnyHolder<ALLOC>( |
231 | 1 | NoInit, allocatorPropagatingCopy(NoInit, source.template get<T>(), allocator), allocator); |
232 | 1 | } |
233 | 1 | else |
234 | 1 | { |
235 | 1 | return AnyHolder<ALLOC>(allocator); |
236 | 1 | } |
237 | 2 | } |
238 | | |
239 | | template <typename T, typename ALLOC, typename ALLOC2> |
240 | | std::vector<T, ALLOC> allocatorPropagatingCopyImpl(const std::vector<T, ALLOC>& source, const ALLOC2& allocator) |
241 | 3.37k | { |
242 | 3.37k | return allocatorPropagatingCopyVec(std::uses_allocator<T, ALLOC>(), source, allocator); |
243 | 3.37k | } |
244 | | |
245 | | template <typename T, typename ALLOC, typename ALLOC2> |
246 | | std::vector<T, ALLOC> allocatorPropagatingCopyImpl( |
247 | | NoInitT, const std::vector<T, ALLOC>& source, const ALLOC2& allocator) |
248 | 64 | { |
249 | 64 | static_assert(std::is_constructible<T, NoInitT, T>::value, "Can be used only for parameterized compounds!"); |
250 | | |
251 | 64 | return allocatorPropagatingCopyVec(std::uses_allocator<T, ALLOC>(), NoInit, source, allocator); |
252 | 64 | } |
253 | | |
254 | | } // namespace detail |
255 | | |
256 | | /** |
257 | | * Copy the input object, propagating the allocator where needed. |
258 | | * |
259 | | * \param source Object to copy. |
260 | | * \param allocator Allocator to be propagated to the target object type constructor. |
261 | | * |
262 | | * \return Object copy. |
263 | | */ |
264 | | template <typename T, typename ALLOC> |
265 | | T allocatorPropagatingCopy(const T& source, const ALLOC& allocator) |
266 | 4.54k | { |
267 | 4.54k | static_assert(!std::is_same<AnyHolder<ALLOC>, T>::value, "Cannot be used for AnyHolder!"); |
268 | | |
269 | 4.54k | return detail::allocatorPropagatingCopyImpl(source, allocator); |
270 | 4.54k | } |
271 | | |
272 | | /** |
273 | | * Copy the input object, propagating the allocator where needed and prevents initialization. |
274 | | * |
275 | | * \param source Object to copy. |
276 | | * \param allocator Allocator to be propagated to the target object type constructor. |
277 | | * |
278 | | * \return Object copy. |
279 | | */ |
280 | | template <typename T, typename ALLOC> |
281 | | T allocatorPropagatingCopy(NoInitT, const T& source, const ALLOC& allocator) |
282 | 264 | { |
283 | 264 | static_assert(!std::is_same<AnyHolder<ALLOC>, T>::value, "Cannot be used for AnyHolder!"); |
284 | | |
285 | 264 | return detail::allocatorPropagatingCopyImpl(NoInit, source, allocator); |
286 | 264 | } |
287 | | |
288 | | /** |
289 | | * Copy the input any holder, propagating the allocator where needed. |
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(const AnyHolder<ALLOC>& source, const ALLOC2& allocator) |
298 | 2 | { |
299 | 2 | return detail::allocatorPropagatingCopyImpl<T>(source, allocator); |
300 | 2 | } |
301 | | |
302 | | /** |
303 | | * Copy the input any holder, propagating the allocator where needed and prevents initialization. |
304 | | * |
305 | | * \param source Any holder to copy. |
306 | | * \param allocator Allocator to be propagated to the target object type constructor. |
307 | | * |
308 | | * \return Copy of any holder. |
309 | | */ |
310 | | template <typename T, typename ALLOC, typename ALLOC2> |
311 | | AnyHolder<ALLOC> allocatorPropagatingCopy(NoInitT, const AnyHolder<ALLOC>& source, const ALLOC2& allocator) |
312 | 2 | { |
313 | 2 | static_assert(std::is_constructible<T, NoInitT, T>::value, "Can be used only for parameterized compounds!"); |
314 | | |
315 | 2 | return detail::allocatorPropagatingCopyImpl<T>(NoInit, source, allocator); |
316 | 2 | } |
317 | | |
318 | | } // namespace zserio |
319 | | |
320 | | #endif // ZSERIO_ALLOCATOR_PROPAGATING_COPY_H_INC |