Coverage Report

Created: 2026-09-01 06:50

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/stdplus/include/stdplus/raw.hpp
Line
Count
Source
1
#pragma once
2
#include <stdplus/concepts.hpp>
3
#include <stdplus/exception.hpp>
4
5
#include <algorithm>
6
#include <format>
7
#include <span>
8
#include <stdexcept>
9
#include <string_view>
10
#include <type_traits>
11
12
namespace stdplus
13
{
14
namespace raw
15
{
16
17
namespace detail
18
{
19
20
/** @brief Gets the datatype referenced in a container
21
 */
22
template <typename Container>
23
using dataType = std::remove_pointer_t<decltype(std::data(
24
    std::declval<std::add_lvalue_reference_t<Container>>()))>;
25
26
/** @brief Gets the sizetype referenced in a container
27
 */
28
template <typename Container>
29
using sizeType =
30
    decltype(std::size(std::declval<std::add_lvalue_reference_t<Container>>()));
31
32
/** @brief Determines if the container holds trivially copyable data
33
 */
34
template <typename Container>
35
inline constexpr bool containsTrivial =
36
    std::is_trivially_copyable_v<dataType<Container>>;
37
38
/** @brief Adds const to A if B is const
39
 */
40
template <typename A, typename B>
41
using copyConst =
42
    std::conditional_t<std::is_const_v<B>, std::add_const_t<A>, A>;
43
44
/** @brief Determines if a type is a container of data
45
 */
46
template <typename, typename = void>
47
inline constexpr bool hasData = false;
48
template <typename T>
49
inline constexpr bool hasData<T, std::void_t<dataType<T>, sizeType<T>>> = true;
50
51
template <typename T>
52
concept ContainsTrivial = hasData<T> && containsTrivial<T>;
53
template <typename T>
54
concept NotContainerTrivial = !hasData<T> && TriviallyCopyable<T>;
55
56
} // namespace detail
57
58
/** @brief Compares two containers to see if their raw bytes are equal
59
 *
60
 *  @param[in] a - The first container
61
 *  @param[in] b - The second container
62
 *  @return True if they are the same, false otherwise
63
 */
64
template <TriviallyCopyable A, TriviallyCopyable B>
65
constexpr bool equal(const A& a, const B& b) noexcept
66
{
67
    static_assert(sizeof(A) == sizeof(B));
68
    const auto a_byte = reinterpret_cast<const std::byte*>(&a);
69
    const auto b_byte = reinterpret_cast<const std::byte*>(&b);
70
    return std::equal(a_byte, a_byte + sizeof(A), b_byte);
71
}
72
73
/** @brief Copies data from a buffer into a copyable type
74
 *
75
 *  @param[in] data - The data buffer being copied from
76
 *  @return The copyable type with data populated
77
 */
78
#define STDPLUS_COPY_FROM(func, comp)                                          \
79
    template <TriviallyCopyable T, detail::ContainsTrivial Container>          \
80
    constexpr T func(const Container& c)                                       \
81
23.3M
    {                                                                          \
82
23.3M
        T ret;                                                                 \
83
23.3M
        const size_t bytes = std::size(c) * sizeof(*std::data(c));             \
84
23.3M
        if (bytes comp sizeof(ret))                                            \
85
23.3M
        {                                                                      \
86
1.34k
            throw exception::Incomplete(                                       \
87
1.34k
                std::format(#func ": {} < {}", bytes, sizeof(ret)));           \
88
1.34k
        }                                                                      \
89
23.3M
        const auto c_bytes = reinterpret_cast<const std::byte*>(std::data(c)); \
90
23.3M
        const auto ret_bytes = reinterpret_cast<std::byte*>(&ret);             \
91
23.3M
        std::copy(c_bytes, c_bytes + sizeof(ret), ret_bytes);                  \
92
23.3M
        return ret;                                                            \
93
23.3M
    }
_ZN7stdplus3raw8copyFromITkNS_17TriviallyCopyableE21payload_update_statusTkNS0_6detail15ContainsTrivialENSt3__14spanIKhLm18446744073709551615EEEEET_RKT0_
Line
Count
Source
81
603
    {                                                                          \
82
603
        T ret;                                                                 \
83
603
        const size_t bytes = std::size(c) * sizeof(*std::data(c));             \
84
603
        if (bytes comp sizeof(ret))                                            \
85
603
        {                                                                      \
86
603
            throw exception::Incomplete(                                       \
87
603
                std::format(#func ": {} < {}", bytes, sizeof(ret)));           \
88
603
        }                                                                      \
89
603
        const auto c_bytes = reinterpret_cast<const std::byte*>(std::data(c)); \
90
0
        const auto ret_bytes = reinterpret_cast<std::byte*>(&ret);             \
91
0
        std::copy(c_bytes, c_bytes + sizeof(ret), ret_bytes);                  \
92
0
        return ret;                                                            \
93
603
    }
_ZN7stdplus3raw8copyFromITkNS_17TriviallyCopyableEN6google4hoth8internal9RspHeaderETkNS0_6detail15ContainsTrivialENSt3__14spanIKhLm18446744073709551615EEEEET_RKT0_
Line
Count
Source
81
23.3M
    {                                                                          \
82
23.3M
        T ret;                                                                 \
83
23.3M
        const size_t bytes = std::size(c) * sizeof(*std::data(c));             \
84
23.3M
        if (bytes comp sizeof(ret))                                            \
85
23.3M
        {                                                                      \
86
0
            throw exception::Incomplete(                                       \
87
0
                std::format(#func ": {} < {}", bytes, sizeof(ret)));           \
88
0
        }                                                                      \
89
23.3M
        const auto c_bytes = reinterpret_cast<const std::byte*>(std::data(c)); \
90
23.3M
        const auto ret_bytes = reinterpret_cast<std::byte*>(&ret);             \
91
23.3M
        std::copy(c_bytes, c_bytes + sizeof(ret), ret_bytes);                  \
92
23.3M
        return ret;                                                            \
93
23.3M
    }
_ZN7stdplus3raw8copyFromITkNS_17TriviallyCopyableE31payload_update_confirm_responseTkNS0_6detail15ContainsTrivialENSt3__14spanIKhLm18446744073709551615EEEEET_RKT0_
Line
Count
Source
81
737
    {                                                                          \
82
737
        T ret;                                                                 \
83
737
        const size_t bytes = std::size(c) * sizeof(*std::data(c));             \
84
737
        if (bytes comp sizeof(ret))                                            \
85
737
        {                                                                      \
86
737
            throw exception::Incomplete(                                       \
87
737
                std::format(#func ": {} < {}", bytes, sizeof(ret)));           \
88
737
        }                                                                      \
89
737
        const auto c_bytes = reinterpret_cast<const std::byte*>(std::data(c)); \
90
0
        const auto ret_bytes = reinterpret_cast<std::byte*>(&ret);             \
91
0
        std::copy(c_bytes, c_bytes + sizeof(ret), ret_bytes);                  \
92
0
        return ret;                                                            \
93
737
    }
94
STDPLUS_COPY_FROM(copyFrom, <)
95
STDPLUS_COPY_FROM(copyFromStrict, !=)
96
#undef STDPLUS_COPY_FROM
97
98
/** @brief If you can guarantee the underlying data is properly aligned
99
 *  for raw struct access this specifier is used to override compile checks. */
100
struct Aligned
101
{};
102
struct UnAligned
103
{};
104
105
/** @brief References the data from a buffer if aligned
106
 *
107
 *  @param[in] data - The data buffer being referenced
108
 *  @return The reference to the data in the new type
109
 */
110
#define STDPLUS_REF_FROM(func, comp)                                           \
111
    template <TriviallyCopyable T, typename A = stdplus::raw::UnAligned,       \
112
              detail::ContainsTrivial Container,                               \
113
              typename Tp = detail::copyConst<T, detail::dataType<Container>>> \
114
    constexpr Tp& func(Container&& c)                                          \
115
515
    {                                                                          \
116
515
        static_assert(std::is_same_v<A, Aligned> ||                            \
117
515
                      sizeof(*std::data(c)) % alignof(Tp) == 0);               \
118
515
        const size_t bytes = std::size(c) * sizeof(*std::data(c));             \
119
515
        if (bytes comp sizeof(Tp))                                             \
120
515
        {                                                                      \
121
0
            throw exception::Incomplete(                                       \
122
0
                std::format(#func ": {} < {}", bytes, sizeof(Tp)));            \
123
0
        }                                                                      \
124
515
        return *reinterpret_cast<Tp*>(std::data(c));                           \
125
515
    }
126
STDPLUS_REF_FROM(refFrom, <)
127
STDPLUS_REF_FROM(refFromStrict, !=)
128
#undef STDPLUS_REF_FROM
129
130
/** @brief Extracts data from a buffer into a copyable type
131
 *         Updates the data buffer to show that data was removed
132
 *
133
 *  @param[in,out] data - The data buffer being extracted from
134
 *  @return The copyable type with data populated
135
 */
136
template <typename T, typename CharT>
137
constexpr T extract(std::basic_string_view<CharT>& data)
138
{
139
    T ret = copyFrom<T>(data);
140
    static_assert(sizeof(T) % sizeof(CharT) == 0);
141
    data.remove_prefix(sizeof(T) / sizeof(CharT));
142
    return ret;
143
}
144
template <typename T, TriviallyCopyable IntT>
145
constexpr T extract(std::span<IntT>& data)
146
23.3M
{
147
23.3M
    T ret = copyFrom<T>(data);
148
23.3M
    static_assert(sizeof(T) % sizeof(IntT) == 0);
149
23.3M
    data = data.subspan(sizeof(T) / sizeof(IntT));
150
23.3M
    return ret;
151
23.3M
}
152
153
/** @brief Extracts data from a buffer as a reference if aligned
154
 *         Updates the data buffer to show that data was removed
155
 *
156
 *  @param[in,out] data - The data buffer being extracted from
157
 *  @return A reference to the data
158
 */
159
template <typename T, typename A = stdplus::raw::UnAligned, typename CharT>
160
constexpr const T& extractRef(std::basic_string_view<CharT>& data)
161
{
162
    const T& ret = refFrom<T, A>(data);
163
    static_assert(sizeof(T) % sizeof(CharT) == 0);
164
    data.remove_prefix(sizeof(T) / sizeof(CharT));
165
    return ret;
166
}
167
template <typename T, typename A = stdplus::raw::UnAligned,
168
          TriviallyCopyable IntT, typename Tp = detail::copyConst<T, IntT>>
169
constexpr Tp& extractRef(std::span<IntT>& data)
170
515
{
171
515
    Tp& ret = refFrom<Tp, A>(data);
172
515
    static_assert(sizeof(Tp) % sizeof(IntT) == 0);
173
515
    data = data.subspan(sizeof(Tp) / sizeof(IntT));
174
515
    return ret; // NOLINT(clang-analyzer-cplusplus.InnerPointer)
175
515
}
176
177
/** @brief Returns the std::span referencing the data of the raw trivial type
178
 *         or of trivial types in a contiguous container.
179
 *
180
 *  @param[in] t - The trivial raw data
181
 *  @return A view over the input with the given output integral type
182
 */
183
template <typename CharT, detail::NotContainerTrivial T>
184
constexpr std::basic_string_view<CharT> asView(const T& t) noexcept
185
{
186
    static_assert(sizeof(T) % sizeof(CharT) == 0);
187
    return {reinterpret_cast<const CharT*>(&t), sizeof(T) / sizeof(CharT)};
188
}
189
190
template <typename CharT, detail::ContainsTrivial Container>
191
constexpr std::basic_string_view<CharT> asView(const Container& c) noexcept
192
{
193
    static_assert(sizeof(*std::data(c)) % sizeof(CharT) == 0);
194
    return {reinterpret_cast<const CharT*>(std::data(c)),
195
            std::size(c) * sizeof(*std::data(c)) / sizeof(CharT)};
196
}
197
198
template <TriviallyCopyable IntT, detail::NotContainerTrivial T,
199
          typename IntTp = detail::copyConst<IntT, T>>
200
constexpr std::span<IntTp> asSpan(T& t) noexcept
201
{
202
    static_assert(sizeof(T) % sizeof(IntTp) == 0);
203
    return {reinterpret_cast<IntTp*>(&t), sizeof(T) / sizeof(IntTp)};
204
}
205
template <TriviallyCopyable IntT, detail::ContainsTrivial Container,
206
          typename IntTp = detail::copyConst<IntT, detail::dataType<Container>>>
207
constexpr std::span<IntTp> asSpan(Container&& c) noexcept
208
{
209
    static_assert(sizeof(*std::data(c)) % sizeof(IntTp) == 0);
210
    return {reinterpret_cast<IntTp*>(std::data(c)),
211
            std::size(c) * sizeof(*std::data(c)) / sizeof(IntTp)};
212
}
213
214
} // namespace raw
215
} // namespace stdplus