14 #ifndef WPIUTIL_WPI_ENDIAN_H
15 #define WPIUTIL_WPI_ENDIAN_H
17 #include "wpi/AlignOf.h"
18 #include "wpi/Compiler.h"
19 #include "wpi/SwapByteOrder.h"
21 #if defined(__linux__) || defined(__GNU__)
29 #include <type_traits>
34 enum endianness {big, little, native};
37 enum {aligned = 0, unaligned = 1};
42 template<
class T,
int alignment>
44 enum { value = alignment == 0 ?
alignof(T) : alignment };
51 constexpr endianness system_endianness() {
54 #elif defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && __BYTE_ORDER == __BIG_ENDIAN
61 template <
typename value_type>
62 inline value_type byte_swap(value_type value, endianness endian) {
63 if ((endian != native) && (endian != system_endianness()))
64 sys::swapByteOrder(value);
69 template<
typename value_type, endianness endian>
70 inline value_type byte_swap(value_type value) {
71 return byte_swap(value, endian);
75 template <
typename value_type, std::
size_t alignment>
76 inline value_type read(
const void *memory, endianness endian) {
81 memory, (detail::PickAlignment<value_type, alignment>::value)),
83 return byte_swap<value_type>(ret, endian);
86 template<
typename value_type,
88 std::size_t alignment>
89 inline value_type read(
const void *memory) {
90 return read<value_type, alignment>(memory, endian);
95 template <
typename value_type, std::
size_t alignment,
typename CharT>
96 inline value_type readNext(
const CharT *&memory, endianness endian) {
97 value_type ret = read<value_type, alignment>(memory, endian);
98 memory +=
sizeof(value_type);
102 template<
typename value_type, endianness endian, std::size_t alignment,
104 inline value_type readNext(
const CharT *&memory) {
105 return readNext<value_type, alignment, CharT>(memory, endian);
109 template <
typename value_type, std::
size_t alignment>
110 inline void write(
void *memory, value_type value, endianness endian) {
111 value = byte_swap<value_type>(value, endian);
112 memcpy(LLVM_ASSUME_ALIGNED(
113 memory, (detail::PickAlignment<value_type, alignment>::value)),
114 &value,
sizeof(value_type));
117 template<
typename value_type,
119 std::size_t alignment>
120 inline void write(
void *memory, value_type value) {
121 write<value_type, alignment>(memory, value, endian);
124 template <
typename value_type>
125 using make_unsigned_t =
typename std::make_unsigned<value_type>::type;
129 template <
typename value_type, endianness endian, std::
size_t alignment>
130 inline value_type readAtBitAlignment(
const void *memory, uint64_t startBit) {
131 assert(startBit < 8);
133 return read<value_type, endian, alignment>(memory);
139 memory, (detail::PickAlignment<value_type, alignment>::value)),
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]);
145 make_unsigned_t<value_type> lowerVal = val[0] >> startBit;
147 make_unsigned_t<value_type> numBitsFirstVal =
148 (
sizeof(value_type) * 8) - startBit;
149 lowerVal &= ((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1;
152 make_unsigned_t<value_type> upperVal =
153 val[1] & (((make_unsigned_t<value_type>)1 << startBit) - 1);
155 upperVal <<= numBitsFirstVal;
157 return lowerVal | upperVal;
163 template <
typename value_type, endianness endian, std::
size_t alignment>
164 inline void writeAtBitAlignment(
void *memory, value_type value,
166 assert(startBit < 8);
168 write<value_type, endian, alignment>(memory, value);
174 memory, (detail::PickAlignment<value_type, alignment>::value)),
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]);
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;
189 lowerVal &= (((make_unsigned_t<value_type>)1 << numBitsFirstVal) - 1);
191 lowerVal <<= startBit;
197 val[1] &= ~(((make_unsigned_t<value_type>)1 << startBit) - 1);
199 make_unsigned_t<value_type> upperVal = value >> numBitsFirstVal;
201 upperVal &= ((make_unsigned_t<value_type>)1 << startBit) - 1;
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(
208 memory, (detail::PickAlignment<value_type, alignment>::value)),
209 &val[0],
sizeof(value_type) * 2);
217 template<
typename value_type,
219 std::size_t alignment>
225 operator value_type()
const {
226 return endian::read<value_type, endian, alignment>(
227 (
const void*)Value.buffer);
230 void operator=(value_type newValue) {
231 endian::write<value_type, endian, alignment>(
232 (
void*)Value.buffer, newValue);
236 *
this = *
this + newValue;
241 *
this = *
this - newValue;
246 *
this = *
this | newValue;
251 *
this = *
this & newValue;
257 sizeof(value_type)> Value;
261 explicit ref(
void *Ptr) : Ptr(Ptr) {}
263 operator value_type()
const {
264 return endian::read<value_type, endian, alignment>(Ptr);
267 void operator=(value_type NewValue) {
268 endian::write<value_type, endian, alignment>(Ptr, NewValue);
350 template <
typename T>
inline T read(
const void *P, endianness E) {
351 return read<T, unaligned>(P, E);
354 template <
typename T, endianness E>
inline T read(
const void *P) {
355 return *(
const detail::packed_endian_specific_integral<T, E, unaligned> *)P;
358 inline uint16_t read16(
const void *P, endianness E) {
359 return read<uint16_t>(P, E);
361 inline uint32_t read32(
const void *P, endianness E) {
362 return read<uint32_t>(P, E);
364 inline uint64_t read64(
const void *P, endianness E) {
365 return read<uint64_t>(P, E);
368 template <endianness E>
inline uint16_t read16(
const void *P) {
369 return read<uint16_t, E>(P);
371 template <endianness E>
inline uint32_t read32(
const void *P) {
372 return read<uint32_t, E>(P);
374 template <endianness E>
inline uint64_t read64(
const void *P) {
375 return read<uint64_t, E>(P);
378 inline uint16_t read16le(
const void *P) {
return read16<little>(P); }
379 inline uint32_t read32le(
const void *P) {
return read32<little>(P); }
380 inline uint64_t read64le(
const void *P) {
return read64<little>(P); }
381 inline uint16_t read16be(
const void *P) {
return read16<big>(P); }
382 inline uint32_t read32be(
const void *P) {
return read32<big>(P); }
383 inline uint64_t read64be(
const void *P) {
return read64<big>(P); }
385 template <
typename T>
inline void write(
void *P, T V, endianness E) {
386 write<T, unaligned>(P, V, E);
389 template <
typename T, endianness E>
inline void write(
void *P, T V) {
390 *(detail::packed_endian_specific_integral<T, E, unaligned> *)P = V;
393 inline void write16(
void *P, uint16_t V, endianness E) {
394 write<uint16_t>(P, V, E);
396 inline void write32(
void *P, uint32_t V, endianness E) {
397 write<uint32_t>(P, V, E);
399 inline void write64(
void *P, uint64_t V, endianness E) {
400 write<uint64_t>(P, V, E);
403 template <endianness E>
inline void write16(
void *P, uint16_t V) {
404 write<uint16_t, E>(P, V);
406 template <endianness E>
inline void write32(
void *P, uint32_t V) {
407 write<uint32_t, E>(P, V);
409 template <endianness E>
inline void write64(
void *P, uint64_t V) {
410 write<uint64_t, E>(P, V);
413 inline void write16le(
void *P, uint16_t V) { write16<little>(P, V); }
414 inline void write32le(
void *P, uint32_t V) { write32<little>(P, V); }
415 inline void write64le(
void *P, uint64_t V) { write64<little>(P, V); }
416 inline void write16be(
void *P, uint16_t V) { write16<big>(P, V); }
417 inline void write32be(
void *P, uint32_t V) { write32<big>(P, V); }
418 inline void write64be(
void *P, uint64_t V) { write64<big>(P, V); }
425 #endif // WPIUTIL_WPI_ENDIAN_H