Coverage Report

Created: 2024-04-30 09:35

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
        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>(
170
1
                NoInit, allocatorPropagatingCopy(NoInit, *source, allocator), 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(const AnyHolder<ALLOC>& source, const ALLOC2& allocator)
200
2
{
201
2
    if (source.hasValue())
202
1
    {
203
1
        return AnyHolder<ALLOC>(allocatorPropagatingCopy(source.template get<T>(), allocator), allocator);
204
1
    }
205
1
    else
206
1
    {
207
1
        return AnyHolder<ALLOC>(allocator);
208
1
    }
209
2
}
210
211
template <typename T, typename ALLOC, typename ALLOC2>
212
AnyHolder<ALLOC> allocatorPropagatingCopyImpl(NoInitT, const AnyHolder<ALLOC>& source, const ALLOC2& allocator)
213
2
{
214
2
    if (source.hasValue())
215
1
    {
216
1
        return AnyHolder<ALLOC>(
217
1
                NoInit, allocatorPropagatingCopy(NoInit, 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
std::vector<T, ALLOC> allocatorPropagatingCopyImpl(const std::vector<T, ALLOC>& source, const ALLOC2& allocator)
227
3.37k
{
228
3.37k
    return allocatorPropagatingCopyVec(std::uses_allocator<T, ALLOC>(), source, allocator);
229
3.37k
}
230
231
template <typename T, typename ALLOC, typename ALLOC2>
232
std::vector<T, ALLOC> allocatorPropagatingCopyImpl(
233
        NoInitT, const std::vector<T, ALLOC>& source, const ALLOC2& allocator)
234
64
{
235
64
    static_assert(std::is_constructible<T, NoInitT, T>::value, "Can be used only for parameterized compounds!");
236
237
64
    return allocatorPropagatingCopyVec(std::uses_allocator<T, ALLOC>(), NoInit, source, allocator);
238
64
}
239
240
} // namespace detail
241
242
/**
243
 * Copy the input object, propagating the allocator where needed.
244
 *
245
 * \param source Object to copy.
246
 * \param allocator Allocator to be propagated to the target object type constructor.
247
 *
248
 * \return Object copy.
249
 */
250
template <typename T, typename ALLOC>
251
T allocatorPropagatingCopy(const T& source, const ALLOC& allocator)
252
4.54k
{
253
4.54k
    static_assert(!std::is_same<AnyHolder<ALLOC>, T>::value, "Cannot be used for AnyHolder!");
254
255
4.54k
    return detail::allocatorPropagatingCopyImpl(source, allocator);
256
4.54k
}
257
258
/**
259
 * Copy the input object, propagating the allocator where needed and prevents initialization.
260
 *
261
 * \param source Object to copy.
262
 * \param allocator Allocator to be propagated to the target object type constructor.
263
 *
264
 * \return Object copy.
265
 */
266
template <typename T, typename ALLOC>
267
T allocatorPropagatingCopy(NoInitT, const T& source, const ALLOC& allocator)
268
264
{
269
264
    static_assert(!std::is_same<AnyHolder<ALLOC>, T>::value, "Cannot be used for AnyHolder!");
270
271
264
    return detail::allocatorPropagatingCopyImpl(NoInit, source, allocator);
272
264
}
273
274
/**
275
 * Copy the input any holder, propagating the allocator where needed.
276
 *
277
 * \param source Any holder to copy.
278
 * \param allocator Allocator to be propagated to the target object type constructor.
279
 *
280
 * \return Copy of any holder.
281
 */
282
template <typename T, typename ALLOC, typename ALLOC2>
283
AnyHolder<ALLOC> allocatorPropagatingCopy(const AnyHolder<ALLOC>& source, const ALLOC2& allocator)
284
2
{
285
2
    return detail::allocatorPropagatingCopyImpl<T>(source, allocator);
286
2
}
287
288
/**
289
 * Copy the input any holder, propagating the allocator where needed and prevents initialization.
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(NoInitT, const AnyHolder<ALLOC>& source, const ALLOC2& allocator)
298
2
{
299
2
    static_assert(std::is_constructible<T, NoInitT, T>::value, "Can be used only for parameterized compounds!");
300
301
2
    return detail::allocatorPropagatingCopyImpl<T>(NoInit, source, allocator);
302
2
}
303
304
} // namespace zserio
305
306
#endif // ZSERIO_ALLOCATOR_PROPAGATING_COPY_H_INC