GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/zserio/SerializeUtil.h Lines: 58 58 100.0 %
Date: 2023-12-13 14:51:09 Branches: 101 194 52.1 %

Line Branch Exec Source
1
/**
2
 * \file
3
 * It provides help methods for serialization and deserialization of generated objects.
4
 *
5
 * These utilities are not used by generated code and they are provided only for user convenience.
6
 *
7
 * \note Please note that file operations allocate memory as needed and are not designed to use allocators.
8
 */
9
10
#ifndef ZSERIO_SERIALIZE_UTIL_H_INC
11
#define ZSERIO_SERIALIZE_UTIL_H_INC
12
13
#include "zserio/BitStreamReader.h"
14
#include "zserio/BitStreamWriter.h"
15
#include "zserio/Vector.h"
16
#include "zserio/FileUtil.h"
17
#include "zserio/Traits.h"
18
19
namespace zserio
20
{
21
22
namespace detail
23
{
24
25
template <typename T>
26
9
void initializeChildrenImpl(std::true_type, T& object)
27
{
28
9
    object.initializeChildren();
29
9
}
30
31
template <typename T>
32
void initializeChildrenImpl(std::false_type, T&)
33
{}
34
35
template <typename T>
36
9
void initializeChildren(T& object)
37
{
38

9
    initializeChildrenImpl(has_initialize_children<T>(), object);
39
9
}
40
41
template <typename T, typename ...ARGS>
42
6
void initializeImpl(std::true_type, T& object, ARGS&&... arguments)
43
{
44
6
    object.initialize(std::forward<ARGS>(arguments)...);
45
6
}
46
47
template <typename T>
48
9
void initializeImpl(std::false_type, T& object)
49
{
50
9
    initializeChildren(object);
51
9
}
52
53
template <typename T, typename ...ARGS>
54
15
void initialize(T& object, ARGS&&... arguments)
55
{
56


15
    initializeImpl(has_initialize<T>(), object, std::forward<ARGS>(arguments)...);
57
15
}
58
59
template <typename T, typename = void>
60
struct allocator_chooser
61
{
62
    using type = std::allocator<uint8_t>;
63
};
64
65
template <typename T>
66
struct allocator_chooser<T, detail::void_t<typename T::allocator_type>>
67
{
68
    using type = typename T::allocator_type;
69
};
70
71
// This implementation needs to be in detail because old MSVC compiler 2015 has problems with calling overload.
72
template <typename T, typename ALLOC, typename ...ARGS>
73
15
BasicBitBuffer<ALLOC> serialize(T& object, const ALLOC& allocator, ARGS&&... arguments)
74
{
75


15
    detail::initialize(object, std::forward<ARGS>(arguments)...);
76




15
    BasicBitBuffer<ALLOC> bitBuffer(object.initializeOffsets(), allocator);
77


15
    BitStreamWriter writer(bitBuffer);
78


15
    object.write(writer);
79
15
    return bitBuffer;
80
}
81
82
} // namespace detail
83
84
/**
85
 * Serializes given generated object to bit buffer using given allocator.
86
 *
87
 * Before serialization, the method properly calls on the given zserio object methods `initialize()`
88
 * (if exits), `initializeChildren()` (if exists) and `initializeOffsets()`.
89
 *
90
 * Example:
91
 * \code{.cpp}
92
 *     #include <zserio/SerializeUtil.h>
93
 *     #include <zserio/pmr/PolymorphicAllocator.h>
94
 *
95
 *     const zserio::pmr::PolymorphicAllocator<> allocator;
96
 *     SomeZserioObject object(allocator);
97
 *     const zserio::BasicBitBuffer<zserio::pmr::PolymorphicAllocator<>> bitBuffer =
98
 *             zserio::serialize(object, allocator);
99
 * \endcode
100
 *
101
 * \param object Generated object to serialize.
102
 * \param allocator Allocator to use to allocate bit buffer.
103
 * \param arguments Object's actual parameters for initialize() method (optional).
104
 *
105
 * \return Bit buffer containing the serialized object.
106
 *
107
 * \throw CppRuntimeException When serialization fails.
108
 */
109
template <typename T, typename ALLOC, typename ...ARGS,
110
        typename std::enable_if<!std::is_enum<T>::value && is_allocator<ALLOC>::value, int>::type = 0>
111
4
BasicBitBuffer<ALLOC> serialize(T& object, const ALLOC& allocator, ARGS&&... arguments)
112
{
113
4
    return detail::serialize(object, allocator, std::forward<ARGS>(arguments)...);
114
}
115
116
/**
117
 * Serializes given generated object to bit buffer using default allocator 'std::allocator<uint8_t>'.
118
 *
119
 * Before serialization, the method properly calls on the given zserio object methods `initialize()`
120
 * (if exits), `initializeChildren()` (if exists) and `initializeOffsets()`.
121
 *
122
 * Example:
123
 * \code{.cpp}
124
 *     #include <zserio/SerializeUtil.h>
125
 *
126
 *     SomeZserioObject object;
127
 *     const zserio::BitBuffer bitBuffer = zserio::serialize(object);
128
 * \endcode
129
 *
130
 * \param object Generated object to serialize.
131
 * \param arguments Object's actual parameters for initialize() method (optional).
132
 *
133
 * \return Bit buffer containing the serialized object.
134
 *
135
 * \throw CppRuntimeException When serialization fails.
136
 */
137
template <typename T, typename ALLOC = typename detail::allocator_chooser<T>::type, typename ...ARGS,
138
        typename std::enable_if<!std::is_enum<T>::value &&
139
                !is_first_allocator<typename std::decay<ARGS>::type...>::value, int>::type = 0>
140
5
BasicBitBuffer<ALLOC> serialize(T& object, ARGS&&... arguments)
141
{
142

5
    return detail::serialize(object, ALLOC(), std::forward<ARGS>(arguments)...);
143
}
144
145
/**
146
 * Serializes given generated enum to bit buffer.
147
 *
148
 * Example:
149
 * \code{.cpp}
150
 *     #include <zserio/SerializeUtil.h>
151
 *
152
 *     const SomeZserioEnum enumValue = SomeZserioEnum::SomeEnumValue;
153
 *     const zserio::BitBuffer bitBuffer = zserio::serialize(enumValue);
154
 * \endcode
155
 *
156
 * \param enumValue Generated enum to serialize.
157
 * \param allocator Allocator to use to allocate bit buffer.
158
 *
159
 * \return Bit buffer containing the serialized enum.
160
 *
161
 * \throw CppRuntimeException When serialization fails.
162
 */
163
template <typename T, typename ALLOC = std::allocator<uint8_t>,
164
        typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
165
6
BasicBitBuffer<ALLOC> serialize(T enumValue, const ALLOC& allocator = ALLOC())
166
{
167


6
    BasicBitBuffer<ALLOC> bitBuffer(zserio::bitSizeOf(enumValue), allocator);
168

6
    BitStreamWriter writer(bitBuffer);
169

6
    zserio::write(writer, enumValue);
170
6
    return bitBuffer;
171
}
172
173
/**
174
 * Deserializes given bit buffer to instance of generated object.
175
 *
176
 * Example:
177
 * \code{.cpp}
178
 *     #include <zserio/SerializeUtil.h>
179
 *
180
 *     SomeZserioObject object;
181
 *     const zserio::BitBuffer bitBuffer = zserio::serialize(object);
182
 *     SomeZserioObject readObject = zserio::deserialize<SomeZserioObject>(bitBuffer);
183
 * \endcode
184
 *
185
 * \param bitBuffer Bit buffer to use.
186
 * \param arguments Object's actual parameters together with allocator for object's read constructor (optional).
187
 *
188
 * \return Generated object created from the given bit buffer.
189
 *
190
 * \throw CppRuntimeException When deserialization fails.
191
 */
192
template <typename T, typename ALLOC, typename ...ARGS>
193
12
typename std::enable_if<!std::is_enum<T>::value, T>::type deserialize(
194
        const BasicBitBuffer<ALLOC>& bitBuffer, ARGS&&... arguments)
195
{
196



12
    BitStreamReader reader(bitBuffer);
197



12
    return T(reader, std::forward<ARGS>(arguments)...);
198
}
199
200
/**
201
 * Deserializes given bit buffer to instance of generated enum.
202
 *
203
 * Example:
204
 * \code{.cpp}
205
 *     #include <zserio/SerializeUtil.h>
206
 *
207
 *     const SomeZserioEnum enumValue = SomeZserioEnum::SomeEnumValue;
208
 *     const zserio::BitBuffer bitBuffer = zserio::serialize(enumValue);
209
 *     const SomeZserioEnum readEnumValue = zserio::deserialize<DummyEnum>(bitBuffer);
210
 * \endcode
211
 *
212
 * \param bitBuffer Bit buffer to use.
213
 *
214
 * \return Generated enum created from the given bit buffer.
215
 *
216
 * \throw CppRuntimeException When deserialization fails.
217
 */
218
template <typename T, typename ALLOC>
219
3
typename std::enable_if<std::is_enum<T>::value, T>::type deserialize(const BasicBitBuffer<ALLOC>& bitBuffer)
220
{
221

3
    BitStreamReader reader(bitBuffer);
222

3
    return zserio::read<T>(reader);
223
}
224
225
/**
226
 * Serializes given generated object to vector of bytes using given allocator.
227
 *
228
 * Before serialization, the method properly calls on the given zserio object methods `initialize()`
229
 * (if exits), `initializeChildren()` (if exists) and `initializeOffsets()`.
230
 *
231
 * Example:
232
 * \code{.cpp}
233
 *     #include <zserio/SerializeUtil.h>
234
 *     #include <zserio/pmr/PolymorphicAllocator.h>
235
 *
236
 *     const zserio::pmr::PolymorphicAllocator<> allocator;
237
 *     SomeZserioObject object(allocator);
238
 *     const zserio::vector<uint8_t, zserio::pmr::PolymorphicAllocator<>> buffer =
239
 *             zserio::serializeToBytes(object, allocator);
240
 * \endcode
241
 *
242
 * \param object Generated object to serialize.
243
 * \param allocator Allocator to use to allocate vector.
244
 * \param arguments Object's actual parameters for initialize() method (optional).
245
 *
246
 * \return Vector of bytes containing the serialized object.
247
 *
248
 * \throw CppRuntimeException When serialization fails.
249
 */
250
template <typename T, typename ALLOC, typename ...ARGS,
251
        typename std::enable_if<!std::is_enum<T>::value && is_allocator<ALLOC>::value, int>::type = 0>
252
4
vector<uint8_t, ALLOC> serializeToBytes(T& object, const ALLOC& allocator, ARGS&&... arguments)
253
{
254
    const BasicBitBuffer<ALLOC> bitBuffer = detail::serialize(object, allocator,
255


8
            std::forward<ARGS>(arguments)...);
256
257


8
    return bitBuffer.getBytes();
258
}
259
260
/**
261
 * Serializes given generated object to vector of bytes using default allocator 'std::allocator<uint8_t>'.
262
 *
263
 * Before serialization, the method properly calls on the given zserio object methods `initialize()`
264
 * (if exits), `initializeChildren()` (if exists) and `initializeOffsets()`.
265
 *
266
 * However, it's still possible that not all bits of the last byte are used. In this case, only most
267
 * significant bits of the corresponding size are used.
268
 *
269
 * Example:
270
 * \code{.cpp}
271
 *     #include <zserio/SerializeUtil.h>
272
 *
273
 *     SomeZserioObject object;
274
 *     const zserio::vector<uint8_t> buffer = zserio::serializeToBytes(object);
275
 * \endcode
276
 *
277
 * \param object Generated object to serialize.
278
 * \param arguments Object's actual parameters for initialize() method (optional).
279
 *
280
 * \return Vector of bytes containing the serialized object.
281
 *
282
 * \throw CppRuntimeException When serialization fails.
283
 */
284
template <typename T, typename ALLOC = typename detail::allocator_chooser<T>::type, typename ...ARGS,
285
        typename std::enable_if<!std::is_enum<T>::value &&
286
                !is_first_allocator<typename std::decay<ARGS>::type...>::value, int>::type = 0>
287
2
vector<uint8_t, ALLOC> serializeToBytes(T& object, ARGS&&... arguments)
288
{
289
    const BasicBitBuffer<ALLOC> bitBuffer = detail::serialize(object, ALLOC(),
290

4
            std::forward<ARGS>(arguments)...);
291
292

4
    return bitBuffer.getBytes();
293
}
294
295
/**
296
 * Serializes given generated enum to vector of bytes.
297
 *
298
 * Example:
299
 * \code{.cpp}
300
 *     #include <zserio/SerializeUtil.h>
301
 *
302
 *     const SomeZserioEnum enumValue = SomeZserioEnum::SomeEnumValue;
303
 *     const zserio::vector<uint8_t> buffer = zserio::serializeToBytes(enumValue);
304
 * \endcode
305
 *
306
 * \param enumValue Generated enum to serialize.
307
 * \param allocator Allocator to use to allocate vector.
308
 *
309
 * \return Vector of bytes containing the serialized enum.
310
 *
311
 * \throw CppRuntimeException When serialization fails.
312
 */
313
template <typename T, typename ALLOC = std::allocator<uint8_t>,
314
        typename std::enable_if<std::is_enum<T>::value, int>::type = 0>
315
3
vector<uint8_t, ALLOC> serializeToBytes(T enumValue, const ALLOC& allocator = ALLOC())
316
{
317

6
    const BasicBitBuffer<ALLOC> bitBuffer = serialize(enumValue, allocator);
318
319

6
    return bitBuffer.getBytes();
320
}
321
322
/**
323
 * Deserializes given vector of bytes to instance of generated object.
324
 *
325
 * This method can potentially use all bits of the last byte even if not all of them were written during
326
 * serialization (because there is no way how to specify exact number of bits). Thus, it could allow reading
327
 * behind stream (possibly in case of damaged data).
328
 *
329
 * Example:
330
 * \code{.cpp}
331
 *     #include <zserio/SerializeUtil.h>
332
 *
333
 *     SomeZserioObject object;
334
 *     const zserio::vector<uint8_t> buffer = zserio::serializeToBytes(object);
335
 *     SomeZserioObject readObject = zserio::deserializeFromBytes<SomeZserioObject>(buffer);
336
 * \endcode
337
 *
338
 * \param bitBuffer Vector of bytes to use.
339
 * \param arguments Object's actual parameters together with allocator for object's read constructor (optional).
340
 *
341
 * \return Generated object created from the given vector of bytes.
342
 *
343
 * \throw CppRuntimeException When deserialization fails.
344
 */
345
template <typename T, typename ...ARGS>
346
9
typename std::enable_if<!std::is_enum<T>::value, T>::type deserializeFromBytes(
347
        Span<const uint8_t> buffer, ARGS&&... arguments)
348
{
349



9
    BitStreamReader reader(buffer);
350



9
    return T(reader, std::forward<ARGS>(arguments)...);
351
}
352
353
/**
354
 * Deserializes given vector of bytes to instance of generated enum.
355
 *
356
 * Example:
357
 * \code{.cpp}
358
 *     #include <zserio/SerializeUtil.h>
359
 *
360
 *     const SomeZserioEnum enumValue = SomeZserioEnum::SomeEnumValue;
361
 *     const zserio::vector<uint8_t> buffer = zserio::serializeToBytes(enumValue);
362
 *     const SomeZserioEnum readEnumValue = zserio::deserializeFromBytes<DummyEnum>(buffer);
363
 * \endcode
364
 *
365
 * \param bitBuffer Vector of bytes to use.
366
 *
367
 * \return Generated enum created from the given vector of bytes.
368
 *
369
 * \throw CppRuntimeException When deserialization fails.
370
 */
371
template <typename T>
372
3
typename std::enable_if<std::is_enum<T>::value, T>::type deserializeFromBytes(Span<const uint8_t> buffer)
373
{
374

3
    BitStreamReader reader(buffer);
375

3
    return zserio::read<T>(reader);
376
}
377
378
/**
379
 * Serializes given generated object to file.
380
 *
381
 * Example:
382
 * \code{.cpp}
383
 *     #include <zserio/SerializeUtil.h>
384
 *
385
 *     SomeZserioObject object;
386
 *     zserio::serializeToFile(object, "FileName.bin");
387
 * \endcode
388
 *
389
 * \param object Generated object to serialize.
390
 * \param fileName File name to write.
391
 *
392
 * \throw CppRuntimeException When serialization fails.
393
 */
394
template <typename T, typename ...ARGS>
395
3
void serializeToFile(T& object, const std::string& fileName, ARGS&&... arguments)
396
{
397

6
    const auto bitBuffer = serialize(object, std::forward<ARGS>(arguments)...);
398

3
    writeBufferToFile(bitBuffer, fileName);
399
3
}
400
401
/**
402
 * Deserializes given file contents to instance of generated object.
403
 *
404
 * Example:
405
 * \code{.cpp}
406
 *     #include <zserio/SerializeUtil.h>
407
 *
408
 *     const std::string fileName = "FileName.bin";
409
 *     SomeZserioObject object;
410
 *     zserio::serializeToFile(object, fileName);
411
 *     SomeZserioObject readObject = zserio::deserializeFromFile<SomeZserioObject>(fileName);
412
 * \endcode
413
 *
414
 * \note Please note that BitBuffer is always allocated using 'std::allocator<uint8_t>'.
415
 *
416
 * \param fileName File to use.
417
 * \param arguments Object's arguments (optional).
418
 *
419
 * \return Generated object created from the given file contents.
420
 *
421
 * \throw CppRuntimeException When deserialization fails.
422
 */
423
template <typename T, typename ...ARGS>
424
3
T deserializeFromFile(const std::string& fileName, ARGS&&... arguments)
425
{
426

6
    const BitBuffer bitBuffer = readBufferFromFile(fileName);
427

6
    return deserialize<T>(bitBuffer, std::forward<ARGS>(arguments)...);
428
}
429
430
} // namespace zserio
431
432
#endif // ZSERIO_SERIALIZE_UTIL_H_INC