GCC Code Coverage Report


Directory: gridformat/
File: gridformat/common/serialization.hpp
Date: 2024-11-10 16:24:00
Exec Total Coverage
Lines: 49 51 96.1%
Functions: 40 47 85.1%
Branches: 8 16 50.0%

Line Branch Exec Source
1 // SPDX-FileCopyrightText: 2022-2023 Dennis Gläser <dennis.glaeser@iws.uni-stuttgart.de>
2 // SPDX-License-Identifier: MIT
3 /*!
4 * \file
5 * \ingroup Common
6 * \copydoc GridFormat::Serialization
7 */
8 #ifndef GRIDFORMAT_COMMON_SERIALIZATION_HPP_
9 #define GRIDFORMAT_COMMON_SERIALIZATION_HPP_
10
11 #include <vector>
12 #include <cstddef>
13 #include <algorithm>
14 #include <iterator>
15 #include <span>
16 #include <bit>
17
18 #include <gridformat/common/exceptions.hpp>
19 #include <gridformat/common/precision.hpp>
20 #include <gridformat/common/concepts.hpp>
21
22 namespace GridFormat {
23
24 /*!
25 * \ingroup Common
26 * \brief Represents the serialization (vector of bytes) of an object
27 */
28 class Serialization {
29 public:
30 using Byte = std::byte;
31
32 1 Serialization() = default;
33
34 162281 explicit Serialization(std::size_t size)
35
1/2
✓ Branch 1 taken 162281 times.
✗ Branch 2 not taken.
324562 : _data{size}
36 162281 {}
37
38 template<Concepts::Scalar T>
39 57 static Serialization from_scalar(const T& value) {
40 57 Serialization result{sizeof(value)};
41 57 std::byte* out = result.as_span().data();
42 57 const std::byte* value_bytes = reinterpret_cast<const std::byte*>(&value);
43
1/2
✓ Branch 1 taken 52 times.
✗ Branch 2 not taken.
57 std::copy_n(value_bytes, sizeof(value), out);
44 57 return result;
45 }
46
47 117201 std::span<std::byte> as_span() { return {_data}; }
48 std::span<const std::byte> as_span() const { return {_data}; }
49
50 261125 std::size_t size() const {
51 261125 return _data.size();
52 }
53
54 201498 void resize(std::size_t size, Byte value = Byte{0}) {
55 201498 _data.resize(size, value);
56 201498 }
57
58 178 void push_back(std::vector<std::byte>&& bytes) {
59 178 const auto size_before = size();
60 178 _data.reserve(size_before + bytes.size());
61 178 std::ranges::move(std::move(bytes), std::back_inserter(_data));
62 178 }
63
64 2 void cut_front(std::size_t number_of_bytes) {
65
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
2 if (number_of_bytes > size())
66
1/2
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 throw SizeError("Cannot cut more bytes than stored");
67 1 const auto new_size = _data.size() - number_of_bytes;
68 1 std::span trail{_data.data() + number_of_bytes, new_size};
69
1/2
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 std::ranges::move(trail, _data.begin());
70
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 _data.resize(new_size);
71 1 }
72
73 template<Concepts::Scalar T>
74 719445 std::span<T> as_span_of(const Precision<T>& = {}) {
75 719445 _check_valid_cast<T>();
76 719445 return std::span{reinterpret_cast<T*>(_data.data()), _data.size()/sizeof(T)};
77 }
78
79 template<Concepts::Scalar T>
80 104654 std::span<std::add_const_t<T>> as_span_of(const Precision<T>& = {}) const {
81 104654 _check_valid_cast<T>();
82 104654 return std::span{reinterpret_cast<std::add_const_t<T>*>(_data.data()), _data.size()/sizeof(T)};
83 }
84
85 operator std::span<const std::byte>() const { return {_data}; }
86 operator std::span<std::byte>() { return {_data}; }
87
88 177 std::vector<std::byte>&& data() && { return std::move(_data); }
89
90 private:
91 template<typename T>
92 824102 void _check_valid_cast() const {
93
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 412061 times.
824102 if (_data.size()%sizeof(T) != 0)
94 throw TypeError("Cannot cast to span of given type, size mismatch");
95 824102 }
96
97 std::vector<std::byte> _data;
98 };
99
100
101 //! Options for converting between byte orders
102 struct ByteOrderConversionOptions {
103 std::endian from;
104 std::endian to = std::endian::native;
105 };
106
107
108 //! Convert the byte order of all values in a span
109 template<Concepts::Scalar T>
110 25062 void change_byte_order(std::span<T> values, const ByteOrderConversionOptions& opts) {
111 25062 if (opts.from == opts.to)
112 24451 return;
113
114 611 std::size_t offset = 0;
115 std::array<std::byte, sizeof(T)> buffer;
116 611 auto bytes = std::as_writable_bytes(values);
117 12870 while (offset < bytes.size()) {
118 12259 std::ranges::copy_n(bytes.data() + offset, sizeof(T), buffer.begin());
119 12259 std::ranges::reverse(buffer);
120 12259 std::ranges::copy(buffer, bytes.data() + offset);
121 12259 offset += sizeof(T);
122 }
123 }
124
125
126 } // namespace GridFormat
127
128 #endif // GRIDFORMAT_COMMON_SERIALIZATION_HPP_
129