Coverage Report

Created: 2023-12-13 14:58

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