Direct-BT  2.3.1
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 Gothel Software e.K.
4  * Copyright (c) 2020 ZAFENA AB
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 
26 #ifndef JAU_BYTE_UTIL_HPP_
27 #define JAU_BYTE_UTIL_HPP_
28 
29 #include <cstring>
30 #include <string>
31 #include <memory>
32 #include <cstdint>
33 #include <vector>
34 #include <type_traits>
35 
36 #include <jau/cpp_lang_util.hpp>
37 #include <jau/cpp_pragma.hpp>
38 #include <jau/packed_attribute.hpp>
39 
40 #include <jau/int_types.hpp>
41 
42 namespace jau {
43 
44  #if defined __has_builtin
45  #if __has_builtin(__builtin_bswap16)
46  #define __has_builtin_bswap16 1
47  #endif
48  #elif defined(__GNUC__) && __GNUC_PREREQ (4, 8)
49  #define __has_builtin_bswap16 1
50  #endif
51  #if defined __has_builtin
52  #if __has_builtin(__builtin_bswap32)
53  #define __has_builtin_bswap32 1
54  #endif
55  #elif defined(__GNUC__) && __GNUC_PREREQ (4, 8)
56  #define __has_builtin_bswap32 1
57  #endif
58  #if defined __has_builtin
59  #if __has_builtin(__builtin_bswap64)
60  #define __has_builtin_bswap64 1
61  #endif
62  #elif defined(__GNUC__) && __GNUC_PREREQ (4, 8)
63  #define __has_builtin_bswap64 1
64  #endif
65 
66  constexpr uint16_t bswap(uint16_t const source) noexcept {
67  #if defined __has_builtin_bswap16
68  return __builtin_bswap16(source);
69  #else
70  return (uint16_t) ( ( ( (source) >> 8 ) & 0xff ) |
71  ( ( (source) & 0xff) << 8 ) );
72  #endif
73  }
74 
75  constexpr uint32_t bswap(uint32_t const source) noexcept {
76  #if defined __has_builtin_bswap32
77  return __builtin_bswap32(source);
78  #else
79  return ( ( source & 0xff000000U ) >> 24 ) |
80  ( ( source & 0x00ff0000U ) >> 8 ) |
81  ( ( source & 0x0000ff00U ) << 8 ) |
82  ( ( source & 0x000000ffU ) << 24 );
83  #endif
84  }
85 
86  constexpr uint64_t bswap(uint64_t const & source) noexcept {
87  #if defined __has_builtin_bswap64
88  return __builtin_bswap64(source);
89  #else
90  return ( ( source & 0xff00000000000000ULL ) >> 56 ) |
91  ( ( source & 0x00ff000000000000ULL ) >> 40 ) |
92  ( ( source & 0x0000ff0000000000ULL ) >> 24 ) |
93  ( ( source & 0x000000ff00000000ULL ) >> 8 ) |
94  ( ( source & 0x00000000ff000000ULL ) << 8 ) |
95  ( ( source & 0x0000000000ff0000ULL ) << 24 ) |
96  ( ( source & 0x000000000000ff00ULL ) << 40 ) |
97  ( ( source & 0x00000000000000ffULL ) << 56 );
98  #endif
99  }
100 
101  constexpr uint128_t bswap(uint128_t const & source) noexcept {
102  uint128_t dest;
103  uint8_t const * const s = source.data;
104  uint8_t * const d = dest.data;
105  for(nsize_t i=0; i<16; i++) {
106  d[i] = s[15-i];
107  }
108  return dest;
109  }
110 
111  constexpr uint192_t bswap(uint192_t const & source) noexcept {
112  uint192_t dest;
113  uint8_t const * const s = source.data;
114  uint8_t * const d = dest.data;
115  for(nsize_t i=0; i<24; i++) {
116  d[i] = s[23-i];
117  }
118  return dest;
119  }
120 
121  constexpr uint256_t bswap(uint256_t const & source) noexcept {
122  uint256_t dest;
123  uint8_t const * const s = source.data;
124  uint8_t * const d = dest.data;
125  for(nsize_t i=0; i<32; i++) {
126  d[i] = s[31-i];
127  }
128  return dest;
129  }
130 
131  /**
132  // *************************************************
133  // *************************************************
134  // *************************************************
135  */
136 
137  // The pragma to stop multichar warning == error `-Werror=multichar` doesn't seem to work with GCC <= 10.2
138  // Hence we have to disable this specific warning via: `-Wno-multichar`
139  // until all our compiler support `__builtin_bit_cast(T, a)`
140 
143 
144  namespace impl {
145  constexpr uint32_t get_host_order() noexcept {
147  constexpr uint8_t b[4] { 0x44, 0x43, 0x42, 0x41 }; // h->l: 41 42 43 44 = 'ABCD' hex ASCII code
148  return jau::bit_cast<uint32_t, uint8_t[4]>( b );
149  } else {
150  return 'ABCD'; // h->l: 41 42 43 44 = 'ABCD' hex ASCII code
151  }
152  }
153  }
154 
155  /**
156  * Endian identifier, indicating endianess of all scaler types.
157  * <p>
158  * Inspired by C++20 std::endian
159  * </p>
160  * <p>
161  * Corner case platforms currently not supported,
162  * i.e. unified endianess and mixed endianess.
163  * </p>
164  * <p>
165  * All endian API entries are of `constexpr` and hence evaluated at compile time.<br>
166  * Therefore, if-branches and expressions are also of `constexpr` and optimized 'away' at compile time.<br>
167  * This includes the `cpu_to_<endian>(..)` and `<endian>_to_cpu(..)` etc utility functions.
168  * </p>
169  */
170  enum class endian : uint32_t
171  {
172  /** Identifier for little endian. */
173  little = 0x41424344U, // h->l: 41 42 43 44 = 'ABCD' hex ASCII code
174 
175  /** Identifier for big endian. */
176  big = 0x44434241U, // h->l: 44 43 42 41 = 'DCBA' hex ASCII code
177 
178  /** Identifier for DEC PDP-11, aka `ENDIAN_LITTLE_WORD`. */
179  pdp = 0x43444142U, // h->l: 43 44 41 42 = 'CDAB' hex ASCII code
180 
181  /** Identifier for Honeywell 316, aka `ENDIAN_BIG_WORD`. */
182  honeywell = 0x42414443U, // h->l: 42 41 44 43 = 'BADC' hex ASCII code
183 
184  /** Undetermined endian */
185  undefined = 0x00000000U,
186 
187  /** Identifier for native platform type, one of the above. */
189  };
190 
192 
193  /**
194  * Return std::string representation of the given jau::endian.
195  * @param v the jau::endian value
196  * @return the std::string representation
197  */
198  constexpr_cxx20 std::string to_string(const endian& v) noexcept {
199  switch(v) {
200  case endian::little: return "little";
201  case endian::big: return "big";
202  case endian::pdp: return "pdb";
203  case endian::honeywell: return "honeywell";
204  case endian::undefined: return "undefined";
205  }
206  return "unlisted";
207  }
208 
209  /**
210  * Evaluates `true` if the given endian is defined,
211  * i.e. `little`, `big`, `pdp` or `honeywell`.
212  */
213  constexpr bool isDefinedEndian(const endian &v) noexcept {
214  switch(v) {
215  case endian::little:
216  [[fallthrough]];
217  case endian::big:
218  [[fallthrough]];
219  case endian::pdp:
220  [[fallthrough]];
221  case endian::honeywell:
222  return true;
223  default:
224  return false;
225  }
226  }
227 
228  /**
229  * Evaluates `true` if platform is running in little endian mode,
230  * i.e. `jau::endian::little == jau::endian::native`.
231  */
232  constexpr bool isLittleEndian() noexcept {
233  return endian::little == endian::native;
234  }
235 
236  /**
237  * Evaluates `true` if platform is running in big endian mode,
238  * i.e. `jau::endian::big == jau::endian::native`.
239  */
240  constexpr bool isBigEndian() noexcept {
241  return endian::big == endian::native;
242  }
243 
244  /**
245  * Evaluates `true` if platform is running in little or big endian mode,
246  * i.e. `jau::endian::little == jau::endian::native || jau::endian::big == jau::endian::native`.
247  */
248  constexpr bool isLittleOrBigEndian() noexcept {
250  }
251 
252  /**
253  * A little-endian type trait for convenience ..
254  * <p>
255  * Since all endian definitions are of `constexpr`, code can simply use expressions of these
256  * for compile-time evaluation and optimization. A template `SFINAE` is not required.
257  * </p>
258  * @tparam Dummy_type just to make template `SFINAE` happy
259  */
260  template <typename Dummy_type> struct has_endian_little : std::integral_constant<bool, endian::little == endian::native> {};
261 
262  /**
263  * Value access of little-endian type trait for convenience ..
264  * <p>
265  * Since all endian definitions are of `constexpr`, code can simply use expressions of these
266  * for compile-time evaluation and optimization. A template `SFINAE` is not required.
267  * </p>
268  * @tparam Dummy_type just to make template `SFINAE` happy
269  */
270  template <typename Dummy_type> constexpr bool has_endian_little_v = has_endian_little<Dummy_type>::value;
271 
272  /**
273  * A big-endian type trait for convenience ..
274  * <p>
275  * Since all endian definitions are of `constexpr`, code can simply use expressions of these
276  * for compile-time evaluation and optimization. A template `SFINAE` is not required.
277  * </p>
278  * @tparam Dummy_type just to make template `SFINAE` happy
279  */
280  template <typename Dummy_type> struct has_endian_big : std::integral_constant<bool, endian::big == endian::native> {};
281 
282  /**
283  * Value access of big-endian type trait for convenience ..
284  * <p>
285  * Since all endian definitions are of `constexpr`, code can simply use expressions of these
286  * for compile-time evaluation and optimization. A template `SFINAE` is not required.
287  * </p>
288  * @tparam Dummy_type just to make template `SFINAE` happy
289  */
290  template <typename Dummy_type> constexpr bool has_endian_big_v = has_endian_big<Dummy_type>::value;
291 
292  /**
293  // *************************************************
294  // *************************************************
295  // *************************************************
296  */
297 
298  /**
299  * On the i386 the host byte order is Least Significant Byte first (LSB) or Little-Endian,
300  * whereas the network byte order, as used on the Internet, is Most Significant Byte first (MSB) or Big-Endian.
301  * See #include <arpa/inet.h>
302  *
303  * Bluetooth is LSB or Little-Endian!
304  */
305 
306  constexpr uint16_t be_to_cpu(uint16_t const n) noexcept {
307  static_assert(isLittleOrBigEndian()); // one static_assert is sufficient for whole compilation unit
308  if( isLittleEndian() ) {
309  return bswap(n);
310  } else if( isBigEndian() ) {
311  return bswap(n);
312  } else {
313  return 0; // unreachable -> static_assert(..) above
314  }
315  }
316  constexpr uint16_t cpu_to_be(uint16_t const h) noexcept {
317  if( isLittleEndian() ) {
318  return bswap(h);
319  } else if( isBigEndian() ) {
320  return h;
321  } else {
322  return 0; // unreachable -> static_assert(..) above
323  }
324  }
325  constexpr uint16_t le_to_cpu(uint16_t const l) noexcept {
326  if( isLittleEndian() ) {
327  return l;
328  } else if( isBigEndian() ) {
329  return bswap(l);
330  } else {
331  return 0; // unreachable -> static_assert(..) above
332  }
333  }
334  constexpr uint16_t cpu_to_le(uint16_t const h) noexcept {
335  if( isLittleEndian() ) {
336  return h;
337  } else if( isBigEndian() ) {
338  return bswap(h);
339  } else {
340  return 0; // unreachable -> static_assert(..) above
341  }
342  }
343 
344  constexpr uint32_t be_to_cpu(uint32_t const n) noexcept {
345  if( isLittleEndian() ) {
346  return bswap(n);
347  } else if( isBigEndian() ) {
348  return n;
349  } else {
350  return 0; // unreachable -> static_assert(..) above
351  }
352  }
353  constexpr uint32_t cpu_to_be(uint32_t const h) noexcept {
354  if( isLittleEndian() ) {
355  return bswap(h);
356  } else if( isBigEndian() ) {
357  return h;
358  } else {
359  return 0; // unreachable -> static_assert(..) above
360  }
361  }
362  constexpr uint32_t le_to_cpu(uint32_t const l) noexcept {
363  if( isLittleEndian() ) {
364  return l;
365  } else if( isBigEndian() ) {
366  return bswap(l);
367  } else {
368  return 0; // unreachable -> static_assert(..) above
369  }
370  }
371  constexpr uint32_t cpu_to_le(uint32_t const h) noexcept {
372  if( isLittleEndian() ) {
373  return h;
374  } else if( isBigEndian() ) {
375  return bswap(h);
376  } else {
377  return 0; // unreachable -> static_assert(..) above
378  }
379  }
380 
381  constexpr uint64_t be_to_cpu(uint64_t const & n) noexcept {
382  if( isLittleEndian() ) {
383  return bswap(n);
384  } else if( isBigEndian() ) {
385  return n;
386  } else {
387  return 0; // unreachable -> static_assert(..) above
388  }
389  }
390  constexpr uint64_t cpu_to_be(uint64_t const & h) noexcept {
391  if( isLittleEndian() ) {
392  return bswap(h);
393  } else if( isBigEndian() ) {
394  return h;
395  } else {
396  return 0; // unreachable -> static_assert(..) above
397  }
398  }
399  constexpr uint64_t le_to_cpu(uint64_t const & l) noexcept {
400  if( isLittleEndian() ) {
401  return l;
402  } else if( isBigEndian() ) {
403  return bswap(l);
404  } else {
405  return 0; // unreachable -> static_assert(..) above
406  }
407  }
408  constexpr uint64_t cpu_to_le(uint64_t const & h) noexcept {
409  if( isLittleEndian() ) {
410  return h;
411  } else if( isBigEndian() ) {
412  return bswap(h);
413  } else {
414  return 0; // unreachable -> static_assert(..) above
415  }
416  }
417 
418  constexpr uint128_t be_to_cpu(uint128_t const & n) noexcept {
419  if( isLittleEndian() ) {
420  return bswap(n);
421  } else if( isBigEndian() ) {
422  return n;
423  } else {
424  return uint128_t(); // unreachable -> static_assert(..) above
425  }
426  }
427  constexpr uint128_t cpu_to_be(uint128_t const & h) noexcept {
428  if( isLittleEndian() ) {
429  return bswap(h);
430  } else if( isBigEndian() ) {
431  return h;
432  } else {
433  return uint128_t(); // unreachable -> static_assert(..) above
434  }
435  }
436  constexpr uint128_t le_to_cpu(uint128_t const & l) noexcept {
437  if( isLittleEndian() ) {
438  return l;
439  } else if( isBigEndian() ) {
440  return bswap(l);
441  } else {
442  return uint128_t(); // unreachable -> static_assert(..) above
443  }
444  }
445  constexpr uint128_t cpu_to_le(uint128_t const & h) noexcept {
446  if( isLittleEndian() ) {
447  return h;
448  } else if( isBigEndian() ) {
449  return bswap(h);
450  } else {
451  return uint128_t(); // unreachable -> static_assert(..) above
452  }
453  }
454 
455  constexpr uint192_t be_to_cpu(uint192_t const & n) noexcept {
456  if( isLittleEndian() ) {
457  return bswap(n);
458  } else if( isBigEndian() ) {
459  return n;
460  } else {
461  return uint192_t(); // unreachable -> static_assert(..) above
462  }
463  }
464  constexpr uint192_t cpu_to_be(uint192_t const & h) noexcept {
465  if( isLittleEndian() ) {
466  return bswap(h);
467  } else if( isBigEndian() ) {
468  return h;
469  } else {
470  return uint192_t(); // unreachable -> static_assert(..) above
471  }
472  }
473  constexpr uint192_t le_to_cpu(uint192_t const & l) noexcept {
474  if( isLittleEndian() ) {
475  return l;
476  } else if( isBigEndian() ) {
477  return bswap(l);
478  } else {
479  return uint192_t(); // unreachable -> static_assert(..) above
480  }
481  }
482  constexpr uint192_t cpu_to_le(uint192_t const & h) noexcept {
483  if( isLittleEndian() ) {
484  return h;
485  } else if( isBigEndian() ) {
486  return bswap(h);
487  } else {
488  return uint192_t(); // unreachable -> static_assert(..) above
489  }
490  }
491 
492  constexpr uint256_t be_to_cpu(uint256_t const & n) noexcept {
493  if( isLittleEndian() ) {
494  return bswap(n);
495  } else if( isBigEndian() ) {
496  return n;
497  } else {
498  return uint256_t(); // unreachable -> static_assert(..) above
499  }
500  }
501  constexpr uint256_t cpu_to_be(uint256_t const & h) noexcept {
502  if( isLittleEndian() ) {
503  return bswap(h);
504  } else if( isBigEndian() ) {
505  return h;
506  } else {
507  return uint256_t(); // unreachable -> static_assert(..) above
508  }
509  }
510  constexpr uint256_t le_to_cpu(uint256_t const & l) noexcept {
511  if( isLittleEndian() ) {
512  return l;
513  } else if( isBigEndian() ) {
514  return bswap(l);
515  } else {
516  return uint256_t(); // unreachable -> static_assert(..) above
517  }
518  }
519  constexpr uint256_t cpu_to_le(uint256_t const & h) noexcept {
520  if( isLittleEndian() ) {
521  return h;
522  } else if( isBigEndian() ) {
523  return bswap(h);
524  } else {
525  return uint256_t(); // unreachable -> static_assert(..) above
526  }
527 
528  }
529 
530  /**
531  // *************************************************
532  // *************************************************
533  // *************************************************
534  */
535 
536  constexpr void put_uint8(uint8_t * buffer, nsize_t const byte_offset, const uint8_t v) noexcept
537  {
538  *pointer_cast<uint8_t *>( buffer + byte_offset ) = v;
539  }
540  constexpr uint8_t get_uint8(uint8_t const * buffer, nsize_t const byte_offset) noexcept
541  {
542  return *pointer_cast<uint8_t const *>( buffer + byte_offset );
543  }
544  constexpr int8_t get_int8(uint8_t const * buffer, nsize_t const byte_offset) noexcept
545  {
546  return *pointer_cast<int8_t const *>( buffer + byte_offset );
547  }
548 
549  /**
550  * Safe access to a pointer cast from unaligned memory via __packed__ attribute,
551  * i.e. utilizing compiler generated safe load and store operations.
552  * <p>
553  * This template shall cause no costs, the cast data pointer is identical to 'T & p = &store'.
554  * </p>
555  */
556  template<typename T> __pack ( struct packed_t {
557  T store;
558  constexpr T get(const bool littleEndian) const noexcept { return littleEndian ? le_to_cpu(store) : be_to_cpu(store); }
559  } ) ;
560 
561  constexpr void put_uint16(uint8_t * buffer, nsize_t const byte_offset, const uint16_t v) noexcept
562  {
563  /**
564  * Handle potentially misaligned address of buffer + byte_offset, can't just
565  * uint16_t * p = (uint16_t *) ( buffer + byte_offset );
566  * *p = v;
567  * Universal alternative using memcpy is costly:
568  * memcpy(buffer + byte_offset, &v, sizeof(v));
569  * Use compiler magic 'struct __attribute__((__packed__))' access:
570  */
571  pointer_cast<packed_t<uint16_t>*>( buffer + byte_offset )->store = v;
572  }
573  constexpr void put_uint16(uint8_t * buffer, nsize_t const byte_offset, const uint16_t v, const bool littleEndian) noexcept
574  {
575  /**
576  * Handle potentially misaligned address of buffer + byte_offset, can't just
577  * uint16_t * p = (uint16_t *) ( buffer + byte_offset );
578  * *p = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
579  * Universal alternative using memcpy is costly:
580  * const uint16_t v2 = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
581  * memcpy(buffer + byte_offset, &v2, sizeof(v2));
582  * Use compiler magic 'struct __attribute__((__packed__))' access:
583  */
584  pointer_cast<packed_t<uint16_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
585  }
586  constexpr uint16_t get_uint16(uint8_t const * buffer, nsize_t const byte_offset) noexcept
587  {
588  /**
589  * Handle potentially misaligned address of buffer + byte_offset, can't just
590  * uint16_t const * p = (uint16_t const *) ( buffer + byte_offset );
591  * return *p;
592  * Universal alternative using memcpy is costly:
593  * uint16_t v;
594  * memcpy(&v, buffer + byte_offset, sizeof(v));
595  * return v;
596  * Use compiler magic 'struct __attribute__((__packed__))' access:
597  */
598  return pointer_cast<const packed_t<uint16_t>*>( buffer + byte_offset )->store;
599  }
600  constexpr uint16_t get_uint16(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
601  {
602  /**
603  * Handle potentially misaligned address of buffer + byte_offset, can't just
604  * uint16_t const * p = (uint16_t const *) ( buffer + byte_offset );
605  * return littleEndian ? le_to_cpu(*p) : be_to_cpu(*p);
606  * Universal alternative using memcpy is costly:
607  * uint16_t v;
608  * memcpy(&v, buffer + byte_offset, sizeof(v));
609  * return littleEndian ? le_to_cpu(v) : be_to_cpu(v);
610  * Use compiler magic 'struct __attribute__((__packed__))' access:
611  */
612  return pointer_cast<const packed_t<uint16_t>*>( buffer + byte_offset )->get(littleEndian);
613  }
614 
615  constexpr void put_uint32(uint8_t * buffer, nsize_t const byte_offset, const uint32_t v) noexcept
616  {
617  pointer_cast<packed_t<uint32_t>*>( buffer + byte_offset )->store = v;
618  }
619  constexpr void put_uint32(uint8_t * buffer, nsize_t const byte_offset, const uint32_t v, const bool littleEndian) noexcept
620  {
621  pointer_cast<packed_t<uint32_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
622  }
623  constexpr uint32_t get_uint32(uint8_t const * buffer, nsize_t const byte_offset) noexcept
624  {
625  return pointer_cast<const packed_t<uint32_t>*>( buffer + byte_offset )->store;
626  }
627  constexpr uint32_t get_uint32(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
628  {
629  return pointer_cast<const packed_t<uint32_t>*>( buffer + byte_offset )->get(littleEndian);
630  }
631 
632  constexpr void put_uint64(uint8_t * buffer, nsize_t const byte_offset, const uint64_t & v) noexcept
633  {
634  pointer_cast<packed_t<uint64_t>*>( buffer + byte_offset )->store = v;
635  }
636  constexpr void put_uint64(uint8_t * buffer, nsize_t const byte_offset, const uint64_t & v, const bool littleEndian) noexcept
637  {
638  pointer_cast<packed_t<uint64_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
639  }
640  constexpr uint64_t get_uint64(uint8_t const * buffer, nsize_t const byte_offset) noexcept
641  {
642  return pointer_cast<const packed_t<uint64_t>*>( buffer + byte_offset )->store;
643  }
644  constexpr uint64_t get_uint64(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
645  {
646  return pointer_cast<const packed_t<uint64_t>*>( buffer + byte_offset )->get(littleEndian);
647  }
648 
649  constexpr void put_uint128(uint8_t * buffer, nsize_t const byte_offset, const uint128_t & v) noexcept
650  {
651  pointer_cast<packed_t<uint128_t>*>( buffer + byte_offset )->store = v;
652  }
653  constexpr void put_uint128(uint8_t * buffer, nsize_t const byte_offset, const uint128_t & v, const bool littleEndian) noexcept
654  {
655  pointer_cast<packed_t<uint128_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
656  }
657  constexpr uint128_t get_uint128(uint8_t const * buffer, nsize_t const byte_offset) noexcept
658  {
659  return pointer_cast<const packed_t<uint128_t>*>( buffer + byte_offset )->store;
660  }
661  constexpr uint128_t get_uint128(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
662  {
663  return pointer_cast<const packed_t<uint128_t>*>( buffer + byte_offset )->get(littleEndian);
664  }
665 
666  constexpr void put_uint192(uint8_t * buffer, nsize_t const byte_offset, const uint192_t & v) noexcept
667  {
668  pointer_cast<packed_t<uint192_t>*>( buffer + byte_offset )->store = v;
669  }
670  constexpr void put_uint192(uint8_t * buffer, nsize_t const byte_offset, const uint192_t & v, const bool littleEndian) noexcept
671  {
672  pointer_cast<packed_t<uint192_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
673  }
674  constexpr uint192_t get_uint192(uint8_t const * buffer, nsize_t const byte_offset) noexcept
675  {
676  return pointer_cast<const packed_t<uint192_t>*>( buffer + byte_offset )->store;
677  }
678  constexpr uint192_t get_uint192(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
679  {
680  return pointer_cast<const packed_t<uint192_t>*>( buffer + byte_offset )->get(littleEndian);
681  }
682 
683  constexpr void put_uint256(uint8_t * buffer, nsize_t const byte_offset, const uint256_t & v) noexcept
684  {
685  pointer_cast<packed_t<uint256_t>*>( buffer + byte_offset )->store = v;
686  }
687  constexpr void put_uint256(uint8_t * buffer, nsize_t const byte_offset, const uint256_t & v, const bool littleEndian) noexcept
688  {
689  pointer_cast<packed_t<uint256_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
690  }
691  constexpr uint256_t get_uint256(uint8_t const * buffer, nsize_t const byte_offset) noexcept
692  {
693  return pointer_cast<const packed_t<uint256_t>*>( buffer + byte_offset )->store;
694  }
695  constexpr uint256_t get_uint256(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
696  {
697  return pointer_cast<const packed_t<uint256_t>*>( buffer + byte_offset )->get(littleEndian);
698  }
699 
700  /**
701  // *************************************************
702  // *************************************************
703  // *************************************************
704  */
705 
706  template<typename T>
707  constexpr
708  typename std::enable_if_t<
709  std::is_standard_layout_v<T>,
710  void>
711  put_value(uint8_t * buffer, nsize_t const byte_offset, const T& v) noexcept
712  {
713  // reinterpret_cast<packed_t<T>*>( buffer + byte_offset )->store = v;
714  pointer_cast<packed_t<T>*>( buffer + byte_offset )->store = v;
715  }
716 
717  template<typename T>
718  constexpr
719  typename std::enable_if_t<
720  std::is_standard_layout_v<T>,
721  void>
722  put_value(uint8_t * buffer, nsize_t const byte_offset, const T& v, const bool littleEndian) noexcept
723  {
724  pointer_cast<packed_t<T>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
725  }
726 
727  template<typename T>
728  constexpr
729  typename std::enable_if_t<
730  std::is_standard_layout_v<T>,
731  T>
732  get_value(uint8_t const * buffer, nsize_t const byte_offset) noexcept
733  {
734  return pointer_cast<const packed_t<T>*>( buffer + byte_offset )->store;
735  }
736 
737  template<typename T>
738  constexpr
739  typename std::enable_if_t<
740  std::is_standard_layout_v<T>,
741  T>
742  get_value(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
743  {
744  return pointer_cast<const packed_t<T>*>( buffer + byte_offset )->get(littleEndian);
745  }
746 
747 } // namespace jau
748 
749 /** \example test_basictypeconv.cpp
750  * This C++ unit test validates the jau::bswap and get/set value implementation
751  */
752 
753 #endif /* JAU_BYTE_UTIL_HPP_ */
constexpr_cxx20
#define constexpr_cxx20
constexpr qualifier replacement for C++20 constexpr.
Definition: cpp_lang_util.hpp:95
jau::is_builtin_bit_cast_available
constexpr bool is_builtin_bit_cast_available() noexcept
Query whether __builtin_bit_cast(Dest_type, arg) is available, using jau::has_builtin_bit_cast.
Definition: cpp_lang_util.hpp:243
jau::endian::undefined
@ undefined
Undetermined endian.
jau::endian::pdp
@ pdp
Identifier for DEC PDP-11, aka ENDIAN_LITTLE_WORD.
jau::has_endian_little
A little-endian type trait for convenience .
Definition: byte_util.hpp:260
jau::endian::honeywell
@ honeywell
Identifier for Honeywell 316, aka ENDIAN_BIG_WORD.
jau::put_uint192
constexpr void put_uint192(uint8_t *buffer, nsize_t const byte_offset, const uint192_t &v) noexcept
Definition: byte_util.hpp:666
packed_attribute.hpp
jau::uint256_t
Definition: int_types.hpp:125
PRAGMA_DISABLE_WARNING_MULTICHAR
#define PRAGMA_DISABLE_WARNING_MULTICHAR
Definition: cpp_pragma.hpp:58
jau::endian::little
@ little
Identifier for little endian.
PRAGMA_DISABLE_WARNING_PUSH
#define PRAGMA_DISABLE_WARNING_PUSH
Definition: cpp_pragma.hpp:53
jau::put_uint32
constexpr void put_uint32(uint8_t *buffer, nsize_t const byte_offset, const uint32_t v) noexcept
Definition: byte_util.hpp:615
jau
Definition: basic_algos.hpp:34
jau::put_uint128
constexpr void put_uint128(uint8_t *buffer, nsize_t const byte_offset, const uint128_t &v) noexcept
Definition: byte_util.hpp:649
jau::to_string
PRAGMA_DISABLE_WARNING_POP constexpr_cxx20 std::string to_string(const endian &v) noexcept
Return std::string representation of the given jau::endian.
Definition: byte_util.hpp:198
jau::get_int8
constexpr int8_t get_int8(uint8_t const *buffer, nsize_t const byte_offset) noexcept
Definition: byte_util.hpp:544
jau::put_uint64
constexpr void put_uint64(uint8_t *buffer, nsize_t const byte_offset, const uint64_t &v) noexcept
Definition: byte_util.hpp:632
jau::get_uint256
constexpr uint256_t get_uint256(uint8_t const *buffer, nsize_t const byte_offset) noexcept
Definition: byte_util.hpp:691
jau::has_endian_big
A big-endian type trait for convenience .
Definition: byte_util.hpp:280
jau::has_endian_big_v
constexpr bool has_endian_big_v
Value access of big-endian type trait for convenience .
Definition: byte_util.hpp:290
jau::isLittleEndian
constexpr bool isLittleEndian() noexcept
Evaluates true if platform is running in little endian mode, i.e.
Definition: byte_util.hpp:232
jau::endian::big
@ big
Identifier for big endian.
jau::put_uint256
constexpr void put_uint256(uint8_t *buffer, nsize_t const byte_offset, const uint256_t &v) noexcept
Definition: byte_util.hpp:683
jau::get_uint192
constexpr uint192_t get_uint192(uint8_t const *buffer, nsize_t const byte_offset) noexcept
Definition: byte_util.hpp:674
jau::put_value
constexpr std::enable_if_t< std::is_standard_layout_v< T >, void > put_value(uint8_t *buffer, nsize_t const byte_offset, const T &v) noexcept
Definition: byte_util.hpp:711
jau::has_endian_little_v
constexpr bool has_endian_little_v
Value access of little-endian type trait for convenience .
Definition: byte_util.hpp:270
jau::uint192_t::data
uint8_t data[24]
Definition: int_types.hpp:104
jau::cpu_to_be
constexpr uint16_t cpu_to_be(uint16_t const h) noexcept
Definition: byte_util.hpp:316
jau::uint192_t
Definition: int_types.hpp:104
jau::uint128_t::data
uint8_t data[16]
Definition: int_types.hpp:83
jau::uint256_t::data
uint8_t data[32]
Definition: int_types.hpp:125
jau::impl::get_host_order
constexpr uint32_t get_host_order() noexcept
Definition: byte_util.hpp:145
jau::endian::native
@ native
Identifier for native platform type, one of the above.
jau::get_uint8
constexpr uint8_t get_uint8(uint8_t const *buffer, nsize_t const byte_offset) noexcept
Definition: byte_util.hpp:540
direct_bt::BTSecurityRegistry::get
Entry * get(const EUI48 &addr, const std::string &name, AddressNameEntryMatchFunc m) noexcept
Returns a matching BTSecurityRegistry::Entry with the given.
Definition: BTSecurityRegistry.cpp:36
jau::get_uint32
constexpr uint32_t get_uint32(uint8_t const *buffer, nsize_t const byte_offset) noexcept
Definition: byte_util.hpp:623
PRAGMA_DISABLE_WARNING_POP
#define PRAGMA_DISABLE_WARNING_POP
Definition: cpp_pragma.hpp:54
jau::isLittleOrBigEndian
constexpr bool isLittleOrBigEndian() noexcept
Evaluates true if platform is running in little or big endian mode, i.e.
Definition: byte_util.hpp:248
jau::cpu_to_le
constexpr uint16_t cpu_to_le(uint16_t const h) noexcept
Definition: byte_util.hpp:334
jau::get_uint128
constexpr uint128_t get_uint128(uint8_t const *buffer, nsize_t const byte_offset) noexcept
Definition: byte_util.hpp:657
jau::bswap
constexpr uint16_t bswap(uint16_t const source) noexcept
Definition: byte_util.hpp:66
jau::isDefinedEndian
constexpr bool isDefinedEndian(const endian &v) noexcept
Evaluates true if the given endian is defined, i.e.
Definition: byte_util.hpp:213
jau::get_uint64
constexpr uint64_t get_uint64(uint8_t const *buffer, nsize_t const byte_offset) noexcept
Definition: byte_util.hpp:640
jau::get_value
constexpr std::enable_if_t< std::is_standard_layout_v< T >, T > get_value(uint8_t const *buffer, nsize_t const byte_offset) noexcept
Definition: byte_util.hpp:732
jau::endian
endian
Endian identifier, indicating endianess of all scaler types.
Definition: byte_util.hpp:171
jau::le_to_cpu
constexpr uint16_t le_to_cpu(uint16_t const l) noexcept
Definition: byte_util.hpp:325
jau::be_to_cpu
constexpr uint16_t be_to_cpu(uint16_t const n) noexcept
On the i386 the host byte order is Least Significant Byte first (LSB) or Little-Endian,...
Definition: byte_util.hpp:306
jau::nsize_t
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
Definition: int_types.hpp:44
cpp_lang_util.hpp
jau::get_uint16
constexpr uint16_t get_uint16(uint8_t const *buffer, nsize_t const byte_offset) noexcept
Definition: byte_util.hpp:586
int_types.hpp
jau::put_uint16
constexpr void put_uint16(uint8_t *buffer, nsize_t const byte_offset, const uint16_t v) noexcept
Definition: byte_util.hpp:561
cpp_pragma.hpp
jau::uint128_t
Definition: int_types.hpp:83
jau::isBigEndian
constexpr bool isBigEndian() noexcept
Evaluates true if platform is running in big endian mode, i.e.
Definition: byte_util.hpp:240
jau::put_uint8
constexpr void put_uint8(uint8_t *buffer, nsize_t const byte_offset, const uint8_t v) noexcept
Definition: byte_util.hpp:536