WPILibC++ 2025.2.1
Loading...
Searching...
No Matches
Endian.h
Go to the documentation of this file.
1//===- Endian.h - Utilities for IO with endian specific data ----*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file declares generic functions to read and write endian specific data.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef WPIUTIL_WPI_ENDIAN_H
14#define WPIUTIL_WPI_ENDIAN_H
15
16#include "wpi/bit.h"
17#include "wpi/Compiler.h"
18#include "wpi/SwapByteOrder.h"
19#include <cassert>
20#include <cstddef>
21#include <cstdint>
22#include <cstring>
23#include <type_traits>
24
25namespace wpi {
26namespace support {
27
28// These are named values for common alignments.
29enum {aligned = 0, unaligned = 1};
30
31namespace detail {
32
33/// ::value is either alignment, or alignof(T) if alignment is 0.
34template<class T, int alignment>
36 enum { value = alignment == 0 ? alignof(T) : alignment };
37};
38
39} // end namespace detail
40
41namespace endian {
42
43template <typename value_type>
44[[nodiscard]] inline value_type byte_swap(value_type value, endianness endian) {
45 if (endian != wpi::endianness::native)
46 sys::swapByteOrder(value);
47 return value;
48}
49
50/// Swap the bytes of value to match the given endianness.
51template <typename value_type, endianness endian>
52[[nodiscard]] inline value_type byte_swap(value_type value) {
53 if constexpr (endian != wpi::endianness::native)
54 sys::swapByteOrder(value);
55 return value;
56}
57
58/// Read a value of a particular endianness from memory.
59template <typename value_type, std::size_t alignment = unaligned>
60[[nodiscard]] inline value_type read(const void *memory, endianness endian) {
61 value_type ret;
62
63 memcpy(&ret,
66 sizeof(value_type));
67 return byte_swap<value_type>(ret, endian);
68}
69
70template <typename value_type, endianness endian, std::size_t alignment>
71[[nodiscard]] inline value_type read(const void *memory) {
72 return read<value_type, alignment>(memory, endian);
73}
74
75/// Read a value of a particular endianness from a buffer, and increment the
76/// buffer past that value.
77template <typename value_type, std::size_t alignment = unaligned,
78 typename CharT>
79[[nodiscard]] inline value_type readNext(const CharT *&memory,
80 endianness endian) {
81 value_type ret = read<value_type, alignment>(memory, endian);
82 memory += sizeof(value_type);
83 return ret;
84}
85
86template <typename value_type, endianness endian,
87 std::size_t alignment = unaligned, typename CharT>
88[[nodiscard]] inline value_type readNext(const CharT *&memory) {
90}
91
92/// Write a value to memory with a particular endianness.
93template <typename value_type, std::size_t alignment = unaligned>
94inline void write(void *memory, value_type value, endianness endian) {
95 value = byte_swap<value_type>(value, endian);
98 &value, sizeof(value_type));
99}
100
101template<typename value_type,
102 endianness endian,
103 std::size_t alignment>
104inline void write(void *memory, value_type value) {
105 write<value_type, alignment>(memory, value, endian);
106}
107
108/// Write a value of a particular endianness, and increment the buffer past that
109/// value.
110template <typename value_type, std::size_t alignment = unaligned,
111 typename CharT>
112inline void writeNext(CharT *&memory, value_type value, endianness endian) {
113 write(memory, value, endian);
114 memory += sizeof(value_type);
115}
116
117template <typename value_type, endianness endian,
118 std::size_t alignment = unaligned, typename CharT>
119inline void writeNext(CharT *&memory, value_type value) {
121}
122
123template <typename value_type>
124using make_unsigned_t = std::make_unsigned_t<value_type>;
125
126/// Read a value of a particular endianness from memory, for a location
127/// that starts at the given bit offset within the first byte.
128template <typename value_type, endianness endian, std::size_t alignment>
129[[nodiscard]] inline value_type readAtBitAlignment(const void *memory,
130 uint64_t startBit) {
131 assert(startBit < 8);
132 if (startBit == 0)
134 else {
135 // Read two values and compose the result from them.
136 value_type val[2];
137 memcpy(&val[0],
140 sizeof(value_type) * 2);
141 val[0] = byte_swap<value_type, endian>(val[0]);
142 val[1] = byte_swap<value_type, endian>(val[1]);
143
144 // Shift bits from the lower value into place.
145 make_unsigned_t<value_type> lowerVal = val[0] >> startBit;
146 // Mask off upper bits after right shift in case of signed type.
147 make_unsigned_t<value_type> numBitsFirstVal =
148 (sizeof(value_type) * 8) - startBit;
149 lowerVal &= ((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1;
150
151 // Get the bits from the upper value.
153 val[1] & (((make_unsigned_t<value_type>)1 << startBit) - 1);
154 // Shift them in to place.
155 upperVal <<= numBitsFirstVal;
156
157 return lowerVal | upperVal;
158 }
159}
160
161/// Write a value to memory with a particular endianness, for a location
162/// that starts at the given bit offset within the first byte.
163template <typename value_type, endianness endian, std::size_t alignment>
164inline void writeAtBitAlignment(void *memory, value_type value,
165 uint64_t startBit) {
166 assert(startBit < 8);
167 if (startBit == 0)
169 else {
170 // Read two values and shift the result into them.
171 value_type val[2];
172 memcpy(&val[0],
175 sizeof(value_type) * 2);
176 val[0] = byte_swap<value_type, endian>(val[0]);
177 val[1] = byte_swap<value_type, endian>(val[1]);
178
179 // Mask off any existing bits in the upper part of the lower value that
180 // we want to replace.
181 val[0] &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
182 make_unsigned_t<value_type> numBitsFirstVal =
183 (sizeof(value_type) * 8) - startBit;
184 make_unsigned_t<value_type> lowerVal = value;
185 if (startBit > 0) {
186 // Mask off the upper bits in the new value that are not going to go into
187 // the lower value. This avoids a left shift of a negative value, which
188 // is undefined behavior.
189 lowerVal &= (((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1);
190 // Now shift the new bits into place
191 lowerVal <<= startBit;
192 }
193 val[0] |= lowerVal;
194
195 // Mask off any existing bits in the lower part of the upper value that
196 // we want to replace.
197 val[1] &= ~(((make_unsigned_t<value_type>)1 << startBit) - 1);
198 // Next shift the bits that go into the upper value into position.
199 make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal;
200 // Mask off upper bits after right shift in case of signed type.
201 upperVal &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
202 val[1] |= upperVal;
203
204 // Finally, rewrite values.
205 val[0] = byte_swap<value_type, endian>(val[0]);
206 val[1] = byte_swap<value_type, endian>(val[1]);
207 memcpy(LLVM_ASSUME_ALIGNED(
209 &val[0], sizeof(value_type) * 2);
210 }
211}
212
213} // end namespace endian
214
215namespace detail {
216
217template <typename ValueType, endianness Endian, std::size_t Alignment,
220 using value_type = ValueType;
221 static constexpr endianness endian = Endian;
222 static constexpr std::size_t alignment = Alignment;
223
225
226 explicit packed_endian_specific_integral(value_type val) { *this = val; }
227
228 operator value_type() const {
230 (const void*)Value.buffer);
231 }
232
233 void operator=(value_type newValue) {
235 (void*)Value.buffer, newValue);
236 }
237
239 *this = *this + newValue;
240 return *this;
241 }
242
244 *this = *this - newValue;
245 return *this;
246 }
247
249 *this = *this | newValue;
250 return *this;
251 }
252
254 *this = *this & newValue;
255 return *this;
256 }
257
258private:
259 struct {
260 alignas(ALIGN) char buffer[sizeof(value_type)];
261 } Value;
262
263public:
264 struct ref {
265 explicit ref(void *Ptr) : Ptr(Ptr) {}
266
267 operator value_type() const {
269 }
270
271 void operator=(value_type NewValue) {
273 }
274
275 private:
276 void *Ptr;
277 };
278};
279
280} // end namespace detail
281
284 unaligned>;
287 unaligned>;
290 unaligned>;
291
294 unaligned>;
297 unaligned>;
300 unaligned>;
301
304 aligned>;
307 aligned>;
310 aligned>;
311
314 aligned>;
317 aligned>;
320 aligned>;
321
322using ubig16_t =
324 unaligned>;
325using ubig32_t =
327 unaligned>;
328using ubig64_t =
330 unaligned>;
331
332using big16_t =
334 unaligned>;
335using big32_t =
337 unaligned>;
338using big64_t =
340 unaligned>;
341
344 aligned>;
347 aligned>;
350 aligned>;
351
354 aligned>;
357 aligned>;
360 aligned>;
361
364 unaligned>;
367 unaligned>;
370 unaligned>;
371
374 unaligned>;
377 unaligned>;
380 unaligned>;
381
382template <typename T>
383using little_t =
385 unaligned>;
386template <typename T>
388 unaligned>;
389
390template <typename T>
393 aligned>;
394template <typename T>
397
398namespace endian {
399
400template <typename T, endianness E> [[nodiscard]] inline T read(const void *P) {
402}
403
404[[nodiscard]] inline uint16_t read16(const void *P, endianness E) {
405 return read<uint16_t>(P, E);
406}
407[[nodiscard]] inline uint32_t read32(const void *P, endianness E) {
408 return read<uint32_t>(P, E);
409}
410[[nodiscard]] inline uint64_t read64(const void *P, endianness E) {
411 return read<uint64_t>(P, E);
412}
413
414template <endianness E> [[nodiscard]] inline uint16_t read16(const void *P) {
415 return read<uint16_t, E>(P);
416}
417template <endianness E> [[nodiscard]] inline uint32_t read32(const void *P) {
418 return read<uint32_t, E>(P);
419}
420template <endianness E> [[nodiscard]] inline uint64_t read64(const void *P) {
421 return read<uint64_t, E>(P);
422}
423
424[[nodiscard]] inline uint16_t read16le(const void *P) {
426}
427[[nodiscard]] inline uint32_t read32le(const void *P) {
429}
430[[nodiscard]] inline uint64_t read64le(const void *P) {
432}
433[[nodiscard]] inline uint16_t read16be(const void *P) {
435}
436[[nodiscard]] inline uint32_t read32be(const void *P) {
438}
439[[nodiscard]] inline uint64_t read64be(const void *P) {
441}
442
443template <typename T, endianness E> inline void write(void *P, T V) {
445}
446
447inline void write16(void *P, uint16_t V, endianness E) {
448 write<uint16_t>(P, V, E);
449}
450inline void write32(void *P, uint32_t V, endianness E) {
451 write<uint32_t>(P, V, E);
452}
453inline void write64(void *P, uint64_t V, endianness E) {
454 write<uint64_t>(P, V, E);
455}
456
457template <endianness E> inline void write16(void *P, uint16_t V) {
458 write<uint16_t, E>(P, V);
459}
460template <endianness E> inline void write32(void *P, uint32_t V) {
461 write<uint32_t, E>(P, V);
462}
463template <endianness E> inline void write64(void *P, uint64_t V) {
464 write<uint64_t, E>(P, V);
465}
466
467inline void write16le(void *P, uint16_t V) {
469}
470inline void write32le(void *P, uint32_t V) {
472}
473inline void write64le(void *P, uint64_t V) {
475}
476inline void write16be(void *P, uint16_t V) {
478}
479inline void write32be(void *P, uint32_t V) {
481}
482inline void write64be(void *P, uint64_t V) {
484}
485
486} // end namespace endian
487
488} // end namespace support
489} // end namespace wpi
490
491#endif // WPIUTIL_WPI_ENDIAN_H
#define LLVM_ASSUME_ALIGNED(p, a)
\macro LLVM_ASSUME_ALIGNED Returns a pointer with an assumed alignment.
Definition Compiler.h:435
This file implements the C++20 <bit> header.
detail namespace with internal helper functions
Definition input_adapters.h:32
Memory namespace.
Definition heap_allocator.hpp:20
uint64_t read64(const void *P, endianness E)
Definition Endian.h:410
std::make_unsigned_t< value_type > make_unsigned_t
Definition Endian.h:124
void writeAtBitAlignment(void *memory, value_type value, uint64_t startBit)
Write a value to memory with a particular endianness, for a location that starts at the given bit off...
Definition Endian.h:164
uint32_t read32le(const void *P)
Definition Endian.h:427
value_type read(const void *memory, endianness endian)
Read a value of a particular endianness from memory.
Definition Endian.h:60
uint64_t read64be(const void *P)
Definition Endian.h:439
void write32be(void *P, uint32_t V)
Definition Endian.h:479
void write64be(void *P, uint64_t V)
Definition Endian.h:482
uint32_t read32be(const void *P)
Definition Endian.h:436
void write(void *memory, value_type value, endianness endian)
Write a value to memory with a particular endianness.
Definition Endian.h:94
value_type byte_swap(value_type value, endianness endian)
Definition Endian.h:44
uint64_t read64le(const void *P)
Definition Endian.h:430
void write32le(void *P, uint32_t V)
Definition Endian.h:470
uint16_t read16le(const void *P)
Definition Endian.h:424
void write64le(void *P, uint64_t V)
Definition Endian.h:473
value_type readNext(const CharT *&memory, endianness endian)
Read a value of a particular endianness from a buffer, and increment the buffer past that value.
Definition Endian.h:79
void writeNext(CharT *&memory, value_type value, endianness endian)
Write a value of a particular endianness, and increment the buffer past that value.
Definition Endian.h:112
void write32(void *P, uint32_t V, endianness E)
Definition Endian.h:450
void write16(void *P, uint16_t V, endianness E)
Definition Endian.h:447
uint32_t read32(const void *P, endianness E)
Definition Endian.h:407
void write64(void *P, uint64_t V, endianness E)
Definition Endian.h:453
void write16be(void *P, uint16_t V)
Definition Endian.h:476
uint16_t read16be(const void *P)
Definition Endian.h:433
uint16_t read16(const void *P, endianness E)
Definition Endian.h:404
void write16le(void *P, uint16_t V)
Definition Endian.h:467
value_type readAtBitAlignment(const void *memory, uint64_t startBit)
Read a value of a particular endianness from memory, for a location that starts at the given bit offs...
Definition Endian.h:129
@ unaligned
Definition Endian.h:29
@ aligned
Definition Endian.h:29
void swapByteOrder(T &Value)
Definition SwapByteOrder.h:61
Foonathan namespace.
Definition ntcore_cpp.h:26
endianness
Definition bit.h:32
value is either alignment, or alignof(T) if alignment is 0.
Definition Endian.h:35
@ value
Definition Endian.h:36
void operator=(value_type NewValue)
Definition Endian.h:271
char buffer[sizeof(value_type)]
Definition Endian.h:260
packed_endian_specific_integral & operator|=(value_type newValue)
Definition Endian.h:248
static constexpr std::size_t alignment
Definition Endian.h:222
packed_endian_specific_integral(value_type val)
Definition Endian.h:226
packed_endian_specific_integral & operator&=(value_type newValue)
Definition Endian.h:253
static constexpr endianness endian
Definition Endian.h:221
packed_endian_specific_integral & operator-=(value_type newValue)
Definition Endian.h:243
packed_endian_specific_integral & operator+=(value_type newValue)
Definition Endian.h:238
void operator=(value_type newValue)
Definition Endian.h:233