C/C++ API Reference
Loading...
Searching...
No Matches
endian.h
1// Copyright 2020 The Pigweed Authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not
4// use this file except in compliance with the License. You may obtain a copy of
5// the License at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12// License for the specific language governing permissions and limitations under
13// the License.
14#pragma once
15
16#include <algorithm>
17#include <array>
18#include <cstdint>
19#include <cstring>
20#include <type_traits>
21
22#include "pw_bytes/array.h"
23#include "pw_bytes/bit.h"
24#include "pw_bytes/span.h"
25#include "pw_span/span.h"
26
27namespace pw::bytes {
28namespace internal {
29
30// Use a struct rather than an alias to give the type a more reasonable name.
31template <typename T>
33 : std::conditional<
34 sizeof(T) == 1,
35 uint8_t,
36 std::conditional_t<
37 sizeof(T) == 2,
38 uint16_t,
39 std::conditional_t<
40 sizeof(T) == 4,
41 uint32_t,
42 std::conditional_t<sizeof(T) == 8, uint64_t, void>>>> {
43 static_assert(std::is_integral_v<T>);
44};
45
46template <typename T>
47using EquivalentUint = typename EquivalentUintImpl<T>::type;
48
49template <typename U>
50constexpr void CopyLittleEndian(uint8_t value, U* dest) {
51 dest[0] = static_cast<U>(value);
52}
53
54template <typename U>
55constexpr void CopyLittleEndian(uint16_t value, U* dest) {
56 dest[0] = static_cast<U>(value & 0x00FF);
57 dest[1] = static_cast<U>((value & 0xFF00) >> 8);
58}
59
60template <typename U>
61constexpr void CopyLittleEndian(uint32_t value, U* dest) {
62 dest[0] = static_cast<U>((value & 0x000000FF) >> 0 * 8);
63 dest[1] = static_cast<U>((value & 0x0000FF00) >> 1 * 8);
64 dest[2] = static_cast<U>((value & 0x00FF0000) >> 2 * 8);
65 dest[3] = static_cast<U>((value & 0xFF000000) >> 3 * 8);
66}
67
68template <typename U>
69constexpr void CopyLittleEndian(uint64_t value, U* dest) {
70 dest[0] = static_cast<U>((value & 0x00000000000000FF) >> 0 * 8);
71 dest[1] = static_cast<U>((value & 0x000000000000FF00) >> 1 * 8);
72 dest[2] = static_cast<U>((value & 0x0000000000FF0000) >> 2 * 8);
73 dest[3] = static_cast<U>((value & 0x00000000FF000000) >> 3 * 8);
74 dest[4] = static_cast<U>((value & 0x000000FF00000000) >> 4 * 8);
75 dest[5] = static_cast<U>((value & 0x0000FF0000000000) >> 5 * 8);
76 dest[6] = static_cast<U>((value & 0x00FF000000000000) >> 6 * 8);
77 dest[7] = static_cast<U>((value & 0xFF00000000000000) >> 7 * 8);
78}
79
80template <typename T, typename U>
81constexpr void CopyLittleEndian(T value, U* dest) {
82 CopyLittleEndian(static_cast<EquivalentUint<T>>(value), dest);
83}
84
85template <typename T>
86constexpr T ReverseBytes(T value) {
87 EquivalentUint<T> unsigned_int = static_cast<EquivalentUint<T>>(value);
88
89 if constexpr (sizeof(unsigned_int) == 1) {
90 return static_cast<T>(unsigned_int);
91 } else if constexpr (sizeof(unsigned_int) == 2) {
92 return static_cast<T>(((unsigned_int & 0x00FF) << 8) |
93 ((unsigned_int & 0xFF00) >> 8));
94 } else if constexpr (sizeof(unsigned_int) == 4) {
95 return static_cast<T>(((unsigned_int & 0x000000FF) << 3 * 8) | //
96 ((unsigned_int & 0x0000FF00) << 1 * 8) | //
97 ((unsigned_int & 0x00FF0000) >> 1 * 8) | //
98 ((unsigned_int & 0xFF000000) >> 3 * 8));
99 } else {
100 static_assert(sizeof(unsigned_int) == 8);
101 return static_cast<T>(((unsigned_int & 0x00000000000000FF) << 7 * 8) | //
102 ((unsigned_int & 0x000000000000FF00) << 5 * 8) | //
103 ((unsigned_int & 0x0000000000FF0000) << 3 * 8) | //
104 ((unsigned_int & 0x00000000FF000000) << 1 * 8) | //
105 ((unsigned_int & 0x000000FF00000000) >> 1 * 8) | //
106 ((unsigned_int & 0x0000FF0000000000) >> 3 * 8) | //
107 ((unsigned_int & 0x00FF000000000000) >> 5 * 8) | //
108 ((unsigned_int & 0xFF00000000000000) >> 7 * 8));
109 }
110}
111
112} // namespace internal
113
115
122template <typename T>
123constexpr T ConvertOrder(endian from, endian to, T value) {
124 return from == to ? value : internal::ReverseBytes(value);
125}
126
130template <typename T>
131constexpr T ConvertOrderTo(endian to_endianness, T value) {
132 return ConvertOrder(endian::native, to_endianness, value);
133}
134
136template <typename T>
137constexpr T ConvertOrderFrom(endian from_endianness, T value) {
138 return ConvertOrder(from_endianness, endian::native, value);
139}
140
144template <typename T, typename U>
145constexpr void CopyInOrder(endian order, T value, U* dest) {
146 static_assert(std::is_same_v<U, std::byte> || std::is_same_v<U, char> ||
147 std::is_same_v<U, unsigned char> ||
148 std::is_same_v<U, signed char>,
149 "pw::bytes::CopyInOrder can only copy to a byte type");
150 internal::CopyLittleEndian(ConvertOrderTo(order, value), dest);
151}
152
154template <typename T>
155constexpr auto CopyInOrder(endian order, T value) {
156 std::array<std::byte, sizeof(T)> bytes{};
157 CopyInOrder(order, value, bytes.data());
158 return bytes;
159}
160
167template <typename T>
168T ReadInOrder(endian order, const void* buffer) {
169 T value;
170 std::memcpy(&value, buffer, sizeof(value));
171 return ConvertOrderFrom(order, value);
172}
173
182template <typename T>
183T ReadInOrder(endian order, const void* buffer, size_t max_bytes_to_read) {
184 T value = {};
185 std::memcpy(&value, buffer, std::min(sizeof(value), max_bytes_to_read));
186 return ConvertOrderFrom(order, value);
187}
188
190template <typename T,
191 typename B,
192 size_t kBufferSize,
193 typename = std::enable_if_t<kBufferSize != dynamic_extent &&
194 sizeof(B) == sizeof(std::byte)>>
195T ReadInOrder(endian order, span<B, kBufferSize> buffer) {
196 static_assert(kBufferSize >= sizeof(T));
197 return ReadInOrder<T>(order, buffer.data());
198}
199
201template <typename T, typename B, size_t kBufferSize>
202T ReadInOrder(endian order, const std::array<B, kBufferSize>& buffer) {
203 return ReadInOrder<T>(order, span(buffer));
204}
205
207template <typename T, typename B, size_t kBufferSize>
208T ReadInOrder(endian order, const B (&buffer)[kBufferSize]) {
209 return ReadInOrder<T>(order, span(buffer));
210}
211
216template <typename T>
217[[nodiscard]] bool ReadInOrder(endian order, ConstByteSpan buffer, T& value) {
218 if (buffer.size() < sizeof(T)) {
219 return false;
220 }
221
222 value = ReadInOrder<T>(order, buffer.data());
223 return true;
224}
225
227
228} // namespace pw::bytes
Definition: span_impl.h:235
constexpr T ConvertOrderTo(endian to_endianness, T value)
Definition: endian.h:131
constexpr T ConvertOrder(endian from, endian to, T value)
Definition: endian.h:123
constexpr T ConvertOrderFrom(endian from_endianness, T value)
Converts a value from the specified byte order to the native byte order.
Definition: endian.h:137
constexpr void CopyInOrder(endian order, T value, U *dest)
Definition: endian.h:145
T ReadInOrder(endian order, const void *buffer)
Definition: endian.h:168