blob: 1f3893f099ab03de4f27f13c05a34c610f9b36bb [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
16/** @brief Determines if the container holds trivially copyable data
17 */
18template <typename Container>
19inline constexpr bool trivialContainer =
20 std::is_trivially_copyable_v<std::remove_pointer_t<decltype(
21 std::data(std::declval<std::add_lvalue_reference_t<Container>>()))>>;
22
23} // namespace detail
24
25/** @brief Copies data from a buffer into a copyable type
26 *
27 * @param[in] data - The data buffer being copied from
28 * @return The copyable type with data populated
29 */
30template <typename T, typename Container>
31T copyFrom(const Container& c)
32{
33 static_assert(std::is_trivially_copyable_v<T>);
34 static_assert(detail::trivialContainer<Container>);
35 T ret;
36 const size_t bytes = std::size(c) * sizeof(*std::data(c));
37 if (bytes < sizeof(ret))
38 {
39 throw std::runtime_error(
40 fmt::format("CopyFrom: {} < {}", bytes, sizeof(ret)));
41 }
42 std::memcpy(&ret, std::data(c), sizeof(ret));
43 return ret;
44}
45
46/** @brief Extracts data from a buffer into a copyable type
47 * Updates the data buffer to show that data was removed
48 *
49 * @param[in,out] data - The data buffer being extracted from
50 * @return The copyable type with data populated
51 */
52template <typename T, typename CharT>
53T extract(std::basic_string_view<CharT>& data)
54{
55 T ret = copyFrom<T>(data);
56 static_assert(sizeof(T) % sizeof(CharT) == 0);
57 data.remove_prefix(sizeof(T) / sizeof(CharT));
58 return ret;
59}
60#ifdef STDPLUS_SPAN_TYPE
61template <typename T, typename IntT,
62 typename = std::enable_if_t<std::is_integral_v<IntT>>>
63T extract(span<const IntT>& data)
64{
65 T ret = copyFrom<T>(data);
66 static_assert(sizeof(T) % sizeof(IntT) == 0);
67 data = data.subspan(sizeof(T) / sizeof(IntT));
68 return ret;
69}
70#endif
71
72/** @brief Returns the span referencing the data of the raw trivial type
73 * or of trivial types in a contiguous container.
74 *
75 * @param[in] t - The trivial raw data
76 * @return A view over the input with the given output integral type
77 */
78template <typename CharT, typename T,
79 typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
80std::basic_string_view<CharT> asView(const T& t) noexcept
81{
82 static_assert(sizeof(T) % sizeof(CharT) == 0);
83 return {reinterpret_cast<const CharT*>(&t), sizeof(T) / sizeof(CharT)};
84}
85template <typename CharT, typename Container,
86 typename = std::enable_if_t<!std::is_trivially_copyable_v<Container>>,
87 typename = decltype(std::data(std::declval<Container>()))>
88std::basic_string_view<CharT> asView(const Container& c) noexcept
89{
90 static_assert(detail::trivialContainer<Container>);
91 static_assert(sizeof(*std::data(c)) % sizeof(CharT) == 0);
92 return {reinterpret_cast<const CharT*>(std::data(c)),
93 std::size(c) * sizeof(*std::data(c)) / sizeof(CharT)};
94}
95#ifdef STDPLUS_SPAN_TYPE
96template <typename IntT, typename T,
97 typename = std::enable_if_t<std::is_integral_v<IntT>>,
98 typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
99span<IntT> asSpan(T& t) noexcept
100{
101 static_assert(sizeof(T) % sizeof(IntT) == 0);
102 return {reinterpret_cast<IntT*>(&t), sizeof(T) / sizeof(IntT)};
103}
104template <typename IntT, typename Container,
105 typename = std::enable_if_t<std::is_integral_v<IntT>>,
106 typename = std::enable_if_t<!std::is_trivially_copyable_v<Container>>,
107 typename = decltype(std::data(std::declval<Container>()))>
108span<IntT> asSpan(Container& c) noexcept
109{
110 static_assert(detail::trivialContainer<Container>);
111 static_assert(sizeof(*std::data(c)) % sizeof(IntT) == 0);
112 return {reinterpret_cast<IntT*>(std::data(c)),
113 std::size(c) * sizeof(*std::data(c)) / sizeof(IntT)};
114}
115template <typename IntT, typename T,
116 typename = std::enable_if_t<std::is_integral_v<IntT>>,
117 typename = std::enable_if_t<std::is_trivially_copyable_v<T>>>
118span<const IntT> asSpan(const T& t) noexcept
119{
120 static_assert(sizeof(T) % sizeof(IntT) == 0);
121 return {reinterpret_cast<const IntT*>(&t), sizeof(T) / sizeof(IntT)};
122}
123template <typename IntT, typename Container,
124 typename = std::enable_if_t<std::is_integral_v<IntT>>,
125 typename = std::enable_if_t<!std::is_trivially_copyable_v<Container>>,
126 typename = decltype(std::data(std::declval<Container>()))>
127span<const IntT> asSpan(const Container& c) noexcept
128{
129 static_assert(detail::trivialContainer<Container>);
130 static_assert(sizeof(*std::data(c)) % sizeof(IntT) == 0);
131 return {reinterpret_cast<const IntT*>(std::data(c)),
132 std::size(c) * sizeof(*std::data(c)) / sizeof(IntT)};
133}
134#endif
135
136} // namespace raw
137} // namespace stdplus