blob: d17bd897719c55c6f01dc8c98e5407fc7a2845ce [file] [log] [blame]
William A. Kennington IIIe0990382019-10-18 02:10:25 -07001#pragma once
2#include <fmt/format.h>
3#include <stdexcept>
4#include <stdplus/types.hpp>
5#include <string_view>
6#include <type_traits>
7
8namespace stdplus
9{
10namespace raw
11{
12
13namespace detail
14{
15
William A. Kennington III0431e3c2020-07-19 02:08:26 -070016/** @brief Gets the datatype referenced in a container
17 */
18template <typename Container>
19using dataType = std::remove_pointer_t<decltype(
20 std::data(std::declval<std::add_lvalue_reference_t<Container>>()))>;
21
William A. Kennington IIIe0990382019-10-18 02:10:25 -070022/** @brief Determines if the container holds trivially copyable data
23 */
24template <typename Container>
25inline constexpr bool trivialContainer =
William A. Kennington III0431e3c2020-07-19 02:08:26 -070026 std::is_trivially_copyable_v<dataType<Container>>;
27
28/** @brief Adds const to A if B is const
29 */
30template <typename A, typename B>
31using copyConst =
32 std::conditional_t<std::is_const_v<B>, std::add_const_t<A>, A>;
William A. Kennington IIIe0990382019-10-18 02:10:25 -070033
William A. Kennington IIIba7d7542020-07-19 20:04:44 -070034/** @brief Determines if a type is a container of data
35 */
36template <typename, typename = void>
37inline constexpr bool hasData = false;
38template <typename T>
39inline constexpr bool hasData<T, std::void_t<dataType<T>>> = true;
40
William A. Kennington IIIe0990382019-10-18 02:10:25 -070041} // namespace detail
42
William A. Kennington III3b35fcf2020-06-13 18:42:39 -070043/** @brief Compares two containers to see if their raw bytes are equal
44 *
45 * @param[in] a - The first container
46 * @param[in] b - The second container
47 * @return True if they are the same, false otherwise
48 */
49template <typename A, typename B>
50bool equal(const A& a, const B& b)
51{
52 static_assert(std::is_trivially_copyable_v<A>);
53 static_assert(std::is_trivially_copyable_v<B>);
54 static_assert(sizeof(A) == sizeof(B));
55 return memcmp(&a, &b, sizeof(A)) == 0;
56}
57
William A. Kennington IIIe0990382019-10-18 02:10:25 -070058/** @brief Copies data from a buffer into a copyable type
59 *
60 * @param[in] data - The data buffer being copied from
61 * @return The copyable type with data populated
62 */
63template <typename T, typename Container>
64T copyFrom(const Container& c)
65{
66 static_assert(std::is_trivially_copyable_v<T>);
67 static_assert(detail::trivialContainer<Container>);
68 T ret;
69 const size_t bytes = std::size(c) * sizeof(*std::data(c));
70 if (bytes < sizeof(ret))
71 {
72 throw std::runtime_error(
73 fmt::format("CopyFrom: {} < {}", bytes, sizeof(ret)));
74 }
75 std::memcpy(&ret, std::data(c), sizeof(ret));
76 return ret;
77}
78
William A. Kennington III5c99ff42020-07-19 02:29:26 -070079/** @brief References the data from a buffer if aligned
80 *
81 * @param[in] data - The data buffer being referenced
82 * @return The reference to the data in the new type
83 */
84template <typename T, typename Container,
85 typename Tp = detail::copyConst<T, detail::dataType<Container>>>
William A. Kennington IIId91442d2020-07-19 14:36:13 -070086Tp& refFrom(Container&& c)
William A. Kennington III5c99ff42020-07-19 02:29:26 -070087{
88 static_assert(std::is_trivially_copyable_v<Tp>);
89 static_assert(detail::trivialContainer<Container>);
90 static_assert(sizeof(*std::data(c)) % alignof(Tp) == 0);
91 const size_t bytes = std::size(c) * sizeof(*std::data(c));
92 if (bytes < sizeof(Tp))
93 {
94 throw std::runtime_error(
95 fmt::format("RefFrom: {} < {}", bytes, sizeof(Tp)));
96 }
97 return *reinterpret_cast<Tp*>(std::data(c));
98}
99
William A. Kennington IIIe0990382019-10-18 02:10:25 -0700100/** @brief Extracts data from a buffer into a copyable type
101 * Updates the data buffer to show that data was removed
102 *
103 * @param[in,out] data - The data buffer being extracted from
104 * @return The copyable type with data populated
105 */
106template <typename T, typename CharT>
107T extract(std::basic_string_view<CharT>& data)
108{
109 T ret = copyFrom<T>(data);
110 static_assert(sizeof(T) % sizeof(CharT) == 0);
111 data.remove_prefix(sizeof(T) / sizeof(CharT));
112 return ret;
113}
114#ifdef STDPLUS_SPAN_TYPE
115template <typename T, typename IntT,
William A. Kennington III800e9cc2020-07-19 04:23:53 -0700116 typename = std::enable_if_t<std::is_trivially_copyable_v<IntT>>>
William A. Kennington III04bac392020-07-18 14:54:11 -0700117T extract(span<IntT>& data)
William A. Kennington IIIe0990382019-10-18 02:10:25 -0700118{
119 T ret = copyFrom<T>(data);
120 static_assert(sizeof(T) % sizeof(IntT) == 0);
121 data = data.subspan(sizeof(T) / sizeof(IntT));
122 return ret;
123}
124#endif
125
William A. Kennington III5c99ff42020-07-19 02:29:26 -0700126/** @brief Extracts data from a buffer as a reference if aligned
127 * Updates the data buffer to show that data was removed
128 *
129 * @param[in,out] data - The data buffer being extracted from
130 * @return A reference to the data
131 */
132template <typename T, typename CharT>
133const T& extractRef(std::basic_string_view<CharT>& data)
134{
135 const T& ret = refFrom<T>(data);
136 static_assert(sizeof(T) % sizeof(CharT) == 0);
137 data.remove_prefix(sizeof(T) / sizeof(CharT));
138 return ret;
139}
140#ifdef STDPLUS_SPAN_TYPE
141template <typename T, typename IntT,
142 typename = std::enable_if_t<std::is_trivially_copyable_v<IntT>>,
143 typename Tp = detail::copyConst<T, IntT>>
144Tp& extractRef(span<IntT>& data)
145{
146 Tp& ret = refFrom<Tp>(data);
147 static_assert(sizeof(Tp) % sizeof(IntT) == 0);
148 data = data.subspan(sizeof(Tp) / sizeof(IntT));
149 return ret;
150}
151#endif
152
William A. Kennington IIIe0990382019-10-18 02:10:25 -0700153/** @brief Returns the span referencing the data of the raw trivial type
154 * or of trivial types in a contiguous container.
155 *
156 * @param[in] t - The trivial raw data
157 * @return A view over the input with the given output integral type
158 */
William A. Kennington IIIba7d7542020-07-19 20:04:44 -0700159template <typename CharT, typename T>
160std::enable_if_t<!detail::hasData<T>, std::basic_string_view<CharT>>
161 asView(const T& t) noexcept
William A. Kennington IIIe0990382019-10-18 02:10:25 -0700162{
William A. Kennington IIIba7d7542020-07-19 20:04:44 -0700163 static_assert(std::is_trivially_copyable_v<T>);
William A. Kennington IIIe0990382019-10-18 02:10:25 -0700164 static_assert(sizeof(T) % sizeof(CharT) == 0);
165 return {reinterpret_cast<const CharT*>(&t), sizeof(T) / sizeof(CharT)};
166}
William A. Kennington IIIba7d7542020-07-19 20:04:44 -0700167
168template <typename CharT, typename Container>
169std::enable_if_t<detail::hasData<Container>, std::basic_string_view<CharT>>
170 asView(const Container& c) noexcept
William A. Kennington IIIe0990382019-10-18 02:10:25 -0700171{
172 static_assert(detail::trivialContainer<Container>);
173 static_assert(sizeof(*std::data(c)) % sizeof(CharT) == 0);
174 return {reinterpret_cast<const CharT*>(std::data(c)),
175 std::size(c) * sizeof(*std::data(c)) / sizeof(CharT)};
176}
William A. Kennington IIIba7d7542020-07-19 20:04:44 -0700177
William A. Kennington IIIe0990382019-10-18 02:10:25 -0700178#ifdef STDPLUS_SPAN_TYPE
179template <typename IntT, typename T,
William A. Kennington III800e9cc2020-07-19 04:23:53 -0700180 typename = std::enable_if_t<std::is_trivially_copyable_v<IntT>>,
William A. Kennington IIIba7d7542020-07-19 20:04:44 -0700181 typename = std::enable_if_t<!detail::hasData<T>>,
William A. Kennington III0431e3c2020-07-19 02:08:26 -0700182 typename IntTp = detail::copyConst<IntT, T>>
183span<IntTp> asSpan(T& t) noexcept
William A. Kennington IIIe0990382019-10-18 02:10:25 -0700184{
William A. Kennington IIIba7d7542020-07-19 20:04:44 -0700185 static_assert(std::is_trivially_copyable_v<T>);
William A. Kennington III0431e3c2020-07-19 02:08:26 -0700186 static_assert(sizeof(T) % sizeof(IntTp) == 0);
187 return {reinterpret_cast<IntTp*>(&t), sizeof(T) / sizeof(IntTp)};
William A. Kennington IIIe0990382019-10-18 02:10:25 -0700188}
189template <typename IntT, typename Container,
William A. Kennington III800e9cc2020-07-19 04:23:53 -0700190 typename = std::enable_if_t<std::is_trivially_copyable_v<IntT>>,
William A. Kennington IIIba7d7542020-07-19 20:04:44 -0700191 typename = std::enable_if_t<detail::hasData<Container>>,
William A. Kennington III0431e3c2020-07-19 02:08:26 -0700192 typename IntTp = detail::copyConst<IntT, detail::dataType<Container>>>
William A. Kennington IIId91442d2020-07-19 14:36:13 -0700193span<IntTp> asSpan(Container&& c) noexcept
William A. Kennington IIIe0990382019-10-18 02:10:25 -0700194{
195 static_assert(detail::trivialContainer<Container>);
William A. Kennington III0431e3c2020-07-19 02:08:26 -0700196 static_assert(sizeof(*std::data(c)) % sizeof(IntTp) == 0);
197 return {reinterpret_cast<IntTp*>(std::data(c)),
198 std::size(c) * sizeof(*std::data(c)) / sizeof(IntTp)};
William A. Kennington IIIe0990382019-10-18 02:10:25 -0700199}
200#endif
201
202} // namespace raw
203} // namespace stdplus