jaulib v1.4.1
Jau Support Library (C++, Java, ..)
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 constexpr uint16_t bswap(uint16_t const source) noexcept {
89 #if defined __has_builtin_bswap16
90 return __builtin_bswap16(source);
91 #else
92 return (uint16_t) ( ( ( (source) >> 8 ) & 0xff ) |
93 ( ( (source) & 0xff) << 8 ) );
94 #endif
95 }
96
97 constexpr int16_t bswap(int16_t const source) noexcept {
98 #if defined __has_builtin_bswap64
99 return jau::bit_cast<int16_t>( __builtin_bswap16(jau::bit_cast<uint16_t>(source)) );
100 #else
101 return (int16_t) ( ( ( (source) >> 8 ) & 0xff ) |
102 ( ( (source) & 0xff) << 8 ) );
103 #endif
104 }
105
106 constexpr uint32_t bswap(uint32_t const source) noexcept {
107 #if defined __has_builtin_bswap32
108 return __builtin_bswap32(source);
109 #else
110 return ( ( source & 0xff000000U ) >> 24 ) |
111 ( ( source & 0x00ff0000U ) >> 8 ) |
112 ( ( source & 0x0000ff00U ) << 8 ) |
113 ( ( source & 0x000000ffU ) << 24 );
114 #endif
115 }
116
117 constexpr int32_t bswap(int32_t const source) noexcept {
118 #if defined __has_builtin_bswap64
119 return jau::bit_cast<int32_t>( __builtin_bswap32(jau::bit_cast<uint32_t>(source)) );
120 #else
121 return jau::bit_cast<int32_t>( ( ( source & 0xff000000U ) >> 24 ) |
122 ( ( source & 0x00ff0000U ) >> 8 ) |
123 ( ( source & 0x0000ff00U ) << 8 ) |
124 ( ( source & 0x000000ffU ) << 24 ) );
125 #endif
126 }
127
128 constexpr uint64_t bswap(uint64_t const & source) noexcept {
129 #if defined __has_builtin_bswap64
130 return __builtin_bswap64(source);
131 #else
132 return ( ( source & 0xff00000000000000ULL ) >> 56 ) |
133 ( ( source & 0x00ff000000000000ULL ) >> 40 ) |
134 ( ( source & 0x0000ff0000000000ULL ) >> 24 ) |
135 ( ( source & 0x000000ff00000000ULL ) >> 8 ) |
136 ( ( source & 0x00000000ff000000ULL ) << 8 ) |
137 ( ( source & 0x0000000000ff0000ULL ) << 24 ) |
138 ( ( source & 0x000000000000ff00ULL ) << 40 ) |
139 ( ( source & 0x00000000000000ffULL ) << 56 );
140 #endif
141 }
142
143 constexpr int64_t bswap(int64_t const & source) noexcept {
144 #if defined __has_builtin_bswap64
145 return jau::bit_cast<int64_t>( __builtin_bswap64(jau::bit_cast<uint64_t>(source)) );
146 #else
147 return jau::bit_cast<int64_t>( ( ( source & 0xff00000000000000ULL ) >> 56 ) |
148 ( ( source & 0x00ff000000000000ULL ) >> 40 ) |
149 ( ( source & 0x0000ff0000000000ULL ) >> 24 ) |
150 ( ( source & 0x000000ff00000000ULL ) >> 8 ) |
151 ( ( source & 0x00000000ff000000ULL ) << 8 ) |
152 ( ( source & 0x0000000000ff0000ULL ) << 24 ) |
153 ( ( source & 0x000000000000ff00ULL ) << 40 ) |
154 ( ( source & 0x00000000000000ffULL ) << 56 ) );
155 #endif
156 }
157
158 constexpr void bswap(uint8_t * sink, uint8_t const * source, nsize_t len) {
159 source += len - 1;
160 for (; len > 0; len--) {
161 *sink++ = *source--;
162 }
163 }
164
165 constexpr uint128dp_t bswap(uint128dp_t const & source) noexcept {
166 uint128dp_t dest;
167 bswap(dest.data, source.data, 16);
168 return dest;
169 }
170
171 constexpr uint192dp_t bswap(uint192dp_t const & source) noexcept {
172 uint192dp_t dest;
173 bswap(dest.data, source.data, 24);
174 return dest;
175 }
176
177 constexpr uint256dp_t bswap(uint256dp_t const & source) noexcept {
178 uint256dp_t dest;
179 bswap(dest.data, source.data, 32);
180 return dest;
181 }
182
183 inline char* cast_uint8_ptr_to_char(uint8_t* b) noexcept {
184 return reinterpret_cast<char*>(b);
185 }
186 inline const char* cast_uint8_ptr_to_char(const uint8_t* b) noexcept {
187 return reinterpret_cast<const char*>(b);
188 }
189
190 inline const uint8_t* cast_char_ptr_to_uint8(const char* s) noexcept {
191 return reinterpret_cast<const uint8_t*>(s);
192 }
193
194 /**
195 // *************************************************
196 // *************************************************
197 // *************************************************
198 */
199
202
203 namespace impl {
204 constexpr uint32_t get_host_order() noexcept {
205 if constexpr ( jau::has_builtin_bit_cast() ) {
206 constexpr uint8_t b[4] { 0x44, 0x43, 0x42, 0x41 }; // h->l: 41 42 43 44 = 'ABCD' hex ASCII code
208 } else {
209 // The pragma to stop multichar warning == error `-Werror=multichar` doesn't seem to work with GCC <= 10.2
210 // Hence we have to disable this specific warning via: `-Wno-multichar`
211 // until all our compiler support `__builtin_bit_cast(T, a)`
212 return 'ABCD'; // h->l: 41 42 43 44 = 'ABCD' hex ASCII code
213 }
214 }
215 }
216
217 /**
218 * Endian identifier, indicating endianess of all scalar types.
219 *
220 * Inspired by C++20 std::endian
221 *
222 * Corner case platforms currently not supported,
223 * i.e. unified endianess and mixed endianess.
224 *
225 * All endian API entries are of `constexpr` and hence evaluated at compile time.<br>
226 * Therefore, if-branches and expressions are also of `constexpr` and optimized 'away' at compile time.<br>
227 * This includes the `cpu_to_<endian>(..)` and `<endian>_to_cpu(..)` etc utility functions.
228 *
229 * On i386 platforms the host byte order is Least Significant Byte first (LSB) or Little-Endian,
230 * whereas the network byte order, as used on the Internet, is Most Significant Byte first (MSB) or Big-Endian.
231 * See #include <arpa/inet.h>
232 *
233 * Bluetooth is LSB or Little-Endian!
234 *
235 * See \ref lb_endian
236 */
237 enum class endian_t : uint32_t
238 {
239 /** Identifier for little endian. */
240 little = 0x41424344U, // h->l: 41 42 43 44 = 'ABCD' hex ASCII code
241
242 /** Identifier for big endian. */
243 big = 0x44434241U, // h->l: 44 43 42 41 = 'DCBA' hex ASCII code
244
245 /** Identifier for DEC PDP-11, aka `ENDIAN_LITTLE_WORD`. */
246 pdp = 0x43444142U, // h->l: 43 44 41 42 = 'CDAB' hex ASCII code
247
248 /** Identifier for Honeywell 316, aka `ENDIAN_BIG_WORD`. */
249 honeywell = 0x42414443U, // h->l: 42 41 44 43 = 'BADC' hex ASCII code
250
251 /** Undetermined endian */
252 undefined = 0x00000000U,
253
254 /** Identifier for native platform type, one of the above. */
256 };
257
259
260 /** Simplified reduced \ref endian type only covering little- and big-endian. See \ref endian for details. */
261 enum class lb_endian_t : uint32_t
262 {
263 /** Identifier for little endian, equivalent to endian::little. */
264 little = static_cast<uint32_t>( endian_t::little ),
265
266 /** Identifier for big endian, equivalent to endian::big. */
267 big = static_cast<uint32_t>( endian_t::big ),
268
269 /** Identifier for native platform type, one of the above. */
270 native = static_cast<uint32_t>( endian_t::native )
271 };
272
273 /**
274 * Return std::string representation of the given \ref endian.
275 * @param v the \ref endian value
276 * @return the std::string representation
277 */
278 std::string to_string(const endian_t v) noexcept;
279
280 /**
281 * Return std::string representation of the given \ref lb_endian.
282 * @param v the \ref lb_endian value
283 * @return the std::string representation
284 */
285 std::string to_string(const lb_endian_t v) noexcept;
286
287 constexpr lb_endian_t to_lb_endian(const endian_t v) noexcept {
288 switch(v) {
290 case endian_t::big: return lb_endian_t::big;
291 default: {
292 abort(); // never reached
293 }
294 }
295 }
296 constexpr endian_t to_endian(const lb_endian_t v) noexcept {
297 switch(v) {
299 case lb_endian_t::big: return endian_t::big;
300 default: {
301 abort(); // never reached
302 }
303 }
304 }
305
306 /**
307 * Evaluates `true` if the given \ref endian is defined,
308 * i.e. `little`, `big`, `pdp` or `honeywell`.
309 */
310 constexpr bool is_defined_endian(const endian_t &v) noexcept {
311 switch(v) {
312 case endian_t::little:
313 [[fallthrough]];
314 case endian_t::big:
315 [[fallthrough]];
316 case endian_t::pdp:
317 [[fallthrough]];
319 return true;
320 default:
321 return false;
322 }
323 }
324
325 /**
326 * Returns `true` if given `byte_order` equals endian::little, otherwise false.
327 */
328 constexpr bool is_little_endian(const endian_t byte_order) noexcept {
329 return endian_t::little == byte_order;
330 }
331
332 /**
333 * Returns `true` if given `byte_order` equals lb_endian::little, otherwise false.
334 */
335 constexpr bool is_little_endian(const lb_endian_t byte_order) noexcept {
336 return lb_endian_t::little == byte_order;
337 }
338
339 /**
340 * Evaluates `true` if platform is running in little \ref endian mode,
341 * i.e. `jau::endian::little == jau::endian::native`.
342 */
343 constexpr bool is_little_endian() noexcept {
345 }
346
347 /**
348 * Evaluates `true` if platform is running in big \ref endian mode,
349 * i.e. `jau::endian::big == jau::endian::native`.
350 */
351 constexpr bool is_big_endian() noexcept {
353 }
354
355 /**
356 * Evaluates `true` if platform is running in little or big \ref endian mode,
357 * i.e. `jau::endian::little == jau::endian::native || jau::endian::big == jau::endian::native`.
358 */
362
363 /**
364 * A little-endian type trait for convenience ..
365 * <p>
366 * Since all \ref endian definitions are of `constexpr`, code can simply use expressions of these
367 * for compile-time evaluation and optimization. A template `SFINAE` is not required.
368 * </p>
369 * @tparam Dummy_type just to make template `SFINAE` happy
370 */
371 template <typename Dummy_type> struct has_endian_little : std::integral_constant<bool, endian_t::little == endian_t::native> {};
372
373 /**
374 * Value access of little-endian type trait for convenience ..
375 * <p>
376 * Since all \ref endian definitions are of `constexpr`, code can simply use expressions of these
377 * for compile-time evaluation and optimization. A template `SFINAE` is not required.
378 * </p>
379 * @tparam Dummy_type just to make template `SFINAE` happy
380 */
381 template <typename Dummy_type> constexpr bool has_endian_little_v = has_endian_little<Dummy_type>::value;
382
383 /**
384 * A big-endian type trait for convenience ..
385 * <p>
386 * Since all \ref endian definitions are of `constexpr`, code can simply use expressions of these
387 * for compile-time evaluation and optimization. A template `SFINAE` is not required.
388 * </p>
389 * @tparam Dummy_type just to make template `SFINAE` happy
390 */
391 template <typename Dummy_type> struct has_endian_big : std::integral_constant<bool, endian_t::big == endian_t::native> {};
392
393 /**
394 * Value access of big-endian type trait for convenience ..
395 * <p>
396 * Since all \ref endian definitions are of `constexpr`, code can simply use expressions of these
397 * for compile-time evaluation and optimization. A template `SFINAE` is not required.
398 * </p>
399 * @tparam Dummy_type just to make template `SFINAE` happy
400 */
401 template <typename Dummy_type> constexpr bool has_endian_big_v = has_endian_big<Dummy_type>::value;
402
403 /**
404 // *************************************************
405 // *************************************************
406 // *************************************************
407 */
408
409 // one static_assert is sufficient for whole compilation unit
410 static_assert( is_defined_endian(endian_t::native) );
411 static_assert( is_little_or_big_endian() );
412
413 constexpr uint16_t be_to_cpu(uint16_t const n) noexcept {
414 if constexpr ( is_little_endian() ) {
415 return bswap(n);
416 } else if constexpr ( is_big_endian() ) {
417 return n;
418 } else {
419 return 0; // unreachable -> static_assert(..) above
420 }
421 }
422 constexpr uint16_t cpu_to_be(uint16_t const h) noexcept {
423 if constexpr ( is_little_endian() ) {
424 return bswap(h);
425 } else if constexpr ( is_big_endian() ) {
426 return h;
427 } else {
428 return 0; // unreachable -> static_assert(..) above
429 }
430 }
431 constexpr uint16_t le_to_cpu(uint16_t const l) noexcept {
432 if constexpr ( is_little_endian() ) {
433 return l;
434 } else if constexpr ( is_big_endian() ) {
435 return bswap(l);
436 } else {
437 return 0; // unreachable -> static_assert(..) above
438 }
439 }
440 constexpr uint16_t cpu_to_le(uint16_t const h) noexcept {
441 if constexpr ( is_little_endian() ) {
442 return h;
443 } else if constexpr ( is_big_endian() ) {
444 return bswap(h);
445 } else {
446 return 0; // unreachable -> static_assert(..) above
447 }
448 }
449
450 constexpr int16_t be_to_cpu(int16_t const n) noexcept {
451 if constexpr ( is_little_endian() ) {
452 return bswap(n);
453 } else if constexpr ( is_big_endian() ) {
454 return n;
455 } else {
456 return 0; // unreachable -> static_assert(..) above
457 }
458 }
459 constexpr int16_t cpu_to_be(int16_t const h) noexcept {
460 if constexpr ( is_little_endian() ) {
461 return bswap(h);
462 } else if constexpr ( is_big_endian() ) {
463 return h;
464 } else {
465 return 0; // unreachable -> static_assert(..) above
466 }
467 }
468 constexpr int16_t le_to_cpu(int16_t const l) noexcept {
469 if constexpr ( is_little_endian() ) {
470 return l;
471 } else if constexpr ( is_big_endian() ) {
472 return bswap(l);
473 } else {
474 return 0; // unreachable -> static_assert(..) above
475 }
476 }
477 constexpr int16_t cpu_to_le(int16_t const h) noexcept {
478 if constexpr ( is_little_endian() ) {
479 return h;
480 } else if constexpr ( is_big_endian() ) {
481 return bswap(h);
482 } else {
483 return 0; // unreachable -> static_assert(..) above
484 }
485 }
486
487 constexpr uint32_t be_to_cpu(uint32_t const n) noexcept {
488 if constexpr ( is_little_endian() ) {
489 return bswap(n);
490 } else if constexpr ( is_big_endian() ) {
491 return n;
492 } else {
493 return 0; // unreachable -> static_assert(..) above
494 }
495 }
496 constexpr uint32_t cpu_to_be(uint32_t const h) noexcept {
497 if constexpr ( is_little_endian() ) {
498 return bswap(h);
499 } else if constexpr ( is_big_endian() ) {
500 return h;
501 } else {
502 return 0; // unreachable -> static_assert(..) above
503 }
504 }
505 constexpr uint32_t le_to_cpu(uint32_t const l) noexcept {
506 if constexpr ( is_little_endian() ) {
507 return l;
508 } else if constexpr ( is_big_endian() ) {
509 return bswap(l);
510 } else {
511 return 0; // unreachable -> static_assert(..) above
512 }
513 }
514 constexpr uint32_t cpu_to_le(uint32_t const h) noexcept {
515 if constexpr ( is_little_endian() ) {
516 return h;
517 } else if constexpr ( is_big_endian() ) {
518 return bswap(h);
519 } else {
520 return 0; // unreachable -> static_assert(..) above
521 }
522 }
523
524 constexpr int32_t be_to_cpu(int32_t const n) noexcept {
525 if constexpr ( is_little_endian() ) {
526 return bswap(n);
527 } else if constexpr ( is_big_endian() ) {
528 return n;
529 } else {
530 return 0; // unreachable -> static_assert(..) above
531 }
532 }
533 constexpr int32_t cpu_to_be(int32_t const h) noexcept {
534 if constexpr ( is_little_endian() ) {
535 return bswap(h);
536 } else if constexpr ( is_big_endian() ) {
537 return h;
538 } else {
539 return 0; // unreachable -> static_assert(..) above
540 }
541 }
542 constexpr int32_t le_to_cpu(int32_t const l) noexcept {
543 if constexpr ( is_little_endian() ) {
544 return l;
545 } else if constexpr ( is_big_endian() ) {
546 return bswap(l);
547 } else {
548 return 0; // unreachable -> static_assert(..) above
549 }
550 }
551 constexpr int32_t cpu_to_le(int32_t const h) noexcept {
552 if constexpr ( is_little_endian() ) {
553 return h;
554 } else if constexpr ( is_big_endian() ) {
555 return bswap(h);
556 } else {
557 return 0; // unreachable -> static_assert(..) above
558 }
559 }
560
561 constexpr uint64_t be_to_cpu(uint64_t const & n) noexcept {
562 if constexpr ( is_little_endian() ) {
563 return bswap(n);
564 } else if constexpr ( is_big_endian() ) {
565 return n;
566 } else {
567 return 0; // unreachable -> static_assert(..) above
568 }
569 }
570 constexpr uint64_t cpu_to_be(uint64_t const & h) noexcept {
571 if constexpr ( is_little_endian() ) {
572 return bswap(h);
573 } else if constexpr ( is_big_endian() ) {
574 return h;
575 } else {
576 return 0; // unreachable -> static_assert(..) above
577 }
578 }
579 constexpr uint64_t le_to_cpu(uint64_t const & l) noexcept {
580 if constexpr ( is_little_endian() ) {
581 return l;
582 } else if constexpr ( is_big_endian() ) {
583 return bswap(l);
584 } else {
585 return 0; // unreachable -> static_assert(..) above
586 }
587 }
588 constexpr uint64_t cpu_to_le(uint64_t const & h) noexcept {
589 if constexpr ( is_little_endian() ) {
590 return h;
591 } else if constexpr ( is_big_endian() ) {
592 return bswap(h);
593 } else {
594 return 0; // unreachable -> static_assert(..) above
595 }
596 }
597
598 constexpr int64_t be_to_cpu(int64_t const & n) noexcept {
599 if constexpr ( is_little_endian() ) {
600 return bswap(n);
601 } else if constexpr ( is_big_endian() ) {
602 return n;
603 } else {
604 return 0; // unreachable -> static_assert(..) above
605 }
606 }
607 constexpr int64_t cpu_to_be(int64_t const & h) noexcept {
608 if constexpr ( is_little_endian() ) {
609 return bswap(h);
610 } else if constexpr ( is_big_endian() ) {
611 return h;
612 } else {
613 return 0; // unreachable -> static_assert(..) above
614 }
615 }
616 constexpr int64_t le_to_cpu(int64_t const & l) noexcept {
617 if constexpr ( is_little_endian() ) {
618 return l;
619 } else if constexpr ( is_big_endian() ) {
620 return bswap(l);
621 } else {
622 return 0; // unreachable -> static_assert(..) above
623 }
624 }
625 constexpr int64_t cpu_to_le(int64_t const & h) noexcept {
626 if constexpr ( is_little_endian() ) {
627 return h;
628 } else if constexpr ( is_big_endian() ) {
629 return bswap(h);
630 } else {
631 return 0; // unreachable -> static_assert(..) above
632 }
633 }
634
635 constexpr uint128dp_t be_to_cpu(uint128dp_t const & n) noexcept {
636 if constexpr ( is_little_endian() ) {
637 return bswap(n);
638 } else if constexpr ( is_big_endian() ) {
639 return n;
640 } else {
641 return {}; // unreachable -> static_assert(..) above
642 }
643 }
644 constexpr uint128dp_t cpu_to_be(uint128dp_t const & h) noexcept {
645 if constexpr ( is_little_endian() ) {
646 return bswap(h);
647 } else if constexpr ( is_big_endian() ) {
648 return h;
649 } else {
650 return {}; // unreachable -> static_assert(..) above
651 }
652 }
653 constexpr uint128dp_t le_to_cpu(uint128dp_t const & l) noexcept {
654 if constexpr ( is_little_endian() ) {
655 return l;
656 } else if constexpr ( is_big_endian() ) {
657 return bswap(l);
658 } else {
659 return {}; // unreachable -> static_assert(..) above
660 }
661 }
662 constexpr uint128dp_t cpu_to_le(uint128dp_t const & h) noexcept {
663 if constexpr ( is_little_endian() ) {
664 return h;
665 } else if constexpr ( is_big_endian() ) {
666 return bswap(h);
667 } else {
668 return {}; // unreachable -> static_assert(..) above
669 }
670 }
671
672 constexpr uint192dp_t be_to_cpu(uint192dp_t const & n) noexcept {
673 if constexpr ( is_little_endian() ) {
674 return bswap(n);
675 } else if constexpr ( is_big_endian() ) {
676 return n;
677 } else {
678 return {}; // unreachable -> static_assert(..) above
679 }
680 }
681 constexpr uint192dp_t cpu_to_be(uint192dp_t const & h) noexcept {
682 if constexpr ( is_little_endian() ) {
683 return bswap(h);
684 } else if constexpr ( is_big_endian() ) {
685 return h;
686 } else {
687 return {}; // unreachable -> static_assert(..) above
688 }
689 }
690 constexpr uint192dp_t le_to_cpu(uint192dp_t const & l) noexcept {
691 if constexpr ( is_little_endian() ) {
692 return l;
693 } else if constexpr ( is_big_endian() ) {
694 return bswap(l);
695 } else {
696 return {}; // unreachable -> static_assert(..) above
697 }
698 }
699 constexpr uint192dp_t cpu_to_le(uint192dp_t const & h) noexcept {
700 if constexpr ( is_little_endian() ) {
701 return h;
702 } else if constexpr ( is_big_endian() ) {
703 return bswap(h);
704 } else {
705 return {}; // unreachable -> static_assert(..) above
706 }
707 }
708
709 constexpr uint256dp_t be_to_cpu(uint256dp_t const & n) noexcept {
710 if constexpr ( is_little_endian() ) {
711 return bswap(n);
712 } else if constexpr ( is_big_endian() ) {
713 return n;
714 } else {
715 return {}; // unreachable -> static_assert(..) above
716 }
717 }
718 constexpr uint256dp_t cpu_to_be(uint256dp_t const & h) noexcept {
719 if constexpr ( is_little_endian() ) {
720 return bswap(h);
721 } else if constexpr ( is_big_endian() ) {
722 return h;
723 } else {
724 return {}; // unreachable -> static_assert(..) above
725 }
726 }
727 constexpr uint256dp_t le_to_cpu(uint256dp_t const & l) noexcept {
728 if constexpr ( is_little_endian() ) {
729 return l;
730 } else if constexpr ( is_big_endian() ) {
731 return bswap(l);
732 } else {
733 return {}; // unreachable -> static_assert(..) above
734 }
735 }
736 constexpr uint256dp_t cpu_to_le(uint256dp_t const & h) noexcept {
737 if constexpr ( is_little_endian() ) {
738 return h;
739 } else if constexpr ( is_big_endian() ) {
740 return bswap(h);
741 } else {
742 return {}; // unreachable -> static_assert(..) above
743 }
744
745 }
746
747 /**
748 // *************************************************
749 // *************************************************
750 // *************************************************
751 */
752
753 namespace impl {
754 /** @see https://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable */
755 static constexpr std::array<uint8_t, 256> BitRevTable256 =
756 []() constexpr -> std::array<uint8_t, 256> {
757 using namespace jau::int_literals;
758 std::array<uint8_t, 256> result{};
759 for (size_t i = 0; i < 256; ++i) {
760 // result[i] = (i * 0x0202020202_u64 & 0x010884422010_u64) % 1023;
761 result[i] = ( (i * 0x80200802_u64) & 0x0884422110_u64 ) * 0x0101010101_u64 >> 32;
762 }
763 return result;
764 }();
765 }
766
767 /**
768 * Reverse bits of one byte
769 * @see https://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
770 */
771 constexpr uint8_t rev_bits(uint8_t v) noexcept { return impl::BitRevTable256[v]; };
772 /**
773 * Reverse bits of two bytes
774 * @see https://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
775 */
776 constexpr uint16_t rev_bits(uint16_t v) noexcept {
777 return ( uint16_t( impl::BitRevTable256[ v & 0xff] ) << 8) |
778 ( uint16_t( impl::BitRevTable256[(v >> 8) & 0xff] ) );
779 };
780 /**
781 * Reverse bits of four bytes
782 * @see https://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
783 */
784 constexpr uint32_t rev_bits(uint32_t v) noexcept {
785 return ( uint32_t( impl::BitRevTable256[ v & 0xff] ) << 24) |
786 ( uint32_t( impl::BitRevTable256[(v >> 8) & 0xff] ) << 16) |
787 ( uint32_t( impl::BitRevTable256[(v >> 16) & 0xff] ) << 8) |
788 ( uint32_t( impl::BitRevTable256[(v >> 24) & 0xff] ) );
789 };
790 /**
791 * Reverse bits of eight bytes
792 * @see https://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
793 */
794 constexpr uint64_t rev_bits(uint64_t v) noexcept {
795 return ( uint64_t( impl::BitRevTable256[ v & 0xff] ) << 56) |
796 ( uint64_t( impl::BitRevTable256[(v >> 8) & 0xff] ) << 48) |
797 ( uint64_t( impl::BitRevTable256[(v >> 16) & 0xff] ) << 40) |
798 ( uint64_t( impl::BitRevTable256[(v >> 24) & 0xff] ) << 32) |
799 ( uint64_t( impl::BitRevTable256[(v >> 32) & 0xff] ) << 24) |
800 ( uint64_t( impl::BitRevTable256[(v >> 40) & 0xff] ) << 16) |
801 ( uint64_t( impl::BitRevTable256[(v >> 48) & 0xff] ) << 8) |
802 ( uint64_t( impl::BitRevTable256[(v >> 56) & 0xff] ) );
803 };
804
805 /** Returns the T bit mask of n-bits, i.e. n low order 1’s */
806 template<jau::req::unsigned_integral T>
807 static constexpr T bit_mask(size_t n) noexcept {
808 if ( n >= sizeof(T) * CHAR_BIT ) {
809 return std::numeric_limits<T>::max();
810 } else {
811 return (T(1) << n) - T(1);
812 }
813 }
814
815 /**
816 * Reversed `n` bits of value `v`, this is an O(n) operation.
817 *
818 * The reversed bits will stick in their `n` bits position,
819 * i.e. not shifted to the left of `n` bits as `rev_bits(v)` would.
820 * @see https://graphics.stanford.edu/~seander/bithacks.html#BitReverseTable
821 */
822 template<jau::req::unsigned_integral T>
823 constexpr T rev_bits(jau::nsize_t n, T v) {
824 if ( n >= sizeof(T) * CHAR_BIT ) {
825 return rev_bits(v); // reverse all bits
826 }
827 v &= (T(1) << n) - T(1); // mask-out undesired bits
828 T r = v & 1; // r will be reversed bits of v; first get LSB of v
829 jau::nsize_t s = std::min<jau::nsize_t>(n-1, jau::nsize_t( sizeof(T) ) * CHAR_BIT - 1); // extra shift needed at end
830 for (v >>= 1; v; v >>= 1) {
831 r <<= 1;
832 r |= v & 1;
833 --s;
834 }
835 return r << s; // shift when v's highest bits are zero
836 }
837
838 /**
839 // *************************************************
840 // *************************************************
841 // *************************************************
842 */
843
844 constexpr void put_uint8(uint8_t * buffer, const uint8_t v) noexcept
845 {
846 *pointer_cast<uint8_t *>( buffer ) = v;
847 }
848 constexpr uint8_t get_uint8(uint8_t const * buffer) noexcept
849 {
850 return *pointer_cast<uint8_t const *>( buffer );
851 }
852 constexpr int8_t get_int8(uint8_t const * buffer) noexcept
853 {
854 return *pointer_cast<int8_t const *>( buffer );
855 }
856
857 /**
858 * Return packed_t::store after converting it to from either lb_endian::little or lb_endian::big depending on given `byte_order`
859 * to lb_endian::native.
860 * @tparam T
861 * @param source
862 * @param byte_order
863 */
864 template<typename T>
865 constexpr T get_packed_value(const packed_t<T>* source, const lb_endian_t byte_order) noexcept {
866 return is_little_endian(byte_order) ? le_to_cpu(source->store) : be_to_cpu(source->store);
867 }
868
869 /**
870 * Put the given uint16_t value into the given byte address
871 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
872 *
873 * @see \ref packed_t_alignment_cast
874 */
875 constexpr void put_uint16(uint8_t * buffer, const uint16_t v) noexcept
876 {
877 pointer_cast<packed_t<uint16_t>*>( buffer )->store = v;
878 }
879 /**
880 * Put the given uint16_t value into the given byte address
881 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
882 *
883 * The value is converted from lb_endian::native to either lb_endian::little or lb_endian::big depending on given `byte_order`
884 * before it is stored in memory.
885 *
886 * @see \ref packed_t_alignment_cast
887 */
888 constexpr void put_uint16(uint8_t * buffer, const uint16_t v, const lb_endian_t byte_order) noexcept
889 {
890 pointer_cast<packed_t<uint16_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
891 }
892 /**
893 * Returns a uint16_t value from the given byte address
894 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
895 *
896 * @see \ref packed_t_alignment_cast
897 */
898 constexpr uint16_t get_uint16(uint8_t const * buffer) noexcept
899 {
900 return pointer_cast<const packed_t<uint16_t>*>( buffer )->store;
901 }
902 /**
903 * Returns a uint16_t value from the given byte address
904 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
905 *
906 * The value is converted from either lb_endian::little or lb_endian::big depending on given `byte_order`
907 * to lb_endian::native before it is returned to the caller.
908 *
909 * @see \ref packed_t_alignment_cast
910 */
911 constexpr uint16_t get_uint16(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
912 {
913 return get_packed_value(pointer_cast<const packed_t<uint16_t>*>( buffer ), byte_order);
914 }
915
916 /**
917 * Put the given int16_t value into the given byte address
918 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
919 *
920 * @see \ref packed_t_alignment_cast
921 */
922 constexpr void put_int16(uint8_t * buffer, const int16_t v) noexcept
923 {
924 pointer_cast<packed_t<int16_t>*>( buffer )->store = v;
925 }
926 /**
927 * Put the given uint16_t value into the given byte address
928 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
929 *
930 * The value is converted from lb_endian::native to either lb_endian::little or lb_endian::big depending on given `byte_order`
931 * before it is stored in memory.
932 *
933 * @see \ref packed_t_alignment_cast
934 */
935 constexpr void put_int16(uint8_t * buffer, const int16_t v, const lb_endian_t byte_order) noexcept
936 {
937 pointer_cast<packed_t<int16_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
938 }
939 /**
940 * Returns a int16_t value from the given byte address
941 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
942 *
943 * @see \ref packed_t_alignment_cast
944 */
945 constexpr int16_t get_int16(uint8_t const * buffer) noexcept
946 {
947 return pointer_cast<const packed_t<int16_t>*>( buffer )->store;
948 }
949 /**
950 * Returns a int16_t value from the given byte address
951 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
952 *
953 * The value is converted from either lb_endian::little or lb_endian::big depending on given `byte_order`
954 * to lb_endian::native before it is returned to the caller.
955 *
956 * @see \ref packed_t_alignment_cast
957 */
958 constexpr int16_t get_int16(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
959 {
960 return get_packed_value(pointer_cast<const packed_t<int16_t>*>( buffer ), byte_order);
961 }
962
963 /**
964 * See put_uint16() for reference.
965 * @see \ref packed_t_alignment_cast
966 */
967 constexpr void put_uint32(uint8_t * buffer, const uint32_t v) noexcept
968 {
969 pointer_cast<packed_t<uint32_t>*>( buffer )->store = v;
970 }
971 /**
972 * See put_uint16() for reference.
973 * @see \ref packed_t_alignment_cast
974 */
975 constexpr void put_uint32(uint8_t * buffer, const uint32_t v, const lb_endian_t byte_order) noexcept
976 {
977 pointer_cast<packed_t<uint32_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
978 }
979 /**
980 * See get_uint16() for reference.
981 * @see \ref packed_t_alignment_cast
982 */
983 constexpr uint32_t get_uint32(uint8_t const * buffer) noexcept
984 {
985 return pointer_cast<const packed_t<uint32_t>*>( buffer )->store;
986 }
987 /**
988 * See get_uint16() for reference.
989 * @see \ref packed_t_alignment_cast
990 */
991 constexpr uint32_t get_uint32(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
992 {
993 return get_packed_value(pointer_cast<const packed_t<uint32_t>*>( buffer ), byte_order);
994 }
995
996 /**
997 * See put_int16() for reference.
998 * @see \ref packed_t_alignment_cast
999 */
1000 constexpr void put_int32(uint8_t * buffer, const int32_t v) noexcept
1001 {
1002 pointer_cast<packed_t<int32_t>*>( buffer )->store = v;
1003 }
1004 /**
1005 * See put_int16() for reference.
1006 * @see \ref packed_t_alignment_cast
1007 */
1008 constexpr void put_int32(uint8_t * buffer, const int32_t v, const lb_endian_t byte_order) noexcept
1009 {
1010 pointer_cast<packed_t<int32_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
1011 }
1012 /**
1013 * See get_int16() for reference.
1014 * @see \ref packed_t_alignment_cast
1015 */
1016 constexpr int32_t get_int32(uint8_t const * buffer) noexcept
1017 {
1018 return pointer_cast<const packed_t<int32_t>*>( buffer )->store;
1019 }
1020 /**
1021 * See get_int16() for reference.
1022 * @see \ref packed_t_alignment_cast
1023 */
1024 constexpr int32_t get_int32(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
1025 {
1026 return get_packed_value(pointer_cast<const packed_t<int32_t>*>( buffer ), byte_order);
1027 }
1028
1029 /**
1030 * See put_uint16() for reference.
1031 * @see \ref packed_t_alignment_cast
1032 */
1033 constexpr void put_uint64(uint8_t * buffer, const uint64_t & v) noexcept
1034 {
1035 pointer_cast<packed_t<uint64_t>*>( buffer )->store = v;
1036 }
1037 /**
1038 * See put_uint16() for reference.
1039 * @see \ref packed_t_alignment_cast
1040 */
1041 constexpr void put_uint64(uint8_t * buffer, const uint64_t & v, const lb_endian_t byte_order) noexcept
1042 {
1043 pointer_cast<packed_t<uint64_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
1044 }
1045 /**
1046 * See get_uint16() for reference.
1047 * @see \ref packed_t_alignment_cast
1048 */
1049 constexpr uint64_t get_uint64(uint8_t const * buffer) noexcept
1050 {
1051 return pointer_cast<const packed_t<uint64_t>*>( buffer )->store;
1052 }
1053 /**
1054 * See get_uint16() for reference.
1055 * @see \ref packed_t_alignment_cast
1056 */
1057 constexpr uint64_t get_uint64(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
1058 {
1059 return get_packed_value(pointer_cast<const packed_t<uint64_t>*>( buffer ), byte_order);
1060 }
1061
1062 /**
1063 * See put_int16() for reference.
1064 * @see \ref packed_t_alignment_cast
1065 */
1066 constexpr void put_int64(uint8_t * buffer, const int64_t & v) noexcept
1067 {
1068 pointer_cast<packed_t<int64_t>*>( buffer )->store = v;
1069 }
1070 /**
1071 * See put_int16() for reference.
1072 * @see \ref packed_t_alignment_cast
1073 */
1074 constexpr void put_int64(uint8_t * buffer, const int64_t & v, const lb_endian_t byte_order) noexcept
1075 {
1076 pointer_cast<packed_t<int64_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
1077 }
1078 /**
1079 * See get_int16() for reference.
1080 * @see \ref packed_t_alignment_cast
1081 */
1082 constexpr int64_t get_int64(uint8_t const * buffer) noexcept
1083 {
1084 return pointer_cast<const packed_t<int64_t>*>( buffer )->store;
1085 }
1086 /**
1087 * See get_int16() for reference.
1088 * @see \ref packed_t_alignment_cast
1089 */
1090 constexpr int64_t get_int64(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
1091 {
1092 return get_packed_value(pointer_cast<const packed_t<int64_t>*>( buffer ), byte_order);
1093 }
1094
1095 /**
1096 * See put_uint16() for reference.
1097 * @see \ref packed_t_alignment_cast
1098 */
1099 constexpr void put_uint128(uint8_t * buffer, const uint128dp_t & v) noexcept
1100 {
1101 pointer_cast<packed_t<uint128dp_t>*>( buffer )->store = v;
1102 }
1103 /**
1104 * See put_uint16() for reference.
1105 * @see \ref packed_t_alignment_cast
1106 */
1107 constexpr void put_uint128(uint8_t * buffer, const uint128dp_t & v, const lb_endian_t byte_order) noexcept
1108 {
1109 pointer_cast<packed_t<uint128dp_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
1110 }
1111 /**
1112 * See get_uint16() for reference.
1113 * @see \ref packed_t_alignment_cast
1114 */
1115 constexpr uint128dp_t get_uint128(uint8_t const * buffer) noexcept
1116 {
1117 return pointer_cast<const packed_t<uint128dp_t>*>( buffer )->store;
1118 }
1119 /**
1120 * See get_uint16() for reference.
1121 * @see \ref packed_t_alignment_cast
1122 */
1123 constexpr uint128dp_t get_uint128(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
1124 {
1125 return get_packed_value(pointer_cast<const packed_t<uint128dp_t>*>( buffer ), byte_order);
1126 }
1127
1128 /**
1129 * See put_uint16() for reference.
1130 * @see \ref packed_t_alignment_cast
1131 */
1132 constexpr void put_uint192(uint8_t * buffer, const uint192dp_t & v) noexcept
1133 {
1134 pointer_cast<packed_t<uint192dp_t>*>( buffer )->store = v;
1135 }
1136 /**
1137 * See put_uint16() for reference.
1138 * @see \ref packed_t_alignment_cast
1139 */
1140 constexpr void put_uint192(uint8_t * buffer, const uint192dp_t & v, const lb_endian_t byte_order) noexcept
1141 {
1142 pointer_cast<packed_t<uint192dp_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
1143 }
1144 /**
1145 * See get_uint16() for reference.
1146 * @see \ref packed_t_alignment_cast
1147 */
1148 constexpr uint192dp_t get_uint192(uint8_t const * buffer) noexcept
1149 {
1150 return pointer_cast<const packed_t<uint192dp_t>*>( buffer )->store;
1151 }
1152 /**
1153 * See get_uint16() for reference.
1154 * @see \ref packed_t_alignment_cast
1155 */
1156 constexpr uint192dp_t get_uint192(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
1157 {
1158 return get_packed_value(pointer_cast<const packed_t<uint192dp_t>*>( buffer ), byte_order);
1159 }
1160
1161 /**
1162 * See put_uint16() for reference.
1163 * @see \ref packed_t_alignment_cast
1164 */
1165 constexpr void put_uint256(uint8_t * buffer, const uint256dp_t & v) noexcept
1166 {
1167 pointer_cast<packed_t<uint256dp_t>*>( buffer )->store = v;
1168 }
1169 /**
1170 * See put_uint16() for reference.
1171 * @see \ref packed_t_alignment_cast
1172 */
1173 constexpr void put_uint256(uint8_t * buffer, const uint256dp_t & v, const lb_endian_t byte_order) noexcept
1174 {
1175 pointer_cast<packed_t<uint256dp_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
1176 }
1177 /**
1178 * See get_uint16() for reference.
1179 * @see \ref packed_t_alignment_cast
1180 */
1181 constexpr uint256dp_t get_uint256(uint8_t const * buffer) noexcept
1182 {
1183 return pointer_cast<const packed_t<uint256dp_t>*>( buffer )->store;
1184 }
1185 /**
1186 * See get_uint16() for reference.
1187 * @see \ref packed_t_alignment_cast
1188 */
1189 constexpr uint256dp_t get_uint256(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
1190 {
1191 return get_packed_value(pointer_cast<const packed_t<uint256dp_t>*>( buffer ), byte_order);
1192 }
1193
1194 /**
1195 // *************************************************
1196 // *************************************************
1197 // *************************************************
1198 */
1199
1200 /**
1201 * Put the given T value into the given byte address
1202 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
1203 *
1204 * @tparam T
1205 * @param buffer
1206 * @param v
1207 * @see \ref packed_t_alignment_cast
1208 */
1209 template<typename T>
1210 constexpr
1211 typename std::enable_if_t<
1212 std::is_standard_layout_v<T>,
1213 void>
1214 put_value(uint8_t * buffer, const T& v) noexcept
1215 {
1216 // reinterpret_cast<packed_t<T>*>( buffer )->store = v;
1217 pointer_cast<packed_t<T>*>( buffer )->store = v;
1218 }
1219
1220 /**
1221 * Put the given T value into the given byte address
1222 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
1223 *
1224 * The value is converted from lb_endian::native to either lb_endian::little or lb_endian::big depending on given `byte_order`
1225 * before it is stored in memory.
1226 *
1227 * @tparam T
1228 * @param buffer
1229 * @param v
1230 * @param byte_order
1231 * @see \ref packed_t_alignment_cast
1232 */
1233 template<typename T>
1234 constexpr
1235 typename std::enable_if_t<
1236 std::is_standard_layout_v<T>,
1237 void>
1238 put_value(uint8_t * buffer, const T& v, const lb_endian_t byte_order) noexcept
1239 {
1240 pointer_cast<packed_t<T>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
1241 }
1242
1243 /**
1244 * Returns a T value from the given byte address
1245 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
1246 *
1247 * @tparam T
1248 * @param buffer
1249 * @return
1250 * @see \ref packed_t_alignment_cast
1251 */
1252 template<typename T>
1253 constexpr
1254 typename std::enable_if_t<
1255 std::is_standard_layout_v<T>,
1256 T>
1257 get_value(uint8_t const * buffer) noexcept
1258 {
1259 return pointer_cast<const packed_t<T>*>( buffer )->store;
1260 }
1261
1262 /**
1263 * Returns a T value from the given byte address
1264 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
1265 *
1266 * The value is converted from either lb_endian::little or lb_endian::big depending on given `byte_order`
1267 * to lb_endian::native before it is returned to the caller.
1268 *
1269 * @tparam T
1270 * @param buffer
1271 * @param byte_order
1272 * @return
1273 * @see \ref packed_t_alignment_cast
1274 */
1275 template<typename T>
1276 constexpr
1277 typename std::enable_if_t<
1278 std::is_standard_layout_v<T>,
1279 T>
1280 get_value(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
1281 {
1282 return get_packed_value(pointer_cast<const packed_t<T>*>( buffer ), byte_order);
1283 }
1284
1285 /**@}*/
1286
1287} // namespace jau
1288
1289/** \example test_basictypeconv.cpp
1290 * This C++ unit test validates the jau::bswap and get/set value implementation
1291 */
1292
1293#endif /* JAU_BYTE_UTIL_HPP_ */
constexpr uint192dp_t get_uint192(uint8_t const *buffer) noexcept
See get_uint16() for reference.
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.
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 uint16_t bswap(uint16_t const source) noexcept
Definition byte_util.hpp:88
constexpr bool is_little_or_big_endian() noexcept
Evaluates true if platform is running in little or big endian mode, i.e.
constexpr uint16_t cpu_to_be(uint16_t const h) noexcept
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 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 uint16_t le_to_cpu(uint16_t const l) noexcept
constexpr void put_uint8(uint8_t *buffer, const uint8_t v) 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 uint16_t be_to_cpu(uint16_t const n) noexcept
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 uint16_t cpu_to_le(uint16_t const h) noexcept
constexpr void put_int32(uint8_t *buffer, const int32_t v) noexcept
See put_int16() for reference.
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
const uint8_t * cast_char_ptr_to_uint8(const char *s) noexcept
@ 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:85
constexpr uint32_t get_host_order() noexcept
static constexpr std::array< uint8_t, 256 > BitRevTable256
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition backtrace.hpp:32
std::string to_string(const bit_order_t v) noexcept
Return std::string representation of the given bit_order_t.
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]