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
116
123template <typename T>
124constexpr T ConvertOrder(endian from, endian to, T value) {
125 return from == to ? value : internal::ReverseBytes(value);
126}
127
131template <typename T>
132constexpr T ConvertOrderTo(endian to_endianness, T value) {
133 return ConvertOrder(endian::native, to_endianness, value);
134}
135
137template <typename T>
138constexpr T ConvertOrderFrom(endian from_endianness, T value) {
139 return ConvertOrder(from_endianness, endian::native, value);
140}
141
145template <typename T, typename U>
146constexpr void CopyInOrder(endian order, T value, U* dest) {
147 static_assert(std::is_same_v<U, std::byte> || std::is_same_v<U, char> ||
148 std::is_same_v<U, unsigned char> ||
149 std::is_same_v<U, signed char>,
150 "pw::bytes::CopyInOrder can only copy to a byte type");
151 internal::CopyLittleEndian(ConvertOrderTo(order, value), dest);
152}
153
155template <typename T>
156constexpr auto CopyInOrder(endian order, T value) {
157 std::array<std::byte, sizeof(T)> bytes{};
158 CopyInOrder(order, value, bytes.data());
159 return bytes;
160}
161
168template <typename T>
169T ReadInOrder(endian order, const void* buffer) {
170 T value;
171 std::memcpy(&value, buffer, sizeof(value));
172 return ConvertOrderFrom(order, value);
173}
174
183template <typename T>
184T ReadInOrder(endian order, const void* buffer, size_t max_bytes_to_read) {
185 T value = {};
186 std::memcpy(&value, buffer, std::min(sizeof(value), max_bytes_to_read));
187 return ConvertOrderFrom(order, value);
188}
189
191template <typename T,
192 typename B,
193 size_t kBufferSize,
194 typename = std::enable_if_t<kBufferSize != dynamic_extent &&
195 sizeof(B) == sizeof(std::byte)>>
196T ReadInOrder(endian order, span<B, kBufferSize> buffer) {
197 static_assert(kBufferSize >= sizeof(T));
198 return ReadInOrder<T>(order, buffer.data());
199}
200
202template <typename T, typename B, size_t kBufferSize>
203T ReadInOrder(endian order, const std::array<B, kBufferSize>& buffer) {
204 return ReadInOrder<T>(order, span(buffer));
205}
206
208template <typename T, typename B, size_t kBufferSize>
209T ReadInOrder(endian order, const B (&buffer)[kBufferSize]) {
210 return ReadInOrder<T>(order, span(buffer));
211}
212
217template <typename T>
218[[nodiscard]] bool ReadInOrder(endian order, ConstByteSpan buffer, T& value) {
219 if (buffer.size() < sizeof(T)) {
220 return false;
221 }
222
223 value = ReadInOrder<T>(order, buffer.data());
224 return true;
225}
226
228
229} // namespace pw::bytes
Definition: span_impl.h:235
constexpr T ConvertOrderTo(endian to_endianness, T value)
Definition: endian.h:132
constexpr T ConvertOrder(endian from, endian to, T value)
Definition: endian.h:124
constexpr T ConvertOrderFrom(endian from_endianness, T value)
Converts a value from the specified byte order to the native byte order.
Definition: endian.h:138
constexpr void CopyInOrder(endian order, T value, U *dest)
Definition: endian.h:146
T ReadInOrder(endian order, const void *buffer)
Definition: endian.h:169
Binary data manipulation utilities.
Definition: array.h:25