Direct-BT v3.3.0-1-gc2d430c
Direct-BT - Direct Bluetooth Programming.
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 <cstring>
29#include <string>
30#include <memory>
31#include <cstdint>
32#include <vector>
33#include <type_traits>
34
35#include <jau/cpp_lang_util.hpp>
36#include <jau/cpp_pragma.hpp>
38
39#include <jau/int_types.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 uint32_t bswap(uint32_t const source) noexcept {
98 #if defined __has_builtin_bswap32
99 return __builtin_bswap32(source);
100 #else
101 return ( ( source & 0xff000000U ) >> 24 ) |
102 ( ( source & 0x00ff0000U ) >> 8 ) |
103 ( ( source & 0x0000ff00U ) << 8 ) |
104 ( ( source & 0x000000ffU ) << 24 );
105 #endif
106 }
107
108 constexpr uint64_t bswap(uint64_t const & source) noexcept {
109 #if defined __has_builtin_bswap64
110 return __builtin_bswap64(source);
111 #else
112 return ( ( source & 0xff00000000000000ULL ) >> 56 ) |
113 ( ( source & 0x00ff000000000000ULL ) >> 40 ) |
114 ( ( source & 0x0000ff0000000000ULL ) >> 24 ) |
115 ( ( source & 0x000000ff00000000ULL ) >> 8 ) |
116 ( ( source & 0x00000000ff000000ULL ) << 8 ) |
117 ( ( source & 0x0000000000ff0000ULL ) << 24 ) |
118 ( ( source & 0x000000000000ff00ULL ) << 40 ) |
119 ( ( source & 0x00000000000000ffULL ) << 56 );
120 #endif
121 }
122
123 constexpr void bswap(uint8_t * sink, uint8_t const * source, nsize_t len) {
124 source += len - 1;
125 for (; len > 0; len--) {
126 *sink++ = *source--;
127 }
128 }
129
130 constexpr uint128dp_t bswap(uint128dp_t const & source) noexcept {
131 uint128dp_t dest;
132 bswap(dest.data, source.data, 16);
133 return dest;
134 }
135
136 constexpr uint192dp_t bswap(uint192dp_t const & source) noexcept {
137 uint192dp_t dest;
138 bswap(dest.data, source.data, 24);
139 return dest;
140 }
141
142 constexpr uint256dp_t bswap(uint256dp_t const & source) noexcept {
143 uint256dp_t dest;
144 bswap(dest.data, source.data, 32);
145 return dest;
146 }
147
148 inline char* cast_uint8_ptr_to_char(uint8_t* b) noexcept {
149 return reinterpret_cast<char*>(b);
150 }
151 inline const char* cast_uint8_ptr_to_char(const uint8_t* b) noexcept {
152 return reinterpret_cast<const char*>(b);
153 }
154
155 inline const uint8_t* cast_char_ptr_to_uint8(const char* s) noexcept {
156 return reinterpret_cast<const uint8_t*>(s);
157 }
158
159 /**
160 // *************************************************
161 // *************************************************
162 // *************************************************
163 */
164
167
168 namespace impl {
169 constexpr uint32_t get_host_order() noexcept {
170 if constexpr ( jau::is_builtin_bit_cast_available() ) {
171 constexpr uint8_t b[4] { 0x44, 0x43, 0x42, 0x41 }; // h->l: 41 42 43 44 = 'ABCD' hex ASCII code
172 return jau::bit_cast<uint32_t, uint8_t[4]>( b );
173 } else {
174 // The pragma to stop multichar warning == error `-Werror=multichar` doesn't seem to work with GCC <= 10.2
175 // Hence we have to disable this specific warning via: `-Wno-multichar`
176 // until all our compiler support `__builtin_bit_cast(T, a)`
177 return 'ABCD'; // h->l: 41 42 43 44 = 'ABCD' hex ASCII code
178 }
179 }
180 }
181
182 /**
183 * Endian identifier, indicating endianess of all scalar types.
184 *
185 * Inspired by C++20 std::endian
186 *
187 * Corner case platforms currently not supported,
188 * i.e. unified endianess and mixed endianess.
189 *
190 * All endian API entries are of `constexpr` and hence evaluated at compile time.<br>
191 * Therefore, if-branches and expressions are also of `constexpr` and optimized 'away' at compile time.<br>
192 * This includes the `cpu_to_<endian>(..)` and `<endian>_to_cpu(..)` etc utility functions.
193 *
194 * On i386 platforms the host byte order is Least Significant Byte first (LSB) or Little-Endian,
195 * whereas the network byte order, as used on the Internet, is Most Significant Byte first (MSB) or Big-Endian.
196 * See #include <arpa/inet.h>
197 *
198 * Bluetooth is LSB or Little-Endian!
199 *
200 * See \ref lb_endian
201 */
202 enum class endian_t : uint32_t
203 {
204 /** Identifier for little endian. */
205 little = 0x41424344U, // h->l: 41 42 43 44 = 'ABCD' hex ASCII code
206
207 /** Identifier for big endian. */
208 big = 0x44434241U, // h->l: 44 43 42 41 = 'DCBA' hex ASCII code
209
210 /** Identifier for DEC PDP-11, aka `ENDIAN_LITTLE_WORD`. */
211 pdp = 0x43444142U, // h->l: 43 44 41 42 = 'CDAB' hex ASCII code
212
213 /** Identifier for Honeywell 316, aka `ENDIAN_BIG_WORD`. */
214 honeywell = 0x42414443U, // h->l: 42 41 44 43 = 'BADC' hex ASCII code
215
216 /** Undetermined endian */
217 undefined = 0x00000000U,
218
219 /** Identifier for native platform type, one of the above. */
221 };
222
224
225 /** Simplified reduced \ref endian type only covering little- and big-endian. See \ref endian for details. */
226 enum class lb_endian_t : uint32_t
227 {
228 /** Identifier for little endian, equivalent to endian::little. */
229 little = static_cast<uint32_t>( endian_t::little ),
230
231 /** Identifier for big endian, equivalent to endian::big. */
232 big = static_cast<uint32_t>( endian_t::big ),
233
234 /** Identifier for native platform type, one of the above. */
235 native = static_cast<uint32_t>( endian_t::native )
236 };
237
238 /**
239 * Return std::string representation of the given \ref endian.
240 * @param v the \ref endian value
241 * @return the std::string representation
242 */
243 std::string to_string(const endian_t v) noexcept;
244
245 /**
246 * Return std::string representation of the given \ref lb_endian.
247 * @param v the \ref lb_endian value
248 * @return the std::string representation
249 */
250 std::string to_string(const lb_endian_t v) noexcept;
251
252 constexpr lb_endian_t to_lb_endian(const endian_t v) noexcept {
253 switch(v) {
255 case endian_t::big: return lb_endian_t::big;
256 default: {
257 abort(); // never reached
258 }
259 }
260 }
261 constexpr endian_t to_endian(const lb_endian_t v) noexcept {
262 switch(v) {
264 case lb_endian_t::big: return endian_t::big;
265 default: {
266 abort(); // never reached
267 }
268 }
269 }
270
271 /**
272 * Evaluates `true` if the given \ref endian is defined,
273 * i.e. `little`, `big`, `pdp` or `honeywell`.
274 */
275 constexpr bool is_defined_endian(const endian_t &v) noexcept {
276 switch(v) {
277 case endian_t::little:
278 [[fallthrough]];
279 case endian_t::big:
280 [[fallthrough]];
281 case endian_t::pdp:
282 [[fallthrough]];
284 return true;
285 default:
286 return false;
287 }
288 }
289
290 /**
291 * Returns `true` if given `byte_order` equals endian::little, otherwise false.
292 */
293 constexpr bool is_little_endian(const endian_t byte_order) noexcept {
294 return endian_t::little == byte_order;
295 }
296
297 /**
298 * Returns `true` if given `byte_order` equals lb_endian::little, otherwise false.
299 */
300 constexpr bool is_little_endian(const lb_endian_t byte_order) noexcept {
301 return lb_endian_t::little == byte_order;
302 }
303
304 /**
305 * Evaluates `true` if platform is running in little \ref endian mode,
306 * i.e. `jau::endian::little == jau::endian::native`.
307 */
308 constexpr bool is_little_endian() noexcept {
310 }
311
312 /**
313 * Evaluates `true` if platform is running in big \ref endian mode,
314 * i.e. `jau::endian::big == jau::endian::native`.
315 */
316 constexpr bool is_big_endian() noexcept {
318 }
319
320 /**
321 * Evaluates `true` if platform is running in little or big \ref endian mode,
322 * i.e. `jau::endian::little == jau::endian::native || jau::endian::big == jau::endian::native`.
323 */
324 constexpr bool is_little_or_big_endian() noexcept {
326 }
327
328 /**
329 * A little-endian type trait for convenience ..
330 * <p>
331 * Since all \ref endian definitions are of `constexpr`, code can simply use expressions of these
332 * for compile-time evaluation and optimization. A template `SFINAE` is not required.
333 * </p>
334 * @tparam Dummy_type just to make template `SFINAE` happy
335 */
336 template <typename Dummy_type> struct has_endian_little : std::integral_constant<bool, endian_t::little == endian_t::native> {};
337
338 /**
339 * Value access of little-endian type trait for convenience ..
340 * <p>
341 * Since all \ref endian definitions are of `constexpr`, code can simply use expressions of these
342 * for compile-time evaluation and optimization. A template `SFINAE` is not required.
343 * </p>
344 * @tparam Dummy_type just to make template `SFINAE` happy
345 */
346 template <typename Dummy_type> constexpr bool has_endian_little_v = has_endian_little<Dummy_type>::value;
347
348 /**
349 * A big-endian type trait for convenience ..
350 * <p>
351 * Since all \ref endian definitions are of `constexpr`, code can simply use expressions of these
352 * for compile-time evaluation and optimization. A template `SFINAE` is not required.
353 * </p>
354 * @tparam Dummy_type just to make template `SFINAE` happy
355 */
356 template <typename Dummy_type> struct has_endian_big : std::integral_constant<bool, endian_t::big == endian_t::native> {};
357
358 /**
359 * Value access of big-endian type trait for convenience ..
360 * <p>
361 * Since all \ref endian definitions are of `constexpr`, code can simply use expressions of these
362 * for compile-time evaluation and optimization. A template `SFINAE` is not required.
363 * </p>
364 * @tparam Dummy_type just to make template `SFINAE` happy
365 */
366 template <typename Dummy_type> constexpr bool has_endian_big_v = has_endian_big<Dummy_type>::value;
367
368 /**
369 // *************************************************
370 // *************************************************
371 // *************************************************
372 */
373
374 // one static_assert is sufficient for whole compilation unit
375 static_assert( is_defined_endian(endian_t::native) );
376 static_assert( is_little_or_big_endian() );
377
378 constexpr uint16_t be_to_cpu(uint16_t const n) noexcept {
379 if constexpr ( is_little_endian() ) {
380 return bswap(n);
381 } else if constexpr ( is_big_endian() ) {
382 return n;
383 } else {
384 return 0; // unreachable -> static_assert(..) above
385 }
386 }
387 constexpr uint16_t cpu_to_be(uint16_t const h) noexcept {
388 if constexpr ( is_little_endian() ) {
389 return bswap(h);
390 } else if constexpr ( is_big_endian() ) {
391 return h;
392 } else {
393 return 0; // unreachable -> static_assert(..) above
394 }
395 }
396 constexpr uint16_t le_to_cpu(uint16_t const l) noexcept {
397 if constexpr ( is_little_endian() ) {
398 return l;
399 } else if constexpr ( is_big_endian() ) {
400 return bswap(l);
401 } else {
402 return 0; // unreachable -> static_assert(..) above
403 }
404 }
405 constexpr uint16_t cpu_to_le(uint16_t const h) noexcept {
406 if constexpr ( is_little_endian() ) {
407 return h;
408 } else if constexpr ( is_big_endian() ) {
409 return bswap(h);
410 } else {
411 return 0; // unreachable -> static_assert(..) above
412 }
413 }
414
415 constexpr uint32_t be_to_cpu(uint32_t const n) noexcept {
416 if constexpr ( is_little_endian() ) {
417 return bswap(n);
418 } else if constexpr ( is_big_endian() ) {
419 return n;
420 } else {
421 return 0; // unreachable -> static_assert(..) above
422 }
423 }
424 constexpr uint32_t cpu_to_be(uint32_t const h) noexcept {
425 if constexpr ( is_little_endian() ) {
426 return bswap(h);
427 } else if constexpr ( is_big_endian() ) {
428 return h;
429 } else {
430 return 0; // unreachable -> static_assert(..) above
431 }
432 }
433 constexpr uint32_t le_to_cpu(uint32_t const l) noexcept {
434 if constexpr ( is_little_endian() ) {
435 return l;
436 } else if constexpr ( is_big_endian() ) {
437 return bswap(l);
438 } else {
439 return 0; // unreachable -> static_assert(..) above
440 }
441 }
442 constexpr uint32_t cpu_to_le(uint32_t const h) noexcept {
443 if constexpr ( is_little_endian() ) {
444 return h;
445 } else if constexpr ( is_big_endian() ) {
446 return bswap(h);
447 } else {
448 return 0; // unreachable -> static_assert(..) above
449 }
450 }
451
452 constexpr uint64_t be_to_cpu(uint64_t const & n) noexcept {
453 if constexpr ( is_little_endian() ) {
454 return bswap(n);
455 } else if constexpr ( is_big_endian() ) {
456 return n;
457 } else {
458 return 0; // unreachable -> static_assert(..) above
459 }
460 }
461 constexpr uint64_t cpu_to_be(uint64_t const & h) noexcept {
462 if constexpr ( is_little_endian() ) {
463 return bswap(h);
464 } else if constexpr ( is_big_endian() ) {
465 return h;
466 } else {
467 return 0; // unreachable -> static_assert(..) above
468 }
469 }
470 constexpr uint64_t le_to_cpu(uint64_t const & l) noexcept {
471 if constexpr ( is_little_endian() ) {
472 return l;
473 } else if constexpr ( is_big_endian() ) {
474 return bswap(l);
475 } else {
476 return 0; // unreachable -> static_assert(..) above
477 }
478 }
479 constexpr uint64_t cpu_to_le(uint64_t const & h) noexcept {
480 if constexpr ( is_little_endian() ) {
481 return h;
482 } else if constexpr ( is_big_endian() ) {
483 return bswap(h);
484 } else {
485 return 0; // unreachable -> static_assert(..) above
486 }
487 }
488
489 constexpr uint128dp_t be_to_cpu(uint128dp_t const & n) noexcept {
490 if constexpr ( is_little_endian() ) {
491 return bswap(n);
492 } else if constexpr ( is_big_endian() ) {
493 return n;
494 } else {
495 return {}; // unreachable -> static_assert(..) above
496 }
497 }
498 constexpr uint128dp_t cpu_to_be(uint128dp_t const & h) noexcept {
499 if constexpr ( is_little_endian() ) {
500 return bswap(h);
501 } else if constexpr ( is_big_endian() ) {
502 return h;
503 } else {
504 return {}; // unreachable -> static_assert(..) above
505 }
506 }
507 constexpr uint128dp_t le_to_cpu(uint128dp_t const & l) noexcept {
508 if constexpr ( is_little_endian() ) {
509 return l;
510 } else if constexpr ( is_big_endian() ) {
511 return bswap(l);
512 } else {
513 return {}; // unreachable -> static_assert(..) above
514 }
515 }
516 constexpr uint128dp_t cpu_to_le(uint128dp_t const & h) noexcept {
517 if constexpr ( is_little_endian() ) {
518 return h;
519 } else if constexpr ( is_big_endian() ) {
520 return bswap(h);
521 } else {
522 return {}; // unreachable -> static_assert(..) above
523 }
524 }
525
526 constexpr uint192dp_t be_to_cpu(uint192dp_t const & n) noexcept {
527 if constexpr ( is_little_endian() ) {
528 return bswap(n);
529 } else if constexpr ( is_big_endian() ) {
530 return n;
531 } else {
532 return {}; // unreachable -> static_assert(..) above
533 }
534 }
535 constexpr uint192dp_t cpu_to_be(uint192dp_t const & h) noexcept {
536 if constexpr ( is_little_endian() ) {
537 return bswap(h);
538 } else if constexpr ( is_big_endian() ) {
539 return h;
540 } else {
541 return {}; // unreachable -> static_assert(..) above
542 }
543 }
544 constexpr uint192dp_t le_to_cpu(uint192dp_t const & l) noexcept {
545 if constexpr ( is_little_endian() ) {
546 return l;
547 } else if constexpr ( is_big_endian() ) {
548 return bswap(l);
549 } else {
550 return {}; // unreachable -> static_assert(..) above
551 }
552 }
553 constexpr uint192dp_t cpu_to_le(uint192dp_t const & h) noexcept {
554 if constexpr ( is_little_endian() ) {
555 return h;
556 } else if constexpr ( is_big_endian() ) {
557 return bswap(h);
558 } else {
559 return {}; // unreachable -> static_assert(..) above
560 }
561 }
562
563 constexpr uint256dp_t be_to_cpu(uint256dp_t const & n) noexcept {
564 if constexpr ( is_little_endian() ) {
565 return bswap(n);
566 } else if constexpr ( is_big_endian() ) {
567 return n;
568 } else {
569 return {}; // unreachable -> static_assert(..) above
570 }
571 }
572 constexpr uint256dp_t cpu_to_be(uint256dp_t const & h) noexcept {
573 if constexpr ( is_little_endian() ) {
574 return bswap(h);
575 } else if constexpr ( is_big_endian() ) {
576 return h;
577 } else {
578 return {}; // unreachable -> static_assert(..) above
579 }
580 }
581 constexpr uint256dp_t le_to_cpu(uint256dp_t const & l) noexcept {
582 if constexpr ( is_little_endian() ) {
583 return l;
584 } else if constexpr ( is_big_endian() ) {
585 return bswap(l);
586 } else {
587 return {}; // unreachable -> static_assert(..) above
588 }
589 }
590 constexpr uint256dp_t cpu_to_le(uint256dp_t const & h) noexcept {
591 if constexpr ( is_little_endian() ) {
592 return h;
593 } else if constexpr ( is_big_endian() ) {
594 return bswap(h);
595 } else {
596 return {}; // unreachable -> static_assert(..) above
597 }
598
599 }
600
601 /**
602 // *************************************************
603 // *************************************************
604 // *************************************************
605 */
606
607 constexpr void put_uint8(uint8_t * buffer, const uint8_t v) noexcept
608 {
609 *pointer_cast<uint8_t *>( buffer ) = v;
610 }
611 constexpr uint8_t get_uint8(uint8_t const * buffer) noexcept
612 {
613 return *pointer_cast<uint8_t const *>( buffer );
614 }
615 constexpr int8_t get_int8(uint8_t const * buffer) noexcept
616 {
617 return *pointer_cast<int8_t const *>( buffer );
618 }
619
620 /**
621 * Return packed_t::store after converting it to from either lb_endian::little or lb_endian::big depending on given `byte_order`
622 * to lb_endian::native.
623 * @tparam T
624 * @param source
625 * @param byte_order
626 */
627 template<typename T>
628 constexpr T get_packed_value(const packed_t<T>* source, const lb_endian_t byte_order) noexcept {
629 return is_little_endian(byte_order) ? le_to_cpu(source->store) : be_to_cpu(source->store);
630 }
631
632 /**
633 * Put the given uint16_t value into the given byte address
634 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
635 *
636 * @see \ref packed_t_alignment_cast
637 */
638 constexpr void put_uint16(uint8_t * buffer, const uint16_t v) noexcept
639 {
640 pointer_cast<packed_t<uint16_t>*>( buffer )->store = v;
641 }
642 /**
643 * Put the given uint16_t value into the given byte address
644 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
645 *
646 * The value is converted from lb_endian::native to either lb_endian::little or lb_endian::big depending on given `byte_order`
647 * before it is stored in memory.
648 *
649 * @see \ref packed_t_alignment_cast
650 */
651 constexpr void put_uint16(uint8_t * buffer, const uint16_t v, const lb_endian_t byte_order) noexcept
652 {
653 pointer_cast<packed_t<uint16_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
654 }
655 /**
656 * Returns a uint16_t value from the given byte address
657 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
658 *
659 * @see \ref packed_t_alignment_cast
660 */
661 constexpr uint16_t get_uint16(uint8_t const * buffer) noexcept
662 {
663 return pointer_cast<const packed_t<uint16_t>*>( buffer )->store;
664 }
665 /**
666 * Returns a uint16_t value from the given byte address
667 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
668 *
669 * The value is converted from either lb_endian::little or lb_endian::big depending on given `byte_order`
670 * to lb_endian::native before it is returned to the caller.
671 *
672 * @see \ref packed_t_alignment_cast
673 */
674 constexpr uint16_t get_uint16(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
675 {
676 return get_packed_value(pointer_cast<const packed_t<uint16_t>*>( buffer ), byte_order);
677 }
678
679 /**
680 * See put_uint16() for reference.
681 * @see \ref packed_t_alignment_cast
682 */
683 constexpr void put_uint32(uint8_t * buffer, const uint32_t v) noexcept
684 {
685 pointer_cast<packed_t<uint32_t>*>( buffer )->store = v;
686 }
687 /**
688 * See put_uint16() for reference.
689 * @see \ref packed_t_alignment_cast
690 */
691 constexpr void put_uint32(uint8_t * buffer, const uint32_t v, const lb_endian_t byte_order) noexcept
692 {
693 pointer_cast<packed_t<uint32_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
694 }
695 /**
696 * See get_uint16() for reference.
697 * @see \ref packed_t_alignment_cast
698 */
699 constexpr uint32_t get_uint32(uint8_t const * buffer) noexcept
700 {
701 return pointer_cast<const packed_t<uint32_t>*>( buffer )->store;
702 }
703 /**
704 * See get_uint16() for reference.
705 * @see \ref packed_t_alignment_cast
706 */
707 constexpr uint32_t get_uint32(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
708 {
709 return get_packed_value(pointer_cast<const packed_t<uint32_t>*>( buffer ), byte_order);
710 }
711
712 /**
713 * See put_uint16() for reference.
714 * @see \ref packed_t_alignment_cast
715 */
716 constexpr void put_uint64(uint8_t * buffer, const uint64_t & v) noexcept
717 {
718 pointer_cast<packed_t<uint64_t>*>( buffer )->store = v;
719 }
720 /**
721 * See put_uint16() for reference.
722 * @see \ref packed_t_alignment_cast
723 */
724 constexpr void put_uint64(uint8_t * buffer, const uint64_t & v, const lb_endian_t byte_order) noexcept
725 {
726 pointer_cast<packed_t<uint64_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
727 }
728 /**
729 * See get_uint16() for reference.
730 * @see \ref packed_t_alignment_cast
731 */
732 constexpr uint64_t get_uint64(uint8_t const * buffer) noexcept
733 {
734 return pointer_cast<const packed_t<uint64_t>*>( buffer )->store;
735 }
736 /**
737 * See get_uint16() for reference.
738 * @see \ref packed_t_alignment_cast
739 */
740 constexpr uint64_t get_uint64(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
741 {
742 return get_packed_value(pointer_cast<const packed_t<uint64_t>*>( buffer ), byte_order);
743 }
744
745 /**
746 * See put_uint16() for reference.
747 * @see \ref packed_t_alignment_cast
748 */
749 constexpr void put_uint128(uint8_t * buffer, const uint128dp_t & v) noexcept
750 {
751 pointer_cast<packed_t<uint128dp_t>*>( buffer )->store = v;
752 }
753 /**
754 * See put_uint16() for reference.
755 * @see \ref packed_t_alignment_cast
756 */
757 constexpr void put_uint128(uint8_t * buffer, const uint128dp_t & v, const lb_endian_t byte_order) noexcept
758 {
759 pointer_cast<packed_t<uint128dp_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
760 }
761 /**
762 * See get_uint16() for reference.
763 * @see \ref packed_t_alignment_cast
764 */
765 constexpr uint128dp_t get_uint128(uint8_t const * buffer) noexcept
766 {
767 return pointer_cast<const packed_t<uint128dp_t>*>( buffer )->store;
768 }
769 /**
770 * See get_uint16() for reference.
771 * @see \ref packed_t_alignment_cast
772 */
773 constexpr uint128dp_t get_uint128(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
774 {
775 return get_packed_value(pointer_cast<const packed_t<uint128dp_t>*>( buffer ), byte_order);
776 }
777
778 /**
779 * See put_uint16() for reference.
780 * @see \ref packed_t_alignment_cast
781 */
782 constexpr void put_uint192(uint8_t * buffer, const uint192dp_t & v) noexcept
783 {
784 pointer_cast<packed_t<uint192dp_t>*>( buffer )->store = v;
785 }
786 /**
787 * See put_uint16() for reference.
788 * @see \ref packed_t_alignment_cast
789 */
790 constexpr void put_uint192(uint8_t * buffer, const uint192dp_t & v, const lb_endian_t byte_order) noexcept
791 {
792 pointer_cast<packed_t<uint192dp_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
793 }
794 /**
795 * See get_uint16() for reference.
796 * @see \ref packed_t_alignment_cast
797 */
798 constexpr uint192dp_t get_uint192(uint8_t const * buffer) noexcept
799 {
800 return pointer_cast<const packed_t<uint192dp_t>*>( buffer )->store;
801 }
802 /**
803 * See get_uint16() for reference.
804 * @see \ref packed_t_alignment_cast
805 */
806 constexpr uint192dp_t get_uint192(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
807 {
808 return get_packed_value(pointer_cast<const packed_t<uint192dp_t>*>( buffer ), byte_order);
809 }
810
811 /**
812 * See put_uint16() for reference.
813 * @see \ref packed_t_alignment_cast
814 */
815 constexpr void put_uint256(uint8_t * buffer, const uint256dp_t & v) noexcept
816 {
817 pointer_cast<packed_t<uint256dp_t>*>( buffer )->store = v;
818 }
819 /**
820 * See put_uint16() for reference.
821 * @see \ref packed_t_alignment_cast
822 */
823 constexpr void put_uint256(uint8_t * buffer, const uint256dp_t & v, const lb_endian_t byte_order) noexcept
824 {
825 pointer_cast<packed_t<uint256dp_t>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
826 }
827 /**
828 * See get_uint16() for reference.
829 * @see \ref packed_t_alignment_cast
830 */
831 constexpr uint256dp_t get_uint256(uint8_t const * buffer) noexcept
832 {
833 return pointer_cast<const packed_t<uint256dp_t>*>( buffer )->store;
834 }
835 /**
836 * See get_uint16() for reference.
837 * @see \ref packed_t_alignment_cast
838 */
839 constexpr uint256dp_t get_uint256(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
840 {
841 return get_packed_value(pointer_cast<const packed_t<uint256dp_t>*>( buffer ), byte_order);
842 }
843
844 /**
845 // *************************************************
846 // *************************************************
847 // *************************************************
848 */
849
850 /**
851 * Put the given T value into the given byte address
852 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
853 *
854 * @tparam T
855 * @param buffer
856 * @param v
857 * @see \ref packed_t_alignment_cast
858 */
859 template<typename T>
860 constexpr
861 typename std::enable_if_t<
862 std::is_standard_layout_v<T>,
863 void>
864 put_value(uint8_t * buffer, const T& v) noexcept
865 {
866 // reinterpret_cast<packed_t<T>*>( buffer )->store = v;
867 pointer_cast<packed_t<T>*>( buffer )->store = v;
868 }
869
870 /**
871 * Put the given T value into the given byte address
872 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
873 *
874 * The value is converted from lb_endian::native to either lb_endian::little or lb_endian::big depending on given `byte_order`
875 * before it is stored in memory.
876 *
877 * @tparam T
878 * @param buffer
879 * @param v
880 * @param byte_order
881 * @see \ref packed_t_alignment_cast
882 */
883 template<typename T>
884 constexpr
885 typename std::enable_if_t<
886 std::is_standard_layout_v<T>,
887 void>
888 put_value(uint8_t * buffer, const T& v, const lb_endian_t byte_order) noexcept
889 {
890 pointer_cast<packed_t<T>*>( buffer )->store = is_little_endian(byte_order) ? cpu_to_le(v) : cpu_to_be(v);
891 }
892
893 /**
894 * Returns a T value from the given byte address
895 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
896 *
897 * @tparam T
898 * @param buffer
899 * @return
900 * @see \ref packed_t_alignment_cast
901 */
902 template<typename T>
903 constexpr
904 typename std::enable_if_t<
905 std::is_standard_layout_v<T>,
906 T>
907 get_value(uint8_t const * buffer) noexcept
908 {
909 return pointer_cast<const packed_t<T>*>( buffer )->store;
910 }
911
912 /**
913 * Returns a T value from the given byte address
914 * using \ref packed_t to resolve a potential memory alignment issue *free of costs*.
915 *
916 * The value is converted from either lb_endian::little or lb_endian::big depending on given `byte_order`
917 * to lb_endian::native before it is returned to the caller.
918 *
919 * @tparam T
920 * @param buffer
921 * @param byte_order
922 * @return
923 * @see \ref packed_t_alignment_cast
924 */
925 template<typename T>
926 constexpr
927 typename std::enable_if_t<
928 std::is_standard_layout_v<T>,
929 T>
930 get_value(uint8_t const * buffer, const lb_endian_t byte_order) noexcept
931 {
932 return get_packed_value(pointer_cast<const packed_t<T>*>( buffer ), byte_order);
933 }
934
935 /**@}*/
936
937} // namespace jau
938
939/** \example test_basictypeconv.cpp
940 * This C++ unit test validates the jau::bswap and get/set value implementation
941 */
942
943#endif /* JAU_BYTE_UTIL_HPP_ */
constexpr uint192dp_t get_uint192(uint8_t const *buffer) noexcept
See get_uint16() for reference.
Definition: byte_util.hpp:798
constexpr bool has_endian_big_v
Value access of big-endian type trait for convenience .
Definition: byte_util.hpp:366
constexpr uint128dp_t get_uint128(uint8_t const *buffer) noexcept
See get_uint16() for reference.
Definition: byte_util.hpp:765
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...
Definition: byte_util.hpp:628
constexpr bool is_big_endian() noexcept
Evaluates true if platform is running in big endian mode, i.e.
Definition: byte_util.hpp:316
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 ...
Definition: byte_util.hpp:907
constexpr void put_uint256(uint8_t *buffer, const uint256dp_t &v) noexcept
See put_uint16() for reference.
Definition: byte_util.hpp:815
constexpr bool is_defined_endian(const endian_t &v) noexcept
Evaluates true if the given endian is defined, i.e.
Definition: byte_util.hpp:275
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...
Definition: byte_util.hpp:661
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.
Definition: byte_util.hpp:324
constexpr uint16_t cpu_to_be(uint16_t const h) noexcept
Definition: byte_util.hpp:387
constexpr endian_t to_endian(const lb_endian_t v) noexcept
Definition: byte_util.hpp:261
constexpr uint32_t get_uint32(uint8_t const *buffer) noexcept
See get_uint16() for reference.
Definition: byte_util.hpp:699
char * cast_uint8_ptr_to_char(uint8_t *b) noexcept
Definition: byte_util.hpp:148
constexpr void put_uint32(uint8_t *buffer, const uint32_t v) noexcept
See put_uint16() for reference.
Definition: byte_util.hpp:683
endian_t
Endian identifier, indicating endianess of all scalar types.
Definition: byte_util.hpp:203
constexpr uint256dp_t get_uint256(uint8_t const *buffer) noexcept
See get_uint16() for reference.
Definition: byte_util.hpp:831
constexpr void put_uint192(uint8_t *buffer, const uint192dp_t &v) noexcept
See put_uint16() for reference.
Definition: byte_util.hpp:782
constexpr bool has_endian_little_v
Value access of little-endian type trait for convenience .
Definition: byte_util.hpp:346
constexpr uint16_t le_to_cpu(uint16_t const l) noexcept
Definition: byte_util.hpp:396
constexpr void put_uint8(uint8_t *buffer, const uint8_t v) noexcept
Definition: byte_util.hpp:607
lb_endian_t
Simplified reduced endian type only covering little- and big-endian.
Definition: byte_util.hpp:227
std::string to_string(const endian_t v) noexcept
Return std::string representation of the given endian.
constexpr void put_uint64(uint8_t *buffer, const uint64_t &v) noexcept
See put_uint16() for reference.
Definition: byte_util.hpp:716
constexpr bool is_little_endian(const endian_t byte_order) noexcept
Returns true if given byte_order equals endian::little, otherwise false.
Definition: byte_util.hpp:293
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...
Definition: byte_util.hpp:638
constexpr uint16_t be_to_cpu(uint16_t const n) noexcept
Definition: byte_util.hpp:378
constexpr void put_uint128(uint8_t *buffer, const uint128dp_t &v) noexcept
See put_uint16() for reference.
Definition: byte_util.hpp:749
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...
Definition: byte_util.hpp:864
constexpr lb_endian_t to_lb_endian(const endian_t v) noexcept
Definition: byte_util.hpp:252
constexpr uint16_t cpu_to_le(uint16_t const h) noexcept
Definition: byte_util.hpp:405
constexpr uint64_t get_uint64(uint8_t const *buffer) noexcept
See get_uint16() for reference.
Definition: byte_util.hpp:732
constexpr int8_t get_int8(uint8_t const *buffer) noexcept
Definition: byte_util.hpp:615
constexpr uint8_t get_uint8(uint8_t const *buffer) noexcept
Definition: byte_util.hpp:611
const uint8_t * cast_char_ptr_to_uint8(const char *s) noexcept
Definition: byte_util.hpp:155
@ 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.
#define PRAGMA_DISABLE_WARNING_PUSH
Definition: cpp_pragma.hpp:76
#define PRAGMA_DISABLE_WARNING_MULTICHAR
Definition: cpp_pragma.hpp:81
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).
consteval_cxx20 bool is_builtin_bit_cast_available() noexcept
Query whether __builtin_bit_cast(Dest_type, arg) is available, using jau::has_builtin_bit_cast.
#define PRAGMA_DISABLE_WARNING_POP
Definition: cpp_pragma.hpp:77
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
Definition: int_types.hpp:53
constexpr uint32_t get_host_order() noexcept
Definition: byte_util.hpp:169
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Definition: backtrace.hpp:32
A big-endian type trait for convenience .
Definition: byte_util.hpp:356
A little-endian type trait for convenience .
Definition: byte_util.hpp:336
Support aligned memory transfer from and to potentially unaligned memory.
A 128-bit packed uint8_t data array.
Definition: int_types.hpp:114
uint8_t data[16]
Definition: int_types.hpp:114
A 196-bit packed uint8_t data array.
Definition: int_types.hpp:136
uint8_t data[24]
Definition: int_types.hpp:136
A 256-bit packed uint8_t data array.
Definition: int_types.hpp:158
uint8_t data[32]
Definition: int_types.hpp:158