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 <type_traits> |
7 | | #include <memory> |
8 | | #include <vector> |
9 | | |
10 | | #include "zserio/OptionalHolder.h" |
11 | | #include "zserio/AnyHolder.h" |
12 | | #include "zserio/NoInit.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( |
35 | | const AnyHolder<ALLOC>& source, const ALLOC2& allocator); |
36 | | |
37 | | template <typename T, typename ALLOC> |
38 | | T allocatorPropagatingCopy(NoInitT, const T& source, const ALLOC& allocator); |
39 | | |
40 | | template <typename T, typename ALLOC, typename ALLOC2> |
41 | | AnyHolder<ALLOC> allocatorPropagatingCopy( |
42 | | NoInitT, const AnyHolder<ALLOC>& source, const ALLOC2& allocator); |
43 | | |
44 | | namespace detail |
45 | | { |
46 | | |
47 | | // implementation for std::basic_string from old std. libs, that does not fully conform |
48 | | // to C++11. [old-compiler-support] |
49 | | template <typename CharT, typename Traits, typename ALLOC1, typename ALLOC2> |
50 | | std::basic_string<CharT, Traits, ALLOC1> allocatorPropagatingCopyDefault(std::true_type, |
51 | | const std::basic_string<CharT, Traits, ALLOC1>& source, const ALLOC2& allocator) |
52 | 97 | { |
53 | 97 | return std::basic_string<CharT, Traits, ALLOC1>(source.c_str(), source.length(), allocator); |
54 | 97 | } |
55 | | |
56 | | // implementation of copy for vectors of bool from old std. libs, that does not fully |
57 | | // conform to C++11. [old-compiler-support] |
58 | | template <typename ALLOC, typename ALLOC2> |
59 | | std::vector<bool, ALLOC> allocatorPropagatingCopyVec( |
60 | | std::false_type, const std::vector<bool, ALLOC>& source, const ALLOC2& allocator) |
61 | 64 | { |
62 | 64 | std::vector<bool, ALLOC> ret(allocator); |
63 | 64 | ret.reserve(source.size()); |
64 | 64 | ret.assign(source.begin(), source.end()); |
65 | 64 | return ret; |
66 | 64 | } |
67 | | |
68 | | // implementation of copy for "regular" classes that supports allocator |
69 | | template <typename T, typename ALLOC> |
70 | | T allocatorPropagatingCopyDefault(std::true_type, const T& source, const ALLOC& allocator) |
71 | 97 | { |
72 | 97 | return T(source, allocator); |
73 | 97 | } |
74 | | |
75 | | // implementation of copy for "regular" classes that does not support allocator |
76 | | template <typename T, typename ALLOC> |
77 | | T allocatorPropagatingCopyDefault(std::false_type, const T& source, const ALLOC&) |
78 | 577 | { |
79 | 577 | return source; |
80 | 577 | } |
81 | | |
82 | | // implementation of copy for "regular" classes that supports "PropagateAllocator" copy |
83 | | template <typename T, typename ALLOC> |
84 | | T allocatorPropagatingCopyPropagating(std::true_type, const T& source, const ALLOC& allocator) |
85 | 390 | { |
86 | 390 | return T(PropagateAllocator, source, allocator); |
87 | 390 | } |
88 | | |
89 | | // implementation of copy for "regular" classes that supports "PropagateAllocator" copy |
90 | | template <typename T, typename ALLOC> |
91 | | T allocatorPropagatingCopyPropagating(std::true_type, NoInitT, const T& source, const ALLOC& allocator) |
92 | 196 | { |
93 | 196 | return T(PropagateAllocator, NoInit, source, allocator); |
94 | 196 | } |
95 | | |
96 | | // implementation of copy for "regular" classes that does not support "PropagateAllocator" copy |
97 | | template <typename T, typename ALLOC> |
98 | | T allocatorPropagatingCopyPropagating(std::false_type, const T& source, const ALLOC& allocator) |
99 | 771 | { |
100 | 771 | return allocatorPropagatingCopyDefault(std::uses_allocator<T, ALLOC>(), source, allocator); |
101 | 771 | } |
102 | | |
103 | | // implementation of copy for vectors containing type that supports allocator |
104 | | template <typename T, typename ALLOC, typename ALLOC2> |
105 | | std::vector<T, ALLOC> allocatorPropagatingCopyVec( |
106 | | std::true_type, const std::vector<T, ALLOC>& source, const ALLOC2& allocator) |
107 | 354 | { |
108 | 354 | std::vector<T, ALLOC> result(allocator); |
109 | 354 | result.reserve(source.size()); |
110 | 354 | std::transform(source.begin(), source.end(), std::back_inserter(result), |
111 | 642 | [&](const T& value){ return allocatorPropagatingCopy(value, allocator); }); |
112 | 354 | return result; |
113 | 354 | } |
114 | | |
115 | | // implementation of copy for vectors containing type that supports allocator |
116 | | template <typename T, typename ALLOC, typename ALLOC2> |
117 | | std::vector<T, ALLOC> allocatorPropagatingCopyVec( |
118 | | std::true_type, NoInitT, const std::vector<T, ALLOC>& source, const ALLOC2& allocator) |
119 | 64 | { |
120 | 64 | std::vector<T, ALLOC> result(allocator); |
121 | 64 | result.reserve(source.size()); |
122 | 64 | std::transform(source.begin(), source.end(), std::back_inserter(result), |
123 | 192 | [&](const T& value) { return allocatorPropagatingCopy(NoInit, value, allocator); }); |
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>(NoInit, allocatorPropagatingCopy(NoInit, *source, allocator), |
170 | 1 | 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( |
200 | | const AnyHolder<ALLOC>& source, const ALLOC2& allocator) |
201 | 2 | { |
202 | 2 | if (source.hasValue()) |
203 | 1 | { |
204 | 1 | return AnyHolder<ALLOC>(allocatorPropagatingCopy(source.template get<T>(), allocator), |
205 | 1 | allocator); |
206 | 1 | } |
207 | 1 | else |
208 | 1 | { |
209 | 1 | return AnyHolder<ALLOC>(allocator); |
210 | 1 | } |
211 | 2 | } |
212 | | |
213 | | template <typename T, typename ALLOC, typename ALLOC2> |
214 | | AnyHolder<ALLOC> allocatorPropagatingCopyImpl( |
215 | | NoInitT, const AnyHolder<ALLOC>& source, const ALLOC2& allocator) |
216 | 2 | { |
217 | 2 | if (source.hasValue()) |
218 | 1 | { |
219 | 1 | return AnyHolder<ALLOC>(NoInit, allocatorPropagatingCopy(NoInit, source.template get<T>(), allocator), |
220 | 1 | allocator); |
221 | 1 | } |
222 | 1 | else |
223 | 1 | { |
224 | 1 | return AnyHolder<ALLOC>(allocator); |
225 | 1 | } |
226 | 2 | } |
227 | | |
228 | | template <typename T, typename ALLOC, typename ALLOC2> |
229 | | std::vector<T, ALLOC> allocatorPropagatingCopyImpl( |
230 | | const std::vector<T, ALLOC>& source, const ALLOC2& allocator) |
231 | 3.37k | { |
232 | 3.37k | return allocatorPropagatingCopyVec(std::uses_allocator<T, ALLOC>(), source, allocator); |
233 | 3.37k | } |
234 | | |
235 | | template <typename T, typename ALLOC, typename ALLOC2> |
236 | | std::vector<T, ALLOC> allocatorPropagatingCopyImpl( |
237 | | NoInitT, const std::vector<T, ALLOC>& source, const ALLOC2& allocator) |
238 | 64 | { |
239 | 64 | static_assert(std::is_constructible<T, NoInitT, T>::value, "Can be used only for parameterized compounds!"); |
240 | | |
241 | 64 | return allocatorPropagatingCopyVec(std::uses_allocator<T, ALLOC>(), NoInit, source, allocator); |
242 | 64 | } |
243 | | |
244 | | } // namespace detail |
245 | | |
246 | | /** |
247 | | * Copy the input object, propagating the allocator where needed. |
248 | | * |
249 | | * \param source Object to copy. |
250 | | * \param allocator Allocator to be propagated to the target object type constructor. |
251 | | * |
252 | | * \return Object copy. |
253 | | */ |
254 | | template <typename T, typename ALLOC> |
255 | | T allocatorPropagatingCopy(const T& source, const ALLOC& allocator) |
256 | 4.54k | { |
257 | 4.54k | static_assert(!std::is_same<AnyHolder<ALLOC>, T>::value, "Cannot be used for AnyHolder!"); |
258 | | |
259 | 4.54k | return detail::allocatorPropagatingCopyImpl(source, allocator); |
260 | 4.54k | } |
261 | | |
262 | | /** |
263 | | * Copy the input object, propagating the allocator where needed and prevents initialization. |
264 | | * |
265 | | * \param source Object to copy. |
266 | | * \param allocator Allocator to be propagated to the target object type constructor. |
267 | | * |
268 | | * \return Object copy. |
269 | | */ |
270 | | template <typename T, typename ALLOC> |
271 | | T allocatorPropagatingCopy(NoInitT, const T& source, const ALLOC& allocator) |
272 | 264 | { |
273 | 264 | static_assert(!std::is_same<AnyHolder<ALLOC>, T>::value, "Cannot be used for AnyHolder!"); |
274 | | |
275 | 264 | return detail::allocatorPropagatingCopyImpl(NoInit, source, allocator); |
276 | 264 | } |
277 | | |
278 | | /** |
279 | | * Copy the input any holder, propagating the allocator where needed. |
280 | | * |
281 | | * \param source Any holder to copy. |
282 | | * \param allocator Allocator to be propagated to the target object type constructor. |
283 | | * |
284 | | * \return Copy of any holder. |
285 | | */ |
286 | | template <typename T, typename ALLOC, typename ALLOC2> |
287 | | AnyHolder<ALLOC> allocatorPropagatingCopy( |
288 | | const AnyHolder<ALLOC>& source, const ALLOC2& allocator) |
289 | 2 | { |
290 | 2 | return detail::allocatorPropagatingCopyImpl<T>(source, allocator); |
291 | 2 | } |
292 | | |
293 | | /** |
294 | | * Copy the input any holder, propagating the allocator where needed and prevents initialization. |
295 | | * |
296 | | * \param source Any holder to copy. |
297 | | * \param allocator Allocator to be propagated to the target object type constructor. |
298 | | * |
299 | | * \return Copy of any holder. |
300 | | */ |
301 | | template <typename T, typename ALLOC, typename ALLOC2> |
302 | | AnyHolder<ALLOC> allocatorPropagatingCopy( |
303 | | NoInitT, const AnyHolder<ALLOC>& source, const ALLOC2& allocator) |
304 | 2 | { |
305 | 2 | static_assert(std::is_constructible<T, NoInitT, T>::value, "Can be used only for parameterized compounds!"); |
306 | | |
307 | 2 | return detail::allocatorPropagatingCopyImpl<T>(NoInit, source, allocator); |
308 | 2 | } |
309 | | |
310 | | } // namespace zserio |
311 | | |
312 | | #endif // ZSERIO_ALLOCATOR_PROPAGATING_COPY_H_INC |