GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/zserio/AllocatorPropagatingCopy.h Lines: 75 75 100.0 %
Date: 2023-12-13 14:51:09 Branches: 59 195 30.3 %

Line Branch Exec 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
97
std::basic_string<CharT, Traits, ALLOC1> allocatorPropagatingCopyDefault(std::true_type,
51
        const std::basic_string<CharT, Traits, ALLOC1>& source, const ALLOC2& allocator)
52
{
53

97
    return std::basic_string<CharT, Traits, ALLOC1>(source.c_str(), source.length(), allocator);
54
}
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
64
std::vector<bool, ALLOC> allocatorPropagatingCopyVec(
60
        std::false_type, const std::vector<bool, ALLOC>& source, const ALLOC2& allocator)
61
{
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
}
67
68
// implementation of copy for "regular" classes that supports allocator
69
template <typename T, typename ALLOC>
70
97
T allocatorPropagatingCopyDefault(std::true_type, const T& source, const ALLOC& allocator)
71
{
72
97
    return T(source, allocator);
73
}
74
75
// implementation of copy for "regular" classes that does not support allocator
76
template <typename T, typename ALLOC>
77
577
T allocatorPropagatingCopyDefault(std::false_type, const T& source, const ALLOC&)
78
{
79
577
    return source;
80
}
81
82
// implementation of copy for "regular" classes that supports "PropagateAllocator" copy
83
template <typename T, typename ALLOC>
84
390
T allocatorPropagatingCopyPropagating(std::true_type, const T& source, const ALLOC& allocator)
85
{
86



390
    return T(PropagateAllocator, source, allocator);
87
}
88
89
// implementation of copy for "regular" classes that supports "PropagateAllocator" copy
90
template <typename T, typename ALLOC>
91
196
T allocatorPropagatingCopyPropagating(std::true_type, NoInitT, const T& source, const ALLOC& allocator)
92
{
93

196
    return T(PropagateAllocator, NoInit, source, allocator);
94
}
95
96
// implementation of copy for "regular" classes that does not support "PropagateAllocator" copy
97
template <typename T, typename ALLOC>
98
771
T allocatorPropagatingCopyPropagating(std::false_type, const T& source, const ALLOC& allocator)
99
{
100


771
    return allocatorPropagatingCopyDefault(std::uses_allocator<T, ALLOC>(), source, allocator);
101
}
102
103
// implementation of copy for vectors containing type that supports allocator
104
template <typename T, typename ALLOC, typename ALLOC2>
105
354
std::vector<T, ALLOC> allocatorPropagatingCopyVec(
106
        std::true_type, const std::vector<T, ALLOC>& source, const ALLOC2& allocator)
107
{
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
}
114
115
// implementation of copy for vectors containing type that supports allocator
116
template <typename T, typename ALLOC, typename ALLOC2>
117
64
std::vector<T, ALLOC> allocatorPropagatingCopyVec(
118
        std::true_type, NoInitT, const std::vector<T, ALLOC>& source, const ALLOC2& allocator)
119
{
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
}
126
127
// implementation of copy for vectors containing type that does not support allocator
128
template <typename T, typename ALLOC, typename ALLOC2>
129
2961
std::vector<T, ALLOC> allocatorPropagatingCopyVec(
130
        std::false_type, const std::vector<T, ALLOC>& source, const ALLOC2& allocator)
131
{
132
2961
    return std::vector<T, ALLOC>(source, allocator);
133
}
134
135
template <typename T, typename ALLOC>
136
1161
T allocatorPropagatingCopyImpl(const T& source, const ALLOC& allocator)
137
{
138
1538
    return allocatorPropagatingCopyPropagating(
139




1930
            std::is_constructible<T, PropagateAllocatorT, T, ALLOC>(), source, allocator);
140
}
141
142
template <typename T, typename ALLOC>
143
196
T allocatorPropagatingCopyImpl(NoInitT, const T& source, const ALLOC& allocator)
144
{
145
    static_assert(std::is_constructible<T, NoInitT, T>::value, "Can be used only for parameterized compounds!");
146
147
    return allocatorPropagatingCopyPropagating(
148

196
            std::is_constructible<T, PropagateAllocatorT, NoInitT, T, ALLOC>(), NoInit, source, allocator);
149
}
150
151
template <typename T, typename ALLOC, typename ALLOC2>
152
2
HeapOptionalHolder<T, ALLOC> allocatorPropagatingCopyImpl(
153
        const HeapOptionalHolder<T, ALLOC>& source, const ALLOC2& allocator)
154
{
155
2
    if (source.hasValue())
156
1
        return HeapOptionalHolder<T, ALLOC>(allocatorPropagatingCopy(*source, allocator), allocator);
157
    else
158
1
        return HeapOptionalHolder<T, ALLOC>(allocator);
159
}
160
161
template <typename T, typename ALLOC, typename ALLOC2>
162
2
HeapOptionalHolder<T, ALLOC> allocatorPropagatingCopyImpl(
163
        NoInitT, const HeapOptionalHolder<T, ALLOC>& source, const ALLOC2& allocator)
164
{
165
    static_assert(std::is_constructible<T, NoInitT, T>::value, "Can be used only for parameterized compounds!");
166
167
2
    if (source.hasValue())
168
    {
169
1
        return HeapOptionalHolder<T, ALLOC>(NoInit, allocatorPropagatingCopy(NoInit, *source, allocator),
170
1
                allocator);
171
    }
172
    else
173
1
        return HeapOptionalHolder<T, ALLOC>(allocator);
174
}
175
176
template <typename T, typename ALLOC>
177
2
InplaceOptionalHolder<T> allocatorPropagatingCopyImpl(
178
        const InplaceOptionalHolder<T>& source, const ALLOC& allocator)
179
{
180

2
    if (source.hasValue())
181


1
        return InplaceOptionalHolder<T>(allocatorPropagatingCopy(*source, allocator));
182
    else
183
1
        return InplaceOptionalHolder<T>();
184
}
185
186
template <typename T, typename ALLOC>
187
2
InplaceOptionalHolder<T> allocatorPropagatingCopyImpl(
188
        NoInitT, const InplaceOptionalHolder<T>& source, const ALLOC& allocator)
189
{
190
    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
    else
195
1
        return InplaceOptionalHolder<T>();
196
}
197
198
template <typename T, typename ALLOC, typename ALLOC2>
199
2
AnyHolder<ALLOC> allocatorPropagatingCopyImpl(
200
        const AnyHolder<ALLOC>& source, const ALLOC2& allocator)
201
{
202


2
    if (source.hasValue())
203
    {
204
1
        return AnyHolder<ALLOC>(allocatorPropagatingCopy(source.template get<T>(), allocator),
205



1
                allocator);
206
    }
207
    else
208
    {
209
1
        return AnyHolder<ALLOC>(allocator);
210
    }
211
}
212
213
template <typename T, typename ALLOC, typename ALLOC2>
214
2
AnyHolder<ALLOC> allocatorPropagatingCopyImpl(
215
        NoInitT, const AnyHolder<ALLOC>& source, const ALLOC2& allocator)
216
{
217
2
    if (source.hasValue())
218
    {
219
1
        return AnyHolder<ALLOC>(NoInit, allocatorPropagatingCopy(NoInit, source.template get<T>(), allocator),
220
1
                allocator);
221
    }
222
    else
223
    {
224
1
        return AnyHolder<ALLOC>(allocator);
225
    }
226
}
227
228
template <typename T, typename ALLOC, typename ALLOC2>
229
3379
std::vector<T, ALLOC> allocatorPropagatingCopyImpl(
230
        const std::vector<T, ALLOC>& source, const ALLOC2& allocator)
231
{
232









3379
    return allocatorPropagatingCopyVec(std::uses_allocator<T, ALLOC>(), source, allocator);
233
}
234
235
template <typename T, typename ALLOC, typename ALLOC2>
236
64
std::vector<T, ALLOC> allocatorPropagatingCopyImpl(
237
        NoInitT, const std::vector<T, ALLOC>& source, const ALLOC2& allocator)
238
{
239
    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
}
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
4544
T allocatorPropagatingCopy(const T& source, const ALLOC& allocator)
256
{
257
    static_assert(!std::is_same<AnyHolder<ALLOC>, T>::value, "Cannot be used for AnyHolder!");
258
259
4544
    return detail::allocatorPropagatingCopyImpl(source, allocator);
260
}
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
264
T allocatorPropagatingCopy(NoInitT, const T& source, const ALLOC& allocator)
272
{
273
    static_assert(!std::is_same<AnyHolder<ALLOC>, T>::value, "Cannot be used for AnyHolder!");
274
275
264
    return detail::allocatorPropagatingCopyImpl(NoInit, source, allocator);
276
}
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
2
AnyHolder<ALLOC> allocatorPropagatingCopy(
288
        const AnyHolder<ALLOC>& source, const ALLOC2& allocator)
289
{
290
2
    return detail::allocatorPropagatingCopyImpl<T>(source, allocator);
291
}
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
2
AnyHolder<ALLOC> allocatorPropagatingCopy(
303
        NoInitT, const AnyHolder<ALLOC>& source, const ALLOC2& allocator)
304
{
305
    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
}
309
310
} // namespace zserio
311
312
#endif // ZSERIO_ALLOCATOR_PROPAGATING_COPY_H_INC