Coverage Report

Created: 2024-07-18 11:41

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