Gamp v0.0.8
Gamp: Graphics, Audio, Multimedia and Processing
Loading...
Searching...
No Matches
byte_util.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2020-2024 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#ifndef JAU_BYTE_UTIL_HPP_
26#define JAU_BYTE_UTIL_HPP_
27
28#include <array>
29#include <cstring>
30#include <string>
31#include <cstdint>
32#include <type_traits>
33
34#include <jau/cpp_lang_util.hpp>
35#include <jau/cpp_pragma.hpp>
37
38#include <jau/int_types.hpp>
39#include <jau/type_concepts.hpp>
40
41namespace jau {
42
43 /** @defgroup ByteUtils Byte Utilities
44 * Byte utility functions and types for endian- and bit conversions,
45 * inclusive alignment handling and general get & put functionality.
46 *
47 * This category is also supporting \ref Integer.
48 *
49 * All \ref endian API entries are of `constexpr` and hence evaluated at compile time.<br>
50 * Therefore, if-branches and expressions are also of `constexpr` and optimized 'away' at compile time.<br>
51 * This includes the `cpu_to_<endian>(..)` and `<endian>_to_cpu(..)` etc utility functions.
52 *
53 * See \ref endian enum class regarding endian `constexpr` compile time determination.
54 *
55 * Aligned memory transfer from and to potentially unaligned memory
56 * is performed via put_uint16(), get_uint16() with all its explicit stdint types,
57 * as well as the generic template functions put_value() and get_value().
58 * The implementation uses \ref packed_t to resolve a potential memory alignment issue *free of costs*,
59 * see \ref packed_t_alignment_cast.
60 *
61 * @{
62 */
63
64 #if defined __has_builtin
65 #if __has_builtin(__builtin_bswap16)
66 #define __has_builtin_bswap16 1
67 #endif
68 #elif defined(__GNUC__) && __GNUC_PREREQ (4, 8)
69 #define __has_builtin_bswap16 1
70 #endif
71 #if defined __has_builtin
72 #if __has_builtin(__builtin_bswap32)
73 #define __has_builtin_bswap32 1
74 #endif
75 #elif defined(__GNUC__) && __GNUC_PREREQ (4, 8)
76 #define __has_builtin_bswap32 1
77 #endif
78 #if defined __has_builtin
79 #if __has_builtin(__builtin_bswap64)
80 #define __has_builtin_bswap64 1
81 #endif
82 #elif defined(__GNUC__) && __GNUC_PREREQ (4, 8)
83 #define __has_builtin_bswap64 1
84 #endif
85
86 // Remember: constexpr specifier used in a function or static data member (since C++17) declaration implies inline.
87
88 template <jau::req::unsigned_integral T>
89 requires (sizeof(T) == 2)
90 constexpr T bswap(T const & source) noexcept {
91 #if defined __has_builtin_bswap16
92 return __builtin_bswap16(source);
93 #else
94 using namespace jau::int_literals;
95 return (T) ( ( ( source >> 8 ) & 0xff ) |
96 ( ( source & 0xff_u16) << 8 ) );
97 #endif
98 }
99
100 template <jau::req::signed_integral T>
101 requires (sizeof(T) == 2)
102 constexpr T bswap(T const & source) noexcept {
103 #if defined __has_builtin_bswap16
104 return jau::bit_cast<int16_t>( __builtin_bswap16(jau::bit_cast<uint16_t>(source)) );
105 #else
106 using namespace jau::int_literals;
107 const uint16_t usource = jau::bit_cast<uint16_t>(source);
108 return (T) ( ( ( usource >> 8 ) & 0xff ) |
109 ( ( usource & 0xff_u16) << 8 ) );
110 #endif
111 }
112
113 template <jau::req::unsigned_integral T>
114 requires (sizeof(T) == 4)
115 constexpr T bswap(T const & source) noexcept {
116 #if defined __has_builtin_bswap32
117 return __builtin_bswap32(source);
118 #else
119 using namespace jau::int_literals;
120 return ( ( source & 0xff000000_u32 ) >> 24 ) |
121 ( ( source & 0x00ff0000_u32 ) >> 8 ) |
122 ( ( source & 0x0000ff00_u32 ) << 8 ) |
123 ( ( source & 0x000000ff_u32 ) << 24 );
124 #endif
125 }
126
127 template <jau::req::signed_integral T>
128 requires (sizeof(T) == 4)
129 constexpr T bswap(T const & source) noexcept {
130 #if defined __has_builtin_bswap32
131 return jau::bit_cast<T>( __builtin_bswap32(jau::bit_cast<uint32_t>(source)) );
132 #else
133 using namespace jau::int_literals;
134 const uint32_t usource = jau::bit_cast<uint32_t>(source);
135 return jau::bit_cast<T>( ( ( usource & 0xff000000_u32 ) >> 24 ) |
136 ( ( usource & 0x00ff0000_u32 ) >> 8 ) |
137 ( ( usource & 0x0000ff00_u32 ) << 8 ) |
138 ( ( usource & 0x000000ff_u32 ) << 24 ) );
139 #endif
140 }
141
142 template <jau::req::unsigned_integral T>
143 requires (sizeof(T) == 8)
144 constexpr T bswap(T const & source) noexcept {
145 #if defined __has_builtin_bswap64
146 return __builtin_bswap64(source);
147 #else
148 using namespace jau::int_literals;
149 return ( ( source & 0xff00000000000000_u64 ) >> 56 ) |
150 ( ( source & 0x00ff000000000000_u64 ) >> 40 ) |
151 ( ( source & 0x0000ff0000000000_u64 ) >> 24 ) |
152 ( ( source & 0x000000ff00000000_u64 ) >> 8 ) |
153 ( ( source & 0x00000000ff000000_u64 ) << 8 ) |
154 ( ( source & 0x0000000000ff0000_u64 ) << 24 ) |
155 ( ( source & 0x000000000000ff00_u64 ) << 40 ) |
156 ( ( source & 0x00000000000000ff_u64 ) << 56 );
157 #endif
158 }
159
160 template <jau::req::signed_integral T>
161 requires (sizeof(T) == 8)
162 constexpr T bswap(T const & source) noexcept {
163 #if defined __has_builtin_bswap64
164 return jau::bit_cast<T>( __builtin_bswap64(jau::bit_cast<uint64_t>(source)) );
165 #else
166 using namespace jau::int_literals;
167 const uint64_t usource = jau::bit_cast<uint64_t>(source);
168 return jau::bit_cast<T>( ( ( usource & 0xff00000000000000_u64 ) >> 56 ) |
169 ( ( usource & 0x00ff000000000000_u64 ) >> 40 ) |
170 ( ( usource & 0x0000ff0000000000_u64 ) >> 24 ) |
171 ( ( usource & 0x000000ff00000000_u64 ) >> 8 ) |
172 ( ( usource & 0x00000000ff000000_u64 ) << 8 ) |
173 ( ( usource & 0x0000000000ff0000_u64 ) << 24 ) |
174 ( ( usource & 0x000000000000ff00_u64 ) << 40 ) |
175 ( ( usource & 0x00000000000000ff_u64 ) << 56 ) );
176 #endif
177 }
178
179 constexpr void bswap(uint8_t * sink, uint8_t const * source, nsize_t len) {
180 source += len - 1;
181 for (; len > 0; len--) {
182 *sink++ = *source--;
183 }
184 }
185
186 constexpr uint128dp_t bswap(uint128dp_t const & source) noexcept {
187 uint128dp_t dest;
188 bswap(dest.data, source.data, 16);
189 return dest;
190 }
191
192 constexpr uint192dp_t bswap(uint192dp_t const & source) noexcept {
193 uint192dp_t dest;
194 bswap(dest.data, source.data, 24);
195 return dest;
196 }
197
198 constexpr uint256dp_t bswap(uint256dp_t const & source) noexcept {
199 uint256dp_t dest;
200 bswap(dest.data, source.data, 32);
201 return dest;
202 }
203
204 inline char* cast_uint8_ptr_to_char(uint8_t* b) noexcept {
205 return reinterpret_cast<char*>(b);
206 }
207 inline const char* cast_uint8_ptr_to_char(const uint8_t* b) noexcept {
208 return reinterpret_cast<const char*>(b);
209 }
210
211 inline const uint8_t* cast_char_ptr_to_uint8(const char* s) noexcept {
212 return reinterpret_cast<const uint8_t*>(s);
213 }
214
215 /**
216 // *************************************************
217 // *************************************************
218 // *************************************************
219 */
220
223
224 namespace impl {
225 constexpr uint32_t get_host_order() noexcept {
226 if constexpr ( jau::has_builtin_bit_cast() ) {
227 constexpr uint8_t b[4] { 0x44, 0x43, 0x42, 0x41 }; // h->l: 41 42 43 44 = 'ABCD' hex ASCII code
229 } else {
230 // The pragma to stop multichar warning == error `-Werror=multichar` doesn't seem to work with GCC <= 10.2
231 // Hence we have to disable this specific warning via: `-Wno-multichar`
232 // until all our compiler support `__builtin_bit_cast(T, a)`
233 return 'ABCD'; // h->l: 41 42 43 44 = 'ABCD' hex ASCII code
234 }
235 }
236 }
237
238 /**
239 * Endian identifier, indicating endianess of all scalar types.
240 *
241 * Inspired by C++20 std::endian
242 *
243 * Corner case platforms currently not supported,
244 * i.e. unified endianess and mixed endianess.
245 *
246 * All endian API entries are of `constexpr` and hence evaluated at compile time.<br>
247 * Therefore, if-branches and expressions are also of `constexpr` and optimized 'away' at compile time.<br>
248 * This includes the `cpu_to_<endian>(..)` and `<endian>_to_cpu(..)` etc utility functions.
249 *
250 * On i386 platforms the host byte order is Least Significant Byte first (LSB) or Little-Endian,
251 * whereas the network byte order, as used on the Internet, is Most Significant Byte first (MSB) or Big-Endian.
252 * See #include <arpa/inet.h>
253 *
254 * Bluetooth is LSB or Little-Endian!
255 *
256 * See \ref lb_endian
257 */
258 enum class endian_t : uint32_t
259 {
260 /** Identifier for little endian. */
261 little = 0x41424344U, // h->l: 41 42 43 44 = 'ABCD' hex ASCII code
262
263 /** Identifier for big endian. */
264 big = 0x44434241U, // h->l: 44 43 42 41 = 'DCBA' hex ASCII code
265
266 /** Identifier for DEC PDP-11, aka `ENDIAN_LITTLE_WORD`. */
267 pdp = 0x43444142U, // h->l: 43 44 41 42 = 'CDAB' hex ASCII code
268
269 /** Identifier for Honeywell 316, aka `ENDIAN_BIG_WORD`. */
270 honeywell = 0x42414443U, // h->l: 42 41 44 43 = 'BADC' hex ASCII code
271
272 /** Undetermined endian */
273 undefined = 0x00000000U,
274
275 /** Identifier for native platform type, one of the above. */
276 native = impl::get_host_order()
277 };
278
280
281 /** Simplified reduced \ref endian type only covering little- and big-endian. See \ref endian for details. */
282 enum class lb_endian_t : uint32_t
283 {
284 /** Identifier for little endian, equivalent to endian::little. */
285 little = static_cast<uint32_t>( endian_t::little ),
286
287 /** Identifier for big endian, equivalent to endian::big. */
288 big = static_cast<uint32_t>( endian_t::big ),
289
290 /** Identifier for native platform type, one of the above. */
291 native = static_cast<uint32_t>( endian_t::native )
292 };
293
294 /**
295 * Return std::string representation of the given \ref endian.
296 * @param v the \ref endian value
297 * @return the std::string representation
298 */
299 std::string_view to_string(const endian_t v) noexcept;
300
301 /**
302 * Return std::string representation of the given \ref lb_endian.
303 * @param v the \ref lb_endian value
304 * @return the std::string representation
305 */
306 std::string_view to_string(const lb_endian_t v) noexcept;
307
308 constexpr lb_endian_t to_lb_endian(const endian_t v) noexcept {
309 switch(v) {
311 case endian_t::big: return lb_endian_t::big;
312 default: {
313 abort(); // never reached
314 }
315 }
316 }
317 constexpr endian_t to_endian(const lb_endian_t v) noexcept {
318 switch(v) {
320 case lb_endian_t::big: return endian_t::big;
321 default: {
322 abort(); // never reached
323 }
324 }
325 }
326
327 /**
328 * Evaluates `true` if the given \ref endian is defined,
329 * i.e. `little`, `big`, `pdp` or `honeywell`.
330 */
331 constexpr bool is_defined_endian(const endian_t &v) noexcept {
332 switch(v) {
333 case endian_t::little:
334 [[fallthrough]];
335 case endian_t::big:
336 [[fallthrough]];
337 case endian_t::pdp:
338 [[fallthrough]];
340 return true;
341 default:
342 return false;
343 }
344 }
345
346 /**
347 * Returns `true` if given `byte_order` equals endian::little, otherwise false.
348 */
349 constexpr bool is_little_endian(const endian_t byte_order) noexcept {
350 return endian_t::little == byte_order;
351 }
352
353 /**
354 * Returns `true` if given `byte_order` equals lb_endian::little, otherwise false.
355 */
356 constexpr bool is_little_endian(const lb_endian_t byte_order) noexcept {
357 return lb_endian_t::little == byte_order;
358 }
359
360 /**
361 * Evaluates `true` if platform is running in little \ref endian mode,
362 * i.e. `jau::endian::little == jau::endian::native`.
363 */
364 constexpr bool is_little_endian() noexcept {
366 }
367
368 /**
369 * Evaluates `true` if platform is running in big \ref endian mode,
370 * i.e. `jau::endian::big == jau::endian::native`.
371 */
372 constexpr bool is_big_endian() noexcept {
374 }
375
376 /**
377 * Evaluates `true` if platform is running in little or big \ref endian mode,
378 * i.e. `jau::endian::little == jau::endian::native || jau::endian::big == jau::endian::native`.
379 */
383
384 /**
385 * A little-endian type trait for convenience ..
386 * <p>
387 * Since all \ref endian definitions are of `constexpr`, code can simply use expressions of these
388 * for compile-time evaluation and optimization. A template `SFINAE` is not required.
389 * </p>
390 * @tparam Dummy_type just to make template `SFINAE` happy
391 */
392 template <typename Dummy_type> struct has_endian_little : std::integral_constant<bool, endian_t::little == endian_t::native> {};
393
394 /**
395 * Value access of little-endian type trait for convenience ..
396 * <p>
397 * Since all \ref endian definitions are of `constexpr`, code can simply use expressions of these
398 * for compile-time evaluation and optimization. A template `SFINAE` is not required.
399 * </p>
400 * @tparam Dummy_type just to make template `SFINAE` happy
401 */
402 template <typename Dummy_type> constexpr bool has_endian_little_v = has_endian_little<Dummy_type>::value;
403
404 /**
405 * A big-endian type trait for convenience ..
406 * <p>
407 * Since all \ref endian definitions are of `constexpr`, code can simply use expressions of these
408 * for compile-time evaluation and optimization. A template `SFINAE` is not required.
409 * </p>
410 * @tparam Dummy_type just to make template `SFINAE` happy
411 */
412 template <typename Dummy_type> struct has_endian_big : std::integral_constant<bool, endian_t::big == endian_t::native> {};
413
414 /**
415 * Value access of big-endian type trait for convenience ..
416 * <p>
417 * Since all \ref endian definitions are of `constexpr`, code can simply use expressions of these
418 * for compile-time evaluation and optimization. A template `SFINAE` is not required.
419 * </p>
420 * @tparam Dummy_type just to make template `SFINAE` happy
421 */
422 template <typename Dummy_type> constexpr bool has_endian_big_v = has_endian_big<Dummy_type>::value;
423
424 /**
425 // *************************************************
426 // *************************************************
427 // *************************************************
428 */
429
430 // one static_assert is sufficient for whole compilation unit
431 static_assert( is_defined_endian(endian_t::native) );
432 static_assert( is_little_or_big_endian() );
433
434 template <jau::req::unsigned_integral T>
435 constexpr T be_to_cpu(T const n) noexcept {
436 if constexpr ( is_little_endian() ) {
437 return bswap(n);
438 } else if constexpr ( is_big_endian() ) {
439 return n;
440 } else {
441 return 0; // unreachable -> static_assert(..) above
442 }
443 }
444 template <jau::req::unsigned_integral T>
445 constexpr T cpu_to_be(T const h) noexcept {
446 if constexpr ( is_little_endian() ) {
447 return bswap(h);
448 } else if constexpr ( is_big_endian() ) {
449 return h;
450 } else {
451 return 0; // unreachable -> static_assert(..) above
452 }
453 }
454 template <jau::req::unsigned_integral T>
455 constexpr T le_to_cpu(T const l) noexcept {
456 if constexpr ( is_little_endian() ) {
457 return l;
458 } else if constexpr ( is_big_endian() ) {
459 return bswap(l);
460 } else {
461 return 0; // unreachable -> static_assert(..) above
462 }
463 }
464 template <jau::req::unsigned_integral T>
465 constexpr T cpu_to_le(T const h) noexcept {
466 if constexpr ( is_little_endian() ) {
467 return h;
468 } else if constexpr ( is_big_endian() ) {
469 return bswap(h);
470 } else {
471 return 0; // unreachable -> static_assert(..) above
472 }
473 }
474
475 template <jau::req::signed_integral T>
476 constexpr T be_to_cpu(T const n) noexcept {
477 if constexpr ( is_little_endian() ) {
478 return bswap(n);
479 } else if constexpr ( is_big_endian() ) {
480 return n;
481 } else {
482 return 0; // unreachable -> static_assert(..) above
483 }
484 }
485 template <jau::req::signed_integral T>
486 constexpr T cpu_to_be(T const h) noexcept {
487 if constexpr ( is_little_endian() ) {
488 return bswap(h);
489 } else if constexpr ( is_big_endian() ) {
490 return h;
491 } else {
492 return 0; // unreachable -> static_assert(..) above
493 }
494 }
495 template <jau::req::signed_integral T>
496 constexpr T le_to_cpu(T const l) noexcept {
497 if constexpr ( is_little_endian() ) {
498 return l;
499 } else if constexpr ( is_big_endian() ) {
500 return bswap(l);
501 } else {
502 return 0; // unreachable -> static_assert(..) above
503 }
504 }
505 template <jau::req::signed_integral T>
506 constexpr T cpu_to_le(T const h) noexcept {
507 if constexpr ( is_little_endian() ) {
508 return h;
509 } else if constexpr ( is_big_endian() ) {
510 return bswap(h);
511 } else {
512 return 0; // unreachable -> static_assert(..) above
513 }
514 }
515
516
517 constexpr uint128dp_t be_to_cpu(uint128dp_t const & n) noexcept {
518 if constexpr ( is_little_endian() ) {
519 return bswap(n);
520 } else if constexpr ( is_big_endian() ) {
521 return n;
522 } else {
523 return {}; // unreachable -> static_assert(..) above
524 }
525 }
526 constexpr uint128dp_t cpu_to_be(uint128dp_t const & h) noexcept {
527 if constexpr ( is_little_endian() ) {
528 return bswap(h);
529 } else if constexpr ( is_big_endian() ) {
530 return h;
531 } else {
532 return {}; // unreachable -> static_assert(..) above
533 }
534 }
535 constexpr uint128dp_t le_to_cpu(uint128dp_t const & l) noexcept {
536 if constexpr ( is_little_endian() ) {
537 return l;
538 } else if constexpr ( is_big_endian() ) {
539 return bswap(l);
540 } else {
541 return {}; // unreachable -> static_assert(..) above
542 }
543 }
544 constexpr uint128dp_t cpu_to_le(uint128dp_t const & h) noexcept {
545 if constexpr ( is_little_endian() ) {
546 return h;
547 } else if constexpr ( is_big_endian() ) {
548 return bswap(h);
549 } else {
550 return {}; // unreachable -> static_assert(..) above
551 }
552 }
553
554 constexpr uint192dp_t be_to_cpu(uint192dp_t const & n) noexcept {
555 if constexpr ( is_little_endian() ) {
556 return bswap(n);
557 } else if constexpr ( is_big_endian() ) {
558 return n;
559 } else {
560 return {}; // unreachable -> static_assert(..) above
561 }
562 }
563 constexpr uint192dp_t cpu_to_be(uint192dp_t const & h) noexcept {
564 if constexpr ( is_little_endian() ) {
565 return bswap(h);
566 } else if constexpr ( is_big_endian() ) {
567 return h;
568 } else {
569 return {}; // unreachable -> static_assert(..) above
570 }
571 }
572 constexpr uint192dp_t le_to_cpu(uint192dp_t const & l) noexcept {
573 if constexpr ( is_little_endian() ) {
574 return l;
575 } else if constexpr ( is_big_endian() ) {
576 return bswap(l);
577 } else {
578 return {}; // unreachable -> static_assert(..) above
579 }
580 }
581 constexpr uint192dp_t cpu_to_le(uint192dp_t const & h) noexcept {
582 if constexpr ( is_little_endian() ) {
583 return h;
584 } else if constexpr ( is_big_endian() ) {
585 return bswap(h);
586 } else {
587 return {}; // unreachable -> static_assert(..) above
588 }
589 }
590
591 constexpr uint256dp_t be_to_cpu(uint256dp_t const & n) noexcept {
592 if constexpr ( is_little_endian() ) {
593 return bswap(n);
594 } else if constexpr ( is_big_endian() ) {
595 return n;
596 } else {
597 return {}; // unreachable -> static_assert(..) above
598 }
599 }
600 constexpr uint256dp_t cpu_to_be(uint256dp_t const & h) noexcept {
601 if constexpr ( is_little_endian() ) {
602 return bswap(h);
603 } else if constexpr ( is_big_endian() ) {
604 return h;
605 } else {
606 return {}; // unreachable -> static_assert(..) above
607 }
608 }
609 constexpr uint256dp_t le_to_cpu(uint256dp_t const & l) noexcept {
610 if constexpr ( is_little_endian() ) {
611 return l;
612 } else if constexpr ( is_big_endian() ) {
613 return bswap(l);
614 } else {
615 return {}; // unreachable -> static_assert(..) above
616 }
617 }
618 constexpr uint256dp_t cpu_to_le(uint256dp_t const & h) noexcept {
619 if constexpr ( is_little_endian() ) {
620 return h;
621 } else if constexpr ( is_big_endian() ) {
622 return bswap(h);
623 } else {
624 return {}; // unreachable -> static_assert(..) above
625 }
626
627 }
628
629 /**
630 // *************************************************
631 // *************************************************
632 // *************************************************
633 */
634
635 namespace impl {
636 /** @see https://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable */
637 static constexpr std::array<uint8_t, 256> BitRevTable256 =
638 []() constexpr -> std::array<uint8_t, 256> {
639 using namespace jau::int_literals;
640 std::array<uint8_t, 256> result{};
641 for (size_t i = 0; i < 256; ++i) {
642 // result[i] = (i * 0x0202020202_u64 & 0x010884422010_u64) % 1023;
643 result[i] = ( (i * 0x80200802_u64) & 0x0884422110_u64 ) * 0x0101010101_u64 >> 32;
644 }
645 return result;
646 }();
647 }
648
649 /**
650 * Reverse bits of one byte
651 * @see https://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
652 */
653 constexpr uint8_t rev_bits(uint8_t v) noexcept { return impl::BitRevTable256[v]; };
654 /**
655 * Reverse bits of two bytes
656 * @see https://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
657 */
658 constexpr uint16_t rev_bits(uint16_t v) noexcept {
659 return ( uint16_t( impl::BitRevTable256[ v & 0xff] ) << 8) |
660 ( uint16_t( impl::BitRevTable256[(v >> 8) & 0xff] ) );
661 };
662 /**
663 * Reverse bits of four bytes
664 * @see https://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
665 */
666 constexpr uint32_t rev_bits(uint32_t v) noexcept {
667 return ( uint32_t( impl::BitRevTable256[ v & 0xff] ) << 24) |
668 ( uint32_t( impl::BitRevTable256[(v >> 8) & 0xff] ) << 16) |
669 ( uint32_t( impl::BitRevTable256[(v >> 16) & 0xff] ) << 8) |
670 ( uint32_t( impl::BitRevTable256[(v >> 24) & 0xff] ) );
671 };
672 /**
673 * Reverse bits of eight bytes
674 * @see https://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
675 */
676 constexpr uint64_t rev_bits(uint64_t v) noexcept {
677 return ( uint64_t( impl::BitRevTable256[ v & 0xff] ) << 56) |
678 ( uint64_t( impl::BitRevTable256[(v >> 8) & 0xff] ) << 48) |
679 ( uint64_t( impl::BitRevTable256[(v >> 16) & 0xff] ) << 40) |
680 ( uint64_t( impl::BitRevTable256[(v >> 24) & 0xff] ) << 32) |
681 ( uint64_t( impl::BitRevTable256[(v >> 32) & 0xff] ) << 24) |
682 ( uint64_t( impl::BitRevTable256[(v >> 40) & 0xff] ) << 16) |
683 ( uint64_t( impl::BitRevTable256[(v >> 48) & 0xff] ) << 8) |
684 ( uint64_t( impl::BitRevTable256[(v >> 56) & 0xff] ) );
685 };
686
687 /** Returns the T bit mask of n-bits, i.e. n low order 1’s */
688 template<jau::req::unsigned_integral T>
689 static constexpr T bit_mask(size_t n) noexcept {
690 if ( n >= sizeof(T) * CHAR_BIT ) {
691 return std::numeric_limits<T>::max();
692 } else {
693 return (T(1) << n) - T(1);
694 }
695 }
696
697 /**
698 * Reversed `n` bits of value `v`, this is an O(n) operation.
699 *
700 * The reversed bits will stick in their `n` bits position,
701 * i.e. not shifted to the left of `n` bits as `rev_bits(v)` would.
702 * @see https://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
703 */
704 template<jau::req::unsigned_integral T>
705 constexpr T rev_bits(jau::nsize_t n, T v) {
706 if ( n >= sizeof(T) * CHAR_BIT ) {
707 return rev_bits(v); // reverse all bits
708 }
709 v &= (T(1) << n) - T(1); // mask-out undesired bits
710 T r = v & 1; // r will be reversed bits of v; first get LSB of v
711 jau::nsize_t s = std::min<jau::nsize_t>(n-1, jau::nsize_t( sizeof(T) ) * CHAR_BIT - 1); // extra shift needed at end
712 for (v >>= 1; v; v >>= 1) {
713 r <<= 1;
714 r |= v & 1;
715 --s;
716 }
717 return r << s; // shift when v's highest bits are zero
718 }
719
720 /**
721 // *************************************************
722 // *************************************************
723 // *************************************************
724 */
725
726 constexpr void put_uint8(uint8_t * buffer, const uint8_t v) noexcept
727 {
728 *pointer_cast<uint8_t *>( buffer ) = v;
729 }
730 constexpr uint8_t get_uint8(uint8_t const * buffer) noexcept
731 {
732 return *pointer_cast<uint8_t const *>( buffer );
733 }
734 constexpr int8_t get_int8(uint8_t const * buffer) noexcept
735 {
736 return *pointer_cast<int8_t const *>( buffer );
737 }
738
739 /**
740 * Return packed_t::store after converting it to from either lb_endian::little or lb_endian::big depending on given `byte_order`
741 * to lb_endian::native.
742 * @tparam T
743 * @param source
744 * @param byte_order
745 */
746 template<typename T>
747 constexpr T get_packed_value(const packed_t<T>* source, const lb_endian_t byte_order) noexcept {
748 return is_little_endian(byte_order) ? le_to_cpu(source->store) : be_to_cpu(source->store);
749 }
750
751 /**
752 * Put the given uint16_t value into the given byte address
753 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
754 *
755 * @see \ref packed_t_alignment_cast
756 */
757 constexpr void put_uint16(uint8_t * buffer, const uint16_t v) noexcept
758 {
759 pointer_cast<packed_t<uint16_t>*>( buffer )->store = v;
760 }
761 /**
762 * Put the given uint16_t value into the given byte address
763 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
764 *
765 * The value is converted from lb_endian::native to either lb_endian::little or lb_endian::big depending on given `byte_order`
766 * before it is stored in memory.
767 *
768 * @see \ref packed_t_alignment_cast
769 */
770 constexpr void put_uint16(uint8_t * buffer, const uint16_t v, const lb_endian_t byte_order) noexcept
771 {
772 pointer_cast<packed_t<uint16_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
773 }
774 /**
775 * Returns a uint16_t value from the given byte address
776 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
777 *
778 * @see \ref packed_t_alignment_cast
779 */
780 constexpr uint16_t get_uint16(uint8_t const * buffer) noexcept
781 {
782 return pointer_cast<const packed_t<uint16_t>*>( buffer )->store;
783 }
784 /**
785 * Returns a uint16_t value from the given byte address
786 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
787 *
788 * The value is converted from either lb_endian::little or lb_endian::big depending on given `byte_order`
789 * to lb_endian::native before it is returned to the caller.
790 *
791 * @see \ref packed_t_alignment_cast
792 */
793 constexpr uint16_t get_uint16(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
794 {
795 return get_packed_value(pointer_cast<const packed_t<uint16_t>*>( buffer ), byte_order);
796 }
797
798 /**
799 * Put the given int16_t value into the given byte address
800 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
801 *
802 * @see \ref packed_t_alignment_cast
803 */
804 constexpr void put_int16(uint8_t * buffer, const int16_t v) noexcept
805 {
806 pointer_cast<packed_t<int16_t>*>( buffer )->store = v;
807 }
808 /**
809 * Put the given uint16_t value into the given byte address
810 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
811 *
812 * The value is converted from lb_endian::native to either lb_endian::little or lb_endian::big depending on given `byte_order`
813 * before it is stored in memory.
814 *
815 * @see \ref packed_t_alignment_cast
816 */
817 constexpr void put_int16(uint8_t * buffer, const int16_t v, const lb_endian_t byte_order) noexcept
818 {
819 pointer_cast<packed_t<int16_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
820 }
821 /**
822 * Returns a int16_t value from the given byte address
823 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
824 *
825 * @see \ref packed_t_alignment_cast
826 */
827 constexpr int16_t get_int16(uint8_t const * buffer) noexcept
828 {
829 return pointer_cast<const packed_t<int16_t>*>( buffer )->store;
830 }
831 /**
832 * Returns a int16_t value from the given byte address
833 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
834 *
835 * The value is converted from either lb_endian::little or lb_endian::big depending on given `byte_order`
836 * to lb_endian::native before it is returned to the caller.
837 *
838 * @see \ref packed_t_alignment_cast
839 */
840 constexpr int16_t get_int16(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
841 {
842 return get_packed_value(pointer_cast<const packed_t<int16_t>*>( buffer ), byte_order);
843 }
844
845 /**
846 * See put_uint16() for reference.
847 * @see \ref packed_t_alignment_cast
848 */
849 constexpr void put_uint32(uint8_t * buffer, const uint32_t v) noexcept
850 {
851 pointer_cast<packed_t<uint32_t>*>( buffer )->store = v;
852 }
853 /**
854 * See put_uint16() for reference.
855 * @see \ref packed_t_alignment_cast
856 */
857 constexpr void put_uint32(uint8_t * buffer, const uint32_t v, const lb_endian_t byte_order) noexcept
858 {
859 pointer_cast<packed_t<uint32_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
860 }
861 /**
862 * See get_uint16() for reference.
863 * @see \ref packed_t_alignment_cast
864 */
865 constexpr uint32_t get_uint32(uint8_t const * buffer) noexcept
866 {
867 return pointer_cast<const packed_t<uint32_t>*>( buffer )->store;
868 }
869 /**
870 * See get_uint16() for reference.
871 * @see \ref packed_t_alignment_cast
872 */
873 constexpr uint32_t get_uint32(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
874 {
875 return get_packed_value(pointer_cast<const packed_t<uint32_t>*>( buffer ), byte_order);
876 }
877
878 /**
879 * See put_int16() for reference.
880 * @see \ref packed_t_alignment_cast
881 */
882 constexpr void put_int32(uint8_t * buffer, const int32_t v) noexcept
883 {
884 pointer_cast<packed_t<int32_t>*>( buffer )->store = v;
885 }
886 /**
887 * See put_int16() for reference.
888 * @see \ref packed_t_alignment_cast
889 */
890 constexpr void put_int32(uint8_t * buffer, const int32_t v, const lb_endian_t byte_order) noexcept
891 {
892 pointer_cast<packed_t<int32_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
893 }
894 /**
895 * See get_int16() for reference.
896 * @see \ref packed_t_alignment_cast
897 */
898 constexpr int32_t get_int32(uint8_t const * buffer) noexcept
899 {
900 return pointer_cast<const packed_t<int32_t>*>( buffer )->store;
901 }
902 /**
903 * See get_int16() for reference.
904 * @see \ref packed_t_alignment_cast
905 */
906 constexpr int32_t get_int32(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
907 {
908 return get_packed_value(pointer_cast<const packed_t<int32_t>*>( buffer ), byte_order);
909 }
910
911 /**
912 * See put_uint16() for reference.
913 * @see \ref packed_t_alignment_cast
914 */
915 constexpr void put_uint64(uint8_t * buffer, const uint64_t & v) noexcept
916 {
917 pointer_cast<packed_t<uint64_t>*>( buffer )->store = v;
918 }
919 /**
920 * See put_uint16() for reference.
921 * @see \ref packed_t_alignment_cast
922 */
923 constexpr void put_uint64(uint8_t * buffer, const uint64_t & v, const lb_endian_t byte_order) noexcept
924 {
925 pointer_cast<packed_t<uint64_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
926 }
927 /**
928 * See get_uint16() for reference.
929 * @see \ref packed_t_alignment_cast
930 */
931 constexpr uint64_t get_uint64(uint8_t const * buffer) noexcept
932 {
933 return pointer_cast<const packed_t<uint64_t>*>( buffer )->store;
934 }
935 /**
936 * See get_uint16() for reference.
937 * @see \ref packed_t_alignment_cast
938 */
939 constexpr uint64_t get_uint64(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
940 {
941 return get_packed_value(pointer_cast<const packed_t<uint64_t>*>( buffer ), byte_order);
942 }
943
944 /**
945 * See put_int16() for reference.
946 * @see \ref packed_t_alignment_cast
947 */
948 constexpr void put_int64(uint8_t * buffer, const int64_t & v) noexcept
949 {
950 pointer_cast<packed_t<int64_t>*>( buffer )->store = v;
951 }
952 /**
953 * See put_int16() for reference.
954 * @see \ref packed_t_alignment_cast
955 */
956 constexpr void put_int64(uint8_t * buffer, const int64_t & v, const lb_endian_t byte_order) noexcept
957 {
958 pointer_cast<packed_t<int64_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
959 }
960 /**
961 * See get_int16() for reference.
962 * @see \ref packed_t_alignment_cast
963 */
964 constexpr int64_t get_int64(uint8_t const * buffer) noexcept
965 {
966 return pointer_cast<const packed_t<int64_t>*>( buffer )->store;
967 }
968 /**
969 * See get_int16() for reference.
970 * @see \ref packed_t_alignment_cast
971 */
972 constexpr int64_t get_int64(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
973 {
974 return get_packed_value(pointer_cast<const packed_t<int64_t>*>( buffer ), byte_order);
975 }
976
977 /**
978 * See put_uint16() for reference.
979 * @see \ref packed_t_alignment_cast
980 */
981 constexpr void put_uint128(uint8_t * buffer, const uint128dp_t & v) noexcept
982 {
983 pointer_cast<packed_t<uint128dp_t>*>( buffer )->store = v;
984 }
985 /**
986 * See put_uint16() for reference.
987 * @see \ref packed_t_alignment_cast
988 */
989 constexpr void put_uint128(uint8_t * buffer, const uint128dp_t & v, const lb_endian_t byte_order) noexcept
990 {
991 pointer_cast<packed_t<uint128dp_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
992 }
993 /**
994 * See get_uint16() for reference.
995 * @see \ref packed_t_alignment_cast
996 */
997 constexpr uint128dp_t get_uint128(uint8_t const * buffer) noexcept
998 {
999 return pointer_cast<const packed_t<uint128dp_t>*>( buffer )->store;
1000 }
1001 /**
1002 * See get_uint16() for reference.
1003 * @see \ref packed_t_alignment_cast
1004 */
1005 constexpr uint128dp_t get_uint128(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
1006 {
1007 return get_packed_value(pointer_cast<const packed_t<uint128dp_t>*>( buffer ), byte_order);
1008 }
1009
1010 /**
1011 * See put_uint16() for reference.
1012 * @see \ref packed_t_alignment_cast
1013 */
1014 constexpr void put_uint192(uint8_t * buffer, const uint192dp_t & v) noexcept
1015 {
1016 pointer_cast<packed_t<uint192dp_t>*>( buffer )->store = v;
1017 }
1018 /**
1019 * See put_uint16() for reference.
1020 * @see \ref packed_t_alignment_cast
1021 */
1022 constexpr void put_uint192(uint8_t * buffer, const uint192dp_t & v, const lb_endian_t byte_order) noexcept
1023 {
1024 pointer_cast<packed_t<uint192dp_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
1025 }
1026 /**
1027 * See get_uint16() for reference.
1028 * @see \ref packed_t_alignment_cast
1029 */
1030 constexpr uint192dp_t get_uint192(uint8_t const * buffer) noexcept
1031 {
1032 return pointer_cast<const packed_t<uint192dp_t>*>( buffer )->store;
1033 }
1034 /**
1035 * See get_uint16() for reference.
1036 * @see \ref packed_t_alignment_cast
1037 */
1038 constexpr uint192dp_t get_uint192(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
1039 {
1040 return get_packed_value(pointer_cast<const packed_t<uint192dp_t>*>( buffer ), byte_order);
1041 }
1042
1043 /**
1044 * See put_uint16() for reference.
1045 * @see \ref packed_t_alignment_cast
1046 */
1047 constexpr void put_uint256(uint8_t * buffer, const uint256dp_t & v) noexcept
1048 {
1049 pointer_cast<packed_t<uint256dp_t>*>( buffer )->store = v;
1050 }
1051 /**
1052 * See put_uint16() for reference.
1053 * @see \ref packed_t_alignment_cast
1054 */
1055 constexpr void put_uint256(uint8_t * buffer, const uint256dp_t & v, const lb_endian_t byte_order) noexcept
1056 {
1057 pointer_cast<packed_t<uint256dp_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
1058 }
1059 /**
1060 * See get_uint16() for reference.
1061 * @see \ref packed_t_alignment_cast
1062 */
1063 constexpr uint256dp_t get_uint256(uint8_t const * buffer) noexcept
1064 {
1065 return pointer_cast<const packed_t<uint256dp_t>*>( buffer )->store;
1066 }
1067 /**
1068 * See get_uint16() for reference.
1069 * @see \ref packed_t_alignment_cast
1070 */
1071 constexpr uint256dp_t get_uint256(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
1072 {
1073 return get_packed_value(pointer_cast<const packed_t<uint256dp_t>*>( buffer ), byte_order);
1074 }
1075
1076 /**
1077 // *************************************************
1078 // *************************************************
1079 // *************************************************
1080 */
1081
1082 /**
1083 * Put the given T value into the given byte address
1084 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
1085 *
1086 * @tparam T
1087 * @param buffer
1088 * @param v
1089 * @see \ref packed_t_alignment_cast
1090 */
1091 template<typename T>
1092 constexpr
1093 typename std::enable_if_t<
1094 std::is_standard_layout_v<T>,
1095 void>
1096 put_value(uint8_t * buffer, const T& v) noexcept
1097 {
1098 // reinterpret_cast<packed_t<T>*>( buffer )->store = v;
1099 pointer_cast<packed_t<T>*>( buffer )->store = v;
1100 }
1101
1102 /**
1103 * Put the given T value into the given byte address
1104 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
1105 *
1106 * The value is converted from lb_endian::native to either lb_endian::little or lb_endian::big depending on given `byte_order`
1107 * before it is stored in memory.
1108 *
1109 * @tparam T
1110 * @param buffer
1111 * @param v
1112 * @param byte_order
1113 * @see \ref packed_t_alignment_cast
1114 */
1115 template<typename T>
1116 constexpr
1117 typename std::enable_if_t<
1118 std::is_standard_layout_v<T>,
1119 void>
1120 put_value(uint8_t * buffer, const T& v, const lb_endian_t byte_order) noexcept
1121 {
1122 pointer_cast<packed_t<T>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
1123 }
1124
1125 /**
1126 * Returns a T value from the given byte address
1127 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
1128 *
1129 * @tparam T
1130 * @param buffer
1131 * @return
1132 * @see \ref packed_t_alignment_cast
1133 */
1134 template<typename T>
1135 constexpr
1136 typename std::enable_if_t<
1137 std::is_standard_layout_v<T>,
1138 T>
1139 get_value(uint8_t const * buffer) noexcept
1140 {
1141 return pointer_cast<const packed_t<T>*>( buffer )->store;
1142 }
1143
1144 /**
1145 * Returns a T value from the given byte address
1146 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
1147 *
1148 * The value is converted from either lb_endian::little or lb_endian::big depending on given `byte_order`
1149 * to lb_endian::native before it is returned to the caller.
1150 *
1151 * @tparam T
1152 * @param buffer
1153 * @param byte_order
1154 * @return
1155 * @see \ref packed_t_alignment_cast
1156 */
1157 template<typename T>
1158 constexpr
1159 typename std::enable_if_t<
1160 std::is_standard_layout_v<T>,
1161 T>
1162 get_value(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
1163 {
1164 return get_packed_value(pointer_cast<const packed_t<T>*>( buffer ), byte_order);
1165 }
1166
1167 /**
1168 // *************************************************
1169 // *************************************************
1170 // *************************************************
1171 */
1172
1173 /** Bit order type, i.e. least-significant-bit (lsb) or most-significant-bit (msb) first. */
1174 enum class bit_order_t : bool
1175 {
1176 /** Identifier for least-significant-bit (lsb) first. */
1177 lsb = false,
1178
1179 /** Identifier for most-significant-bit (msb) first. */
1180 msb = true
1181 };
1182
1183 /**
1184 * Return std::string representation of the given bit_order_t.
1185 * @param v the bit_order_t value
1186 * @return the std::string representation
1187 */
1188 inline std::string to_string(const bit_order_t v) noexcept {
1189 return v == bit_order_t::lsb ? "lsb" : "msb";
1190 }
1191
1192 /**@}*/
1193
1194} // namespace jau
1195
1196/** \example test_basictypeconv.cpp
1197 * This C++ unit test validates the jau::bswap and get/set value implementation
1198 */
1199
1200#endif /* JAU_BYTE_UTIL_HPP_ */
constexpr uint192dp_t get_uint192(uint8_t const *buffer) noexcept
See get_uint16() for reference.
constexpr T cpu_to_be(T const h) noexcept
constexpr bool has_endian_big_v
Value access of big-endian type trait for convenience .
constexpr uint128dp_t get_uint128(uint8_t const *buffer) noexcept
See get_uint16() for reference.
constexpr int64_t get_int64(uint8_t const *buffer) noexcept
See get_int16() for reference.
constexpr T get_packed_value(const packed_t< T > *source, const lb_endian_t byte_order) noexcept
Return packed_t::store after converting it to from either lb_endian::little or lb_endian::big dependi...
constexpr bool is_little_endian() noexcept
Evaluates true if platform is running in little endian mode, i.e.
constexpr bool is_big_endian() noexcept
Evaluates true if platform is running in big endian mode, i.e.
constexpr std::enable_if_t< std::is_standard_layout_v< T >, T > get_value(uint8_t const *buffer) noexcept
Returns a T value from the given byte address using packed_t to resolve a potential memory alignment ...
constexpr void put_uint256(uint8_t *buffer, const uint256dp_t &v) noexcept
See put_uint16() for reference.
constexpr bool is_defined_endian(const endian_t &v) noexcept
Evaluates true if the given endian is defined, i.e.
static constexpr T bit_mask(size_t n) noexcept
Returns the T bit mask of n-bits, i.e.
bit_order_t
Bit order type, i.e.
constexpr uint16_t get_uint16(uint8_t const *buffer) noexcept
Returns a uint16_t value from the given byte address using packed_t to resolve a potential memory ali...
constexpr bool is_little_or_big_endian() noexcept
Evaluates true if platform is running in little or big endian mode, i.e.
std::string_view to_string(const endian_t v) noexcept
Return std::string representation of the given endian.
constexpr endian_t to_endian(const lb_endian_t v) noexcept
constexpr uint32_t get_uint32(uint8_t const *buffer) noexcept
See get_uint16() for reference.
char * cast_uint8_ptr_to_char(uint8_t *b) noexcept
constexpr T bswap(T const &source) noexcept
Definition byte_util.hpp:90
constexpr void put_uint32(uint8_t *buffer, const uint32_t v) noexcept
See put_uint16() for reference.
constexpr int16_t get_int16(uint8_t const *buffer) noexcept
Returns a int16_t value from the given byte address using packed_t to resolve a potential memory alig...
endian_t
Endian identifier, indicating endianess of all scalar types.
constexpr int32_t get_int32(uint8_t const *buffer) noexcept
See get_int16() for reference.
constexpr uint256dp_t get_uint256(uint8_t const *buffer) noexcept
See get_uint16() for reference.
constexpr void put_uint192(uint8_t *buffer, const uint192dp_t &v) noexcept
See put_uint16() for reference.
constexpr bool has_endian_little_v
Value access of little-endian type trait for convenience .
constexpr void put_int16(uint8_t *buffer, const int16_t v) noexcept
Put the given int16_t value into the given byte address using packed_t to resolve a potential memory ...
constexpr void put_uint8(uint8_t *buffer, const uint8_t v) noexcept
constexpr T le_to_cpu(T const l) noexcept
lb_endian_t
Simplified reduced endian type only covering little- and big-endian.
constexpr void put_uint64(uint8_t *buffer, const uint64_t &v) noexcept
See put_uint16() for reference.
constexpr void put_uint16(uint8_t *buffer, const uint16_t v) noexcept
Put the given uint16_t value into the given byte address using packed_t to resolve a potential memory...
constexpr void put_uint128(uint8_t *buffer, const uint128dp_t &v) noexcept
See put_uint16() for reference.
constexpr std::enable_if_t< std::is_standard_layout_v< T >, void > put_value(uint8_t *buffer, const T &v) noexcept
Put the given T value into the given byte address using packed_t to resolve a potential memory alignm...
constexpr lb_endian_t to_lb_endian(const endian_t v) noexcept
constexpr void put_int64(uint8_t *buffer, const int64_t &v) noexcept
See put_int16() for reference.
constexpr void put_int32(uint8_t *buffer, const int32_t v) noexcept
See put_int16() for reference.
constexpr T be_to_cpu(T const n) noexcept
constexpr uint64_t get_uint64(uint8_t const *buffer) noexcept
See get_uint16() for reference.
constexpr int8_t get_int8(uint8_t const *buffer) noexcept
constexpr uint8_t rev_bits(uint8_t v) noexcept
Reverse bits of one byte.
constexpr uint8_t get_uint8(uint8_t const *buffer) noexcept
constexpr T cpu_to_le(T const h) noexcept
const uint8_t * cast_char_ptr_to_uint8(const char *s) noexcept
@ lsb
Identifier for least-significant-bit (lsb) first.
@ msb
Identifier for most-significant-bit (msb) first.
@ pdp
Identifier for DEC PDP-11, aka ENDIAN_LITTLE_WORD.
@ undefined
Undetermined endian.
@ native
Identifier for native platform type, one of the above.
@ little
Identifier for little endian.
@ honeywell
Identifier for Honeywell 316, aka ENDIAN_BIG_WORD.
@ big
Identifier for big endian.
@ little
Identifier for little endian, equivalent to endian::little.
@ big
Identifier for big endian, equivalent to endian::big.
constexpr std::enable_if_t< sizeof(Dest)==sizeof(Source) &&std::is_trivially_copyable_v< Dest > &&std::is_trivially_copyable_v< Source >, Dest > bit_cast(const Source &src) noexcept
C++20 bit_cast<>(arg) implementation for C++17.
#define PRAGMA_DISABLE_WARNING_PUSH
consteval_cxx20 bool has_builtin_bit_cast() noexcept
Query whether __builtin_bit_cast(Dest_type, arg) is available via __has_builtin(__builtin_bit_cast).
constexpr std::enable_if_t< sizeof(Dest)==sizeof(Source) &&std::is_pointer_v< Source > &&std::is_pointer_v< Dest >, Dest > pointer_cast(const Source &src) noexcept
A constexpr pointer cast implementation for C++17, inspired by C++20 bit_cast<>(arg).
#define PRAGMA_DISABLE_WARNING_MULTICHAR
#define PRAGMA_DISABLE_WARNING_POP
uint_bytes_t< sizeof(unsigned long int)> nsize_t
Natural 'size_t' alternative using uint<XX>_t with xx = sizeof(unsigned long int)*8 as its natural si...
Definition int_types.hpp:89
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition backtrace.hpp:32
A big-endian type trait for convenience .
A little-endian type trait for convenience .
Support aligned memory transfer from and to potentially unaligned memory.
A 128-bit packed uint8_t data array.
uint8_t data[16]
A 196-bit packed uint8_t data array.
uint8_t data[24]
A 256-bit packed uint8_t data array.
uint8_t data[32]