22#include "pw_bytes/array.h"
23#include "pw_bytes/bit.h"
24#include "pw_bytes/span.h"
25#include "pw_span/span.h"
42 std::conditional_t<sizeof(T) == 8, uint64_t, void>>>> {
43 static_assert(std::is_integral_v<T>);
50constexpr std::array<std::byte,
sizeof(T)> CopyLittleEndian(T value) {
51 return CopyLittleEndian(
static_cast<EquivalentUint<T>
>(value));
55constexpr std::array<std::byte, 1> CopyLittleEndian<uint8_t>(uint8_t value) {
56 return MakeArray(value);
59constexpr std::array<std::byte, 2> CopyLittleEndian<uint16_t>(uint16_t value) {
60 return MakeArray(value & 0x00FF, (value & 0xFF00) >> 8);
64constexpr std::array<std::byte, 4> CopyLittleEndian<uint32_t>(uint32_t value) {
65 return MakeArray((value & 0x000000FF) >> 0 * 8,
66 (value & 0x0000FF00) >> 1 * 8,
67 (value & 0x00FF0000) >> 2 * 8,
68 (value & 0xFF000000) >> 3 * 8);
72constexpr std::array<std::byte, 8> CopyLittleEndian<uint64_t>(uint64_t value) {
73 return MakeArray((value & 0x00000000000000FF) >> 0 * 8,
74 (value & 0x000000000000FF00) >> 1 * 8,
75 (value & 0x0000000000FF0000) >> 2 * 8,
76 (value & 0x00000000FF000000) >> 3 * 8,
77 (value & 0x000000FF00000000) >> 4 * 8,
78 (value & 0x0000FF0000000000) >> 5 * 8,
79 (value & 0x00FF000000000000) >> 6 * 8,
80 (value & 0xFF00000000000000) >> 7 * 8);
84constexpr T ReverseBytes(T value) {
85 EquivalentUint<T> uint =
static_cast<EquivalentUint<T>
>(value);
87 if constexpr (
sizeof(uint) == 1) {
88 return static_cast<T
>(uint);
89 }
else if constexpr (
sizeof(uint) == 2) {
90 return static_cast<T
>(((uint & 0x00FF) << 8) | ((uint & 0xFF00) >> 8));
91 }
else if constexpr (
sizeof(uint) == 4) {
92 return static_cast<T
>(((uint & 0x000000FF) << 3 * 8) |
93 ((uint & 0x0000FF00) << 1 * 8) |
94 ((uint & 0x00FF0000) >> 1 * 8) |
95 ((uint & 0xFF000000) >> 3 * 8));
97 static_assert(
sizeof(uint) == 8);
98 return static_cast<T
>(((uint & 0x00000000000000FF) << 7 * 8) |
99 ((uint & 0x000000000000FF00) << 5 * 8) |
100 ((uint & 0x0000000000FF0000) << 3 * 8) |
101 ((uint & 0x00000000FF000000) << 1 * 8) |
102 ((uint & 0x000000FF00000000) >> 1 * 8) |
103 ((uint & 0x0000FF0000000000) >> 3 * 8) |
104 ((uint & 0x00FF000000000000) >> 5 * 8) |
105 ((uint & 0xFF00000000000000) >> 7 * 8));
119constexpr T ConvertOrder(endian from, endian to, T value) {
120 return from == to ? value : internal::ReverseBytes(value);
127constexpr T ConvertOrderTo(endian to_endianness, T value) {
128 return ConvertOrder(endian::native, to_endianness, value);
133constexpr T ConvertOrderFrom(endian from_endianness, T value) {
134 return ConvertOrder(from_endianness, endian::native, value);
139constexpr auto CopyInOrder(endian order, T value) {
140 return internal::CopyLittleEndian(ConvertOrderTo(order, value));
149T ReadInOrder(endian order,
const void* buffer) {
151 std::memcpy(&value, buffer,
sizeof(value));
152 return ConvertOrderFrom(order, value);
164T ReadInOrder(endian order,
const void* buffer,
size_t max_bytes_to_read) {
166 std::memcpy(&value, buffer, std::min(
sizeof(value), max_bytes_to_read));
167 return ConvertOrderFrom(order, value);
174 typename = std::enable_if_t<kBufferSize != dynamic_extent &&
175 sizeof(B) ==
sizeof(std::byte)>>
176T ReadInOrder(endian order, span<B, kBufferSize> buffer) {
177 static_assert(kBufferSize >=
sizeof(T));
178 return ReadInOrder<T>(order, buffer.data());
182template <
typename T,
typename B,
size_t kBufferSize>
183T ReadInOrder(endian order,
const std::array<B, kBufferSize>& buffer) {
184 return ReadInOrder<T>(order, span(buffer));
188template <
typename T,
typename B,
size_t kBufferSize>
189T ReadInOrder(endian order,
const B (&buffer)[kBufferSize]) {
190 return ReadInOrder<T>(order, span(buffer));
196[[nodiscard]]
bool ReadInOrder(endian order, ConstByteSpan buffer, T& value) {
197 if (buffer.size() <
sizeof(T)) {
201 value = ReadInOrder<T>(order, buffer.data());