summaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2021-02-08 15:02:43 +0100
committerSven Gothel <[email protected]>2021-02-08 15:02:43 +0100
commitb218b12a155a2f07eabbd02e3fbada3feed3aab7 (patch)
treeb432c68247f08810927520b99c3b03af45c05492 /include
parent112528c73f09b262bd53f817f9d9ff9343af0ee9 (diff)
basic_types.hpp: Cleanup; Add constexpr 'enum class endian', 'pointer_cast()' and 'bit_cast()' and have all byte-order conversion and get/set functions be of constexpr; Add generalized template [get|put]_value(..) and to_hex_string(..)
Cleanup - Split basic_types.hpp -> basic_types.hpp + byte_util.hpp + int_types.hpp + string_util.hpp - Moved nsize_t, snsize_t to int_types.hpp and using 'uint_fast32_t' and 'int_fast32_t' as natural types. - Renamed cpp_lang_macros.hpp -> cpp_lang_util.hpp +++ Add constexpr 'enum class endian', 'pointer_cast()' and 'bit_cast()' and have all byte-order conversion and get/set functions be of constexpr. - Exposing '__builtin_bit_cast(Dest_type, arg)' via 'constexpr bool is_builtin_bit_cast_available()' and type traits. - Adding constexpr bit_cast<>() template for C++17 (a C++20 std), allowing constexpr type conversion using '__builtin_bit_cast(Dest_type, arg)', if the latter is available. - Adding constexpr pointer_cast<>() template, allowing constexpr pointer type conversion. Either using '__builtin_bit_cast(Dest_type, arg)' or reinterpret_cast<>(). - Add constexpr 'enum class endian' API, providing compile-time C++ endian evaluation w/o predefined macros. Inspired by C++20. - Replace linux bswap_[16,32,64] with either __builtin_bswap[16,32,64] or own const definition, both allowing constexpr - Add unified overloaded 'constexpr bswap(uint[16,32,64,128,192,256]_t const &)' using constexpr endian API. - Have all [get|put]_<type>(..) operations be of constexpr, using pointer_cast<>() instead of plain reinterpret_cast<>() and the new 'constexpr bswap(..)' methods. +++ Add generalized template [get|put]_value(..) and to_hex_string(..) - Add generalized template 'constexpr T [get|put]_value(..) {}' for std::is_standard_layout_v<T> - Add generalized template 'inline to_hex_string(T const &) {}' for std::is_standard_layout_v<T> +++ All of the above is covered by unit test 'test_basictypecon.cpp' '-std=c++17': - gcc 8.3.0 on arm32, arm64: __builtin_bit_cast() not available - gcc 10.2.1 on amd64: __builtin_bit_cast() not available - clang 9.0.1 on amd64, arm64: __builtin_bit_cast() is available - clang 11.0.1 on amd64: __builtin_bit_cast() is available Full build time (user) incl unit tests (C++ and Java) on GCC - amd64 gcc 11.0.1, 32 cores: 1m38s - arm64 gcc 8.3.0, 4 cores: 13m30s - arm32 gcc 8.3.0, 4 cores: 17m58s
Diffstat (limited to 'include')
-rw-r--r--include/jau/basic_types.hpp726
-rw-r--r--include/jau/byte_util.hpp753
-rw-r--r--include/jau/cow_darray.hpp2
-rw-r--r--include/jau/cow_iterator.hpp2
-rw-r--r--include/jau/cow_vector.hpp2
-rw-r--r--include/jau/cpp_lang_macros.hpp94
-rw-r--r--include/jau/cpp_lang_util.hpp260
-rw-r--r--include/jau/cpp_pragma.hpp63
-rw-r--r--include/jau/int_math.hpp32
-rw-r--r--include/jau/int_types.hpp133
-rw-r--r--include/jau/string_util.hpp329
-rw-r--r--include/jau/type_traits_queries.hpp11
12 files changed, 1550 insertions, 857 deletions
diff --git a/include/jau/basic_types.hpp b/include/jau/basic_types.hpp
index 27a28f3..2b54aee 100644
--- a/include/jau/basic_types.hpp
+++ b/include/jau/basic_types.hpp
@@ -33,16 +33,15 @@
#include <vector>
#include <type_traits>
-extern "C" {
- #include <endian.h>
- #include <byteswap.h>
-}
-
-#include <jau/int_math.hpp>
-#include <jau/cpp_lang_macros.hpp>
+#include <jau/cpp_lang_util.hpp>
#include <jau/packed_attribute.hpp>
#include <jau/type_traits_queries.hpp>
+#include <jau/int_types.hpp>
+#include <jau/int_math.hpp>
+#include <jau/byte_util.hpp>
+#include <jau/string_util.hpp>
+
namespace jau {
/**
@@ -139,443 +138,6 @@ namespace jau {
// *************************************************
*/
- __pack( struct uint128_t {
- uint8_t data[16];
-
- constexpr uint128_t() noexcept : data{0} {}
- constexpr uint128_t(const uint128_t &o) noexcept = default;
- uint128_t(uint128_t &&o) noexcept = default;
- constexpr uint128_t& operator=(const uint128_t &o) noexcept = default;
- uint128_t& operator=(uint128_t &&o) noexcept = default;
-
- void clear() noexcept { bzero(data, sizeof(data)); }
-
- constexpr bool operator==(uint128_t const &o) const noexcept {
- if( this == &o ) {
- return true;
- }
- return !std::memcmp(data, o.data, sizeof(data));
- }
- constexpr bool operator!=(uint128_t const &o) const noexcept
- { return !(*this == o); }
- } ) ;
-
- constexpr uint128_t bswap(uint128_t const & source) noexcept {
- uint128_t dest;
- uint8_t const * const s = source.data;
- uint8_t * const d = dest.data;
- for(nsize_t i=0; i<16; i++) {
- d[i] = s[15-i];
- }
- return dest;
- }
-
- __pack( struct uint192_t {
- uint8_t data[24];
-
- constexpr uint192_t() noexcept : data{0} {}
- constexpr uint192_t(const uint192_t &o) noexcept = default;
- uint192_t(uint192_t &&o) noexcept = default;
- constexpr uint192_t& operator=(const uint192_t &o) noexcept = default;
- uint192_t& operator=(uint192_t &&o) noexcept = default;
-
- void clear() noexcept { bzero(data, sizeof(data)); }
-
- constexpr bool operator==(uint192_t const &o) const noexcept {
- if( this == &o ) {
- return true;
- }
- return !std::memcmp(data, o.data, sizeof(data));
- }
- constexpr bool operator!=(uint192_t const &o) const noexcept
- { return !(*this == o); }
- } );
-
- constexpr uint192_t bswap(uint192_t const & source) noexcept {
- uint192_t dest;
- uint8_t const * const s = source.data;
- uint8_t * const d = dest.data;
- for(nsize_t i=0; i<24; i++) {
- d[i] = s[23-i];
- }
- return dest;
- }
-
- __pack( struct uint256_t {
- uint8_t data[32];
-
- constexpr uint256_t() noexcept : data{0} {}
- constexpr uint256_t(const uint256_t &o) noexcept = default;
- uint256_t(uint256_t &&o) noexcept = default;
- constexpr uint256_t& operator=(const uint256_t &o) noexcept = default;
- uint256_t& operator=(uint256_t &&o) noexcept = default;
-
- void clear() noexcept { bzero(data, sizeof(data)); }
-
- constexpr bool operator==(uint256_t const &o) const noexcept {
- if( this == &o ) {
- return true;
- }
- return !std::memcmp(data, o.data, sizeof(data));
- }
- constexpr bool operator!=(uint256_t const &o) const noexcept
- { return !(*this == o); }
- } );
-
- constexpr uint256_t bswap(uint256_t const & source) noexcept {
- uint256_t dest;
- uint8_t const * const s = source.data;
- uint8_t * const d = dest.data;
- for(nsize_t i=0; i<32; i++) {
- d[i] = s[31-i];
- }
- return dest;
- }
-
- /**
- // *************************************************
- // *************************************************
- // *************************************************
- */
-
- /**
- * On the i386 the host byte order is Least Significant Byte first (LSB) or Little-Endian,
- * whereas the network byte order, as used on the Internet, is Most Significant Byte first (MSB) or Big-Endian.
- * See #include <arpa/inet.h>
- *
- * Bluetooth is LSB or Little-Endian!
- */
-
-#if __BYTE_ORDER == __BIG_ENDIAN
- inline uint16_t be_to_cpu(uint16_t const n) noexcept {
- return n;
- }
- inline uint16_t cpu_to_be(uint16_t const h) noexcept {
- return h;
- }
- inline uint16_t le_to_cpu(uint16_t const l) noexcept {
- return bswap_16(l);
- }
- inline uint16_t cpu_to_le(uint16_t const h) noexcept {
- return bswap_16(h);
- }
-
- inline uint32_t be_to_cpu(uint32_t const n) noexcept {
- return n;
- }
- inline uint32_t cpu_to_be(uint32_t const h) noexcept {
- return h;
- }
- inline uint32_t le_to_cpu(uint32_t const l) noexcept {
- return bswap_32(l);
- }
- inline uint32_t cpu_to_le(uint32_t const h) noexcept {
- return bswap_32(h);
- }
-
- inline uint64_t be_to_cpu(uint64_t const & n) noexcept {
- return n;
- }
- inline uint64_t cpu_to_be(uint64_t const & h) noexcept {
- return h;
- }
- inline uint64_t le_to_cpu(uint64_t const & l) noexcept {
- return bswap_64(l);
- }
- inline uint64_t cpu_to_le(uint64_t const & h) noexcept {
- return bswap_64(h);
- }
-
- constexpr uint128_t be_to_cpu(uint128_t const & n) noexcept {
- return n;
- }
- constexpr uint128_t cpu_to_be(uint128_t const & h) noexcept {
- return n;
- }
- constexpr uint128_t le_to_cpu(uint128_t const & l) noexcept {
- return bswap(l);
- }
- constexpr uint128_t cpu_to_le(uint128_t const & h) noexcept {
- return bswap(h);
- }
-
- constexpr uint192_t be_to_cpu(uint192_t const & n) noexcept {
- return n;
- }
- constexpr uint192_t cpu_to_be(uint192_t const & h) noexcept {
- return n;
- }
- constexpr uint192_t le_to_cpu(uint192_t const & l) noexcept {
- return bswap(l);
- }
- constexpr uint192_t cpu_to_le(uint192_t const & h) noexcept {
- return bswap(h);
- }
-
- constexpr uint256_t be_to_cpu(uint256_t const & n) noexcept {
- return n;
- }
- constexpr uint256_t cpu_to_be(uint256_t const & h) noexcept {
- return n;
- }
- constexpr uint256_t le_to_cpu(uint256_t const & l) noexcept {
- return bswap(l);
- }
- constexpr uint256_t cpu_to_le(uint256_t const & h) noexcept {
- return bswap(h);
- }
-#elif __BYTE_ORDER == __LITTLE_ENDIAN
- inline uint16_t be_to_cpu(uint16_t const n) noexcept {
- return bswap_16(n);
- }
- inline uint16_t cpu_to_be(uint16_t const h) noexcept {
- return bswap_16(h);
- }
- inline uint16_t le_to_cpu(uint16_t const l) noexcept {
- return l;
- }
- inline uint16_t cpu_to_le(uint16_t const h) noexcept {
- return h;
- }
-
- inline uint32_t be_to_cpu(uint32_t const n) noexcept {
- return bswap_32(n);
- }
- inline uint32_t cpu_to_be(uint32_t const h) noexcept {
- return bswap_32(h);
- }
- inline uint32_t le_to_cpu(uint32_t const l) noexcept {
- return l;
- }
- inline uint32_t cpu_to_le(uint32_t const h) noexcept {
- return h;
- }
-
- inline uint64_t be_to_cpu(uint64_t const & n) noexcept {
- return bswap_64(n);
- }
- inline uint64_t cpu_to_be(uint64_t const & h) noexcept {
- return bswap_64(h);
- }
- inline uint64_t le_to_cpu(uint64_t const & l) noexcept {
- return l;
- }
- inline uint64_t cpu_to_le(uint64_t const & h) noexcept {
- return h;
- }
-
- constexpr uint128_t be_to_cpu(uint128_t const & n) noexcept {
- return bswap(n);
- }
- constexpr uint128_t cpu_to_be(uint128_t const & h) noexcept {
- return bswap(h);
- }
- constexpr uint128_t le_to_cpu(uint128_t const & l) noexcept {
- return l;
- }
- constexpr uint128_t cpu_to_le(uint128_t const & h) noexcept {
- return h;
- }
-
- constexpr uint192_t be_to_cpu(uint192_t const & n) noexcept {
- return bswap(n);
- }
- constexpr uint192_t cpu_to_be(uint192_t const & h) noexcept {
- return bswap(h);
- }
- constexpr uint192_t le_to_cpu(uint192_t const & l) noexcept {
- return l;
- }
- constexpr uint192_t cpu_to_le(uint192_t const & h) noexcept {
- return h;
- }
-
- constexpr uint256_t be_to_cpu(uint256_t const & n) noexcept {
- return bswap(n);
- }
- constexpr uint256_t cpu_to_be(uint256_t const & h) noexcept {
- return bswap(h);
- }
- constexpr uint256_t le_to_cpu(uint256_t const & l) noexcept {
- return l;
- }
- constexpr uint256_t cpu_to_le(uint256_t const & h) noexcept {
- return h;
- }
-#else
- #error "Unexpected __BYTE_ORDER"
-#endif
-
- /**
- // *************************************************
- // *************************************************
- // *************************************************
- */
-
- inline void put_uint8(uint8_t * buffer, nsize_t const byte_offset, const uint8_t v) noexcept
- {
- *reinterpret_cast<uint8_t *>( buffer + byte_offset ) = v;
- }
- inline uint8_t get_uint8(uint8_t const * buffer, nsize_t const byte_offset) noexcept
- {
- return *reinterpret_cast<uint8_t const *>( buffer + byte_offset );
- }
- inline int8_t get_int8(uint8_t const * buffer, nsize_t const byte_offset) noexcept
- {
- return *reinterpret_cast<int8_t const *>( buffer + byte_offset );
- }
-
- /**
- * Safe access to a pointer cast from unaligned memory via __packed__ attribute,
- * i.e. utilizing compiler generated safe load and store operations.
- * <p>
- * This template shall cause no costs, the cast data pointer is identical to 'T & p = &store'.
- * </p>
- */
- template<typename T> __pack ( struct packed_t {
- T store;
- constexpr T get(const bool littleEndian) const noexcept { return littleEndian ? le_to_cpu(store) : be_to_cpu(store); }
- } ) ;
-
- inline void put_uint16(uint8_t * buffer, nsize_t const byte_offset, const uint16_t v) noexcept
- {
- /**
- * Handle potentially misaligned address of buffer + byte_offset, can't just
- * uint16_t * p = (uint16_t *) ( buffer + byte_offset );
- * *p = v;
- * Universal alternative using memcpy is costly:
- * memcpy(buffer + byte_offset, &v, sizeof(v));
- * Use compiler magic 'struct __attribute__((__packed__))' access:
- */
- reinterpret_cast<packed_t<uint16_t>*>( buffer + byte_offset )->store = v;
- }
- inline void put_uint16(uint8_t * buffer, nsize_t const byte_offset, const uint16_t v, const bool littleEndian) noexcept
- {
- /**
- * Handle potentially misaligned address of buffer + byte_offset, can't just
- * uint16_t * p = (uint16_t *) ( buffer + byte_offset );
- * *p = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
- * Universal alternative using memcpy is costly:
- * const uint16_t v2 = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
- * memcpy(buffer + byte_offset, &v2, sizeof(v2));
- * Use compiler magic 'struct __attribute__((__packed__))' access:
- */
- reinterpret_cast<packed_t<uint16_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
- }
- inline uint16_t get_uint16(uint8_t const * buffer, nsize_t const byte_offset) noexcept
- {
- /**
- * Handle potentially misaligned address of buffer + byte_offset, can't just
- * uint16_t const * p = (uint16_t const *) ( buffer + byte_offset );
- * return *p;
- * Universal alternative using memcpy is costly:
- * uint16_t v;
- * memcpy(&v, buffer + byte_offset, sizeof(v));
- * return v;
- * Use compiler magic 'struct __attribute__((__packed__))' access:
- */
- return reinterpret_cast<const packed_t<uint16_t>*>( buffer + byte_offset )->store;
- }
- inline uint16_t get_uint16(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
- {
- /**
- * Handle potentially misaligned address of buffer + byte_offset, can't just
- * uint16_t const * p = (uint16_t const *) ( buffer + byte_offset );
- * return littleEndian ? le_to_cpu(*p) : be_to_cpu(*p);
- * Universal alternative using memcpy is costly:
- * uint16_t v;
- * memcpy(&v, buffer + byte_offset, sizeof(v));
- * return littleEndian ? le_to_cpu(v) : be_to_cpu(v);
- * Use compiler magic 'struct __attribute__((__packed__))' access:
- */
- return reinterpret_cast<const packed_t<uint16_t>*>( buffer + byte_offset )->get(littleEndian);
- }
-
- inline void put_uint32(uint8_t * buffer, nsize_t const byte_offset, const uint32_t v) noexcept
- {
- reinterpret_cast<packed_t<uint32_t>*>( buffer + byte_offset )->store = v;
- }
- inline void put_uint32(uint8_t * buffer, nsize_t const byte_offset, const uint32_t v, const bool littleEndian) noexcept
- {
- reinterpret_cast<packed_t<uint32_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
- }
- inline uint32_t get_uint32(uint8_t const * buffer, nsize_t const byte_offset) noexcept
- {
- return reinterpret_cast<const packed_t<uint32_t>*>( buffer + byte_offset )->store;
- }
- inline uint32_t get_uint32(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
- {
- return reinterpret_cast<const packed_t<uint32_t>*>( buffer + byte_offset )->get(littleEndian);
- }
-
- inline void put_uint64(uint8_t * buffer, nsize_t const byte_offset, const uint64_t & v) noexcept
- {
- reinterpret_cast<packed_t<uint64_t>*>( buffer + byte_offset )->store = v;
- }
- inline void put_uint64(uint8_t * buffer, nsize_t const byte_offset, const uint64_t & v, const bool littleEndian) noexcept
- {
- reinterpret_cast<packed_t<uint64_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
- }
- inline uint64_t get_uint64(uint8_t const * buffer, nsize_t const byte_offset) noexcept
- {
- return reinterpret_cast<const packed_t<uint64_t>*>( buffer + byte_offset )->store;
- }
- inline uint64_t get_uint64(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
- {
- return reinterpret_cast<const packed_t<uint64_t>*>( buffer + byte_offset )->get(littleEndian);
- }
-
- inline void put_uint128(uint8_t * buffer, nsize_t const byte_offset, const uint128_t & v) noexcept
- {
- reinterpret_cast<packed_t<uint128_t>*>( buffer + byte_offset )->store = v;
- }
- inline void put_uint128(uint8_t * buffer, nsize_t const byte_offset, const uint128_t & v, const bool littleEndian) noexcept
- {
- reinterpret_cast<packed_t<uint128_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
- }
- inline uint128_t get_uint128(uint8_t const * buffer, nsize_t const byte_offset) noexcept
- {
- return reinterpret_cast<const packed_t<uint128_t>*>( buffer + byte_offset )->store;
- }
- inline uint128_t get_uint128(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
- {
- return reinterpret_cast<const packed_t<uint128_t>*>( buffer + byte_offset )->get(littleEndian);
- }
-
- inline void put_uint192(uint8_t * buffer, nsize_t const byte_offset, const uint192_t & v) noexcept
- {
- reinterpret_cast<packed_t<uint192_t>*>( buffer + byte_offset )->store = v;
- }
- inline void put_uint192(uint8_t * buffer, nsize_t const byte_offset, const uint192_t & v, const bool littleEndian) noexcept
- {
- reinterpret_cast<packed_t<uint192_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
- }
- inline uint192_t get_uint192(uint8_t const * buffer, nsize_t const byte_offset) noexcept
- {
- return reinterpret_cast<const packed_t<uint192_t>*>( buffer + byte_offset )->store;
- }
- inline uint192_t get_uint192(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
- {
- return reinterpret_cast<const packed_t<uint192_t>*>( buffer + byte_offset )->get(littleEndian);
- }
-
- inline void put_uint256(uint8_t * buffer, nsize_t const byte_offset, const uint256_t & v) noexcept
- {
- reinterpret_cast<packed_t<uint256_t>*>( buffer + byte_offset )->store = v;
- }
- inline void put_uint256(uint8_t * buffer, nsize_t const byte_offset, const uint256_t & v, const bool littleEndian) noexcept
- {
- reinterpret_cast<packed_t<uint256_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
- }
- inline uint256_t get_uint256(uint8_t const * buffer, nsize_t const byte_offset) noexcept
- {
- return reinterpret_cast<const packed_t<uint256_t>*>( buffer + byte_offset )->store;
- }
- inline uint256_t get_uint256(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
- {
- return reinterpret_cast<const packed_t<uint256_t>*>( buffer + byte_offset )->get(littleEndian);
- }
-
inline void set_bit_uint32(const uint8_t nr, uint32_t &mask)
{
if( nr > 31 ) { throw IndexOutOfBoundsException(nr, 32, E_FILE_LINE); }
@@ -619,30 +181,6 @@ namespace jau {
*/
/**
- * Returns a C++ String taken from buffer with maximum length of min(max_len, max_len).
- * <p>
- * The maximum length only delimits the string length and does not contain the EOS null byte.
- * An EOS null byte will will be added.
- * </p>
- * <p>
- * The source string within buffer is not required to contain an EOS null byte;
- * </p>
- */
- std::string get_string(const uint8_t *buffer, nsize_t const buffer_len, nsize_t const max_len) noexcept;
-
- /** trim in place */
- void trimInPlace(std::string &s) noexcept;
-
- /** trim copy */
- std::string trimCopy(const std::string &s) noexcept;
-
- /**
- // *************************************************
- // *************************************************
- // *************************************************
- */
-
- /**
* Merge the given 'uuid16' into a 'base_uuid' copy at the given little endian 'uuid16_le_octet_index' position.
* <p>
* The given 'uuid16' value will be added with the 'base_uuid' copy at the given position.
@@ -686,258 +224,6 @@ namespace jau {
*/
uint128_t merge_uint128(uint32_t const uuid32, uint128_t const & base_uuid, nsize_t const uuid32_le_octet_index);
- /**
- // *************************************************
- // *************************************************
- // *************************************************
- */
-
- /**
- * Produce a hexadecimal string representation of the given byte values.
- * <p>
- * If lsbFirst is true, orders LSB left -> MSB right, usual for byte streams. Result will not have a leading `0x`.<br>
- * Otherwise orders MSB left -> LSB right, usual for readable integer values. Result will have a leading `0x`.
- * </p>
- * @param bytes pointer to the first byte to print, less offset
- * @param offset offset to bytes pointer to the first byte to print
- * @param length number of bytes to print
- * @param lsbFirst true having the least significant byte printed first (lowest addressed byte to highest),
- * otherwise have the most significant byte printed first (highest addressed byte to lowest).
- * A leading `0x` will be prepended if `lsbFirst == false`.
- * @param lowerCase true to use lower case hex-chars, otherwise capital letters are being used.
- * @return the hex-string representation of the data
- */
- std::string bytesHexString(const uint8_t * bytes, const nsize_t offset, const nsize_t length,
- const bool lsbFirst, const bool lowerCase=true) noexcept;
-
- /**
- * Produce a hexadecimal string representation of the given byte value.
- * @param dest the std::string reference destination to append
- * @param value the byte value to represent
- * @param lowerCase true to use lower case hex-chars, otherwise capital letters are being used.
- * @return the given std::string reference for chaining
- */
- std::string& byteHexString(std::string& dest, const uint8_t value, const bool lowerCase) noexcept;
-
- /**
- * Produce a lower-case hexadecimal string representation of the given uint8_t values.
- * @param v the value
- * @return the hex-string representation of the value
- */
- inline std::string uint8HexString(const uint8_t v) noexcept {
- return bytesHexString(reinterpret_cast<const uint8_t*>(&v), 0, sizeof(v), false /* lsbFirst */);
- }
-
- /**
- * Produce a lower-case hexadecimal string representation of the given uint16_t value.
- * @param v the value
- * @return the hex-string representation of the value
- */
- inline std::string uint16HexString(const uint16_t v) noexcept {
- return bytesHexString(reinterpret_cast<const uint8_t*>(&v), 0, sizeof(v), false /* lsbFirst */);
- }
-
- /**
- * Produce a lower-case hexadecimal string representation of the given uint32_t value.
- * @param v the value
- * @return the hex-string representation of the value
- */
- inline std::string uint32HexString(const uint32_t v) noexcept {
- return bytesHexString(reinterpret_cast<const uint8_t*>(&v), 0, sizeof(v), false /* lsbFirst */);
- }
-
- /**
- * Produce a lower-case hexadecimal string representation of the given uint64_t value.
- * @param v the value
- * @return the hex-string representation of the value
- */
- inline std::string uint64HexString(const uint64_t& v) noexcept {
- return bytesHexString(reinterpret_cast<const uint8_t*>(&v), 0, sizeof(v), false /* lsbFirst */);
- }
-
- /**
- * Produce a lower-case hexadecimal string representation of the given 'void *' value.
- * @param v the value
- * @return the hex-string representation of the value
- */
- inline std::string aptrHexString(const void * v) noexcept {
- return uint64HexString(reinterpret_cast<uint64_t>(v));
- }
-
- /**
- * Produce a lower-case hexadecimal string representation of the given uint128_t value.
- * @param v the value
- * @return the hex-string representation of the value
- */
- inline std::string uint128HexString(const uint128_t& v) noexcept {
- return bytesHexString(v.data, 0, sizeof(v.data), false /* lsbFirst */);
- }
-
- /**
- * Produce a lower-case hexadecimal string representation of the given uint256_t value.
- * @param v the value
- * @return the hex-string representation of the value
- */
- inline std::string uint256HexString(const uint256_t& v) noexcept {
- return bytesHexString(v.data, 0, sizeof(v.data), false /* lsbFirst */);
- }
-
- /**
- // *************************************************
- // *************************************************
- // *************************************************
- */
-
- /**
- * Produce a decimal string representation of an integral integer value.
- * @tparam T an integral integer type
- * @param v the integral integer value
- * @param separator if not 0, use as separation character, otherwise no separation characters are being used
- * @param width the minimum number of characters to be printed. Add padding with blank space if result is shorter.
- * @return the string representation of the integral integer value
- */
- template<class T>
- std::string to_decimal_string(const T& v, const char separator=',', const nsize_t width=0) noexcept {
- const snsize_t v_sign = jau::sign<T>(v);
- const nsize_t digit10_count1 = jau::digits10<T>(v, v_sign, true /* sign_is_digit */);
- const nsize_t digit10_count2 = v_sign < 0 ? digit10_count1 - 1 : digit10_count1; // less sign
-
- const nsize_t comma_count = 0 == separator ? 0 : ( digit10_count1 - 1 ) / 3;
- const nsize_t net_chars = digit10_count1 + comma_count;
- const nsize_t total_chars = std::max<nsize_t>(width, net_chars);
- std::string res(total_chars, ' ');
-
- T n = v;
- nsize_t char_iter = 0;
-
- for(nsize_t digit10_iter = 0; digit10_iter < digit10_count2 /* && char_iter < total_chars */; digit10_iter++ ) {
- const int digit = v_sign < 0 ? invert_sign( n % 10 ) : n % 10;
- n /= 10;
- if( 0 < digit10_iter && 0 == digit10_iter % 3 ) {
- res[total_chars-1-(char_iter++)] = separator;
- }
- res[total_chars-1-(char_iter++)] = '0' + digit;
- }
- if( v_sign < 0 /* && char_iter < total_chars */ ) {
- res[total_chars-1-(char_iter++)] = '-';
- }
- return res;
- }
-
- /**
- * Produce a decimal string representation of an int32_t value.
- * @param v the value
- * @param separator if not 0, use as separation character, otherwise no separation characters are being used
- * @param width the minimum number of characters to be printed. Add padding with blank space if result is shorter.
- * @return the string representation of the value
- */
- inline std::string int32DecString(const int32_t v, const char separator=',', const nsize_t width=0) noexcept {
- return to_decimal_string<int32_t>(v, separator, width);
- }
-
- /**
- * Produce a decimal string representation of a uint32_t value.
- * @param v the value
- * @param separator if not 0, use as separation character, otherwise no separation characters are being used
- * @param width the minimum number of characters to be printed. Add padding with blank space if result is shorter.
- * @return the string representation of the value
- */
- inline std::string uint32DecString(const uint32_t v, const char separator=',', const nsize_t width=0) noexcept {
- return to_decimal_string<uint32_t>(v, separator, width);
- }
-
- /**
- * Produce a decimal string representation of an int64_t value.
- * @param v the value
- * @param separator if not 0, use as separation character, otherwise no separation characters are being used
- * @param width the minimum number of characters to be printed. Add padding with blank space if result is shorter.
- * @return the string representation of the value
- */
- inline std::string int64DecString(const int64_t& v, const char separator=',', const nsize_t width=0) noexcept {
- return to_decimal_string<int64_t>(v, separator, width);
- }
-
- /**
- * Produce a decimal string representation of a uint64_t value.
- * @param v the value
- * @param separator if not 0, use as separation character, otherwise no separation characters are being used
- * @param width the minimum number of characters to be printed. Add padding with blank space if result is shorter.
- * @return the string representation of the value
- */
- inline std::string uint64DecString(const uint64_t& v, const char separator=',', const nsize_t width=0) noexcept {
- return to_decimal_string<uint64_t>(v, separator, width);
- }
-
- /**
- // *************************************************
- // *************************************************
- // *************************************************
- */
-
- template< class value_type,
- std::enable_if_t< std::is_integral_v<value_type> ||
- std::is_floating_point_v<value_type>,
- bool> = true>
- std::string to_string(const value_type & ref)
- {
- return std::to_string(ref);
- }
- template< class value_type,
- std::enable_if_t<!std::is_integral_v<value_type> &&
- !std::is_floating_point_v<value_type> &&
- std::is_pointer_v<value_type>,
- bool> = true>
- std::string to_string(const value_type & ref)
- {
- return aptrHexString((void*)ref);
- }
-
- template< class value_type,
- std::enable_if_t<!std::is_integral_v<value_type> &&
- !std::is_floating_point_v<value_type> &&
- !std::is_pointer_v<value_type> &&
- jau::has_toString_v<value_type>,
- bool> = true>
- std::string to_string(const value_type & ref) {
- return ref.toString();
- }
-
- template< class value_type,
- std::enable_if_t<!std::is_integral_v<value_type> &&
- !std::is_floating_point_v<value_type> &&
- !std::is_pointer_v<value_type> &&
- !jau::has_toString_v<value_type> &&
- jau::has_to_string_v<value_type>,
- bool> = true>
- std::string to_string(const value_type & ref) {
- return ref.to_string();
- }
-
- template< class value_type,
- std::enable_if_t<!std::is_integral_v<value_type> &&
- !std::is_floating_point_v<value_type> &&
- !std::is_pointer_v<value_type> &&
- !jau::has_toString_v<value_type> &&
- !jau::has_to_string_v<value_type> &&
- jau::has_member_of_pointer_v<value_type>,
- bool> = true>
- std::string to_string(const value_type & ref) {
- return aptrHexString((void*)ref.operator->());
- }
-
- template< class value_type,
- std::enable_if_t<!std::is_integral_v<value_type> &&
- !std::is_floating_point_v<value_type> &&
- !std::is_pointer_v<value_type> &&
- !jau::has_toString_v<value_type> &&
- !jau::has_to_string_v<value_type> &&
- !jau::has_member_of_pointer_v<value_type>,
- bool> = true>
- std::string to_string(const value_type & ref) {
- (void)ref;
- return "jau::to_string<T> not available for "+type_cue<value_type>::print("unknown", TypeTraitGroup::ALL);
- }
-
} // namespace jau
/** \example test_intdecstring01.cpp
diff --git a/include/jau/byte_util.hpp b/include/jau/byte_util.hpp
new file mode 100644
index 0000000..801805d
--- /dev/null
+++ b/include/jau/byte_util.hpp
@@ -0,0 +1,753 @@
+/*
+ * Author: Sven Gothel <[email protected]>
+ * Copyright (c) 2020 Gothel Software e.K.
+ * Copyright (c) 2020 ZAFENA AB
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef JAU_BYTE_UTIL_HPP_
+#define JAU_BYTE_UTIL_HPP_
+
+#include <cstring>
+#include <string>
+#include <memory>
+#include <cstdint>
+#include <vector>
+#include <type_traits>
+
+#include <jau/cpp_lang_util.hpp>
+#include <jau/cpp_pragma.hpp>
+#include <jau/packed_attribute.hpp>
+
+#include <jau/int_types.hpp>
+
+namespace jau {
+
+ #if defined __has_builtin
+ #if __has_builtin(__builtin_bswap16)
+ #define __has_builtin_bswap16 1
+ #endif
+ #elif defined(__GNUC__) && __GNUC_PREREQ (4, 8)
+ #define __has_builtin_bswap16 1
+ #endif
+ #if defined __has_builtin
+ #if __has_builtin(__builtin_bswap32)
+ #define __has_builtin_bswap32 1
+ #endif
+ #elif defined(__GNUC__) && __GNUC_PREREQ (4, 8)
+ #define __has_builtin_bswap32 1
+ #endif
+ #if defined __has_builtin
+ #if __has_builtin(__builtin_bswap64)
+ #define __has_builtin_bswap64 1
+ #endif
+ #elif defined(__GNUC__) && __GNUC_PREREQ (4, 8)
+ #define __has_builtin_bswap64 1
+ #endif
+
+ constexpr uint16_t bswap(uint16_t const source) noexcept {
+ #if defined __has_builtin_bswap16
+ return __builtin_bswap16(source);
+ #else
+ return (uint16_t) ( ( ( (source) >> 8 ) & 0xff ) |
+ ( ( (source) & 0xff) << 8 ) );
+ #endif
+ }
+
+ constexpr uint32_t bswap(uint32_t const source) noexcept {
+ #if defined __has_builtin_bswap32
+ return __builtin_bswap32(source);
+ #else
+ return ( ( source & 0xff000000U ) >> 24 ) |
+ ( ( source & 0x00ff0000U ) >> 8 ) |
+ ( ( source & 0x0000ff00U ) << 8 ) |
+ ( ( source & 0x000000ffU ) << 24 );
+ #endif
+ }
+
+ constexpr uint64_t bswap(uint64_t const & source) noexcept {
+ #if defined __has_builtin_bswap64
+ return __builtin_bswap64(source);
+ #else
+ return ( ( source & 0xff00000000000000ULL ) >> 56 ) |
+ ( ( source & 0x00ff000000000000ULL ) >> 40 ) |
+ ( ( source & 0x0000ff0000000000ULL ) >> 24 ) |
+ ( ( source & 0x000000ff00000000ULL ) >> 8 ) |
+ ( ( source & 0x00000000ff000000ULL ) << 8 ) |
+ ( ( source & 0x0000000000ff0000ULL ) << 24 ) |
+ ( ( source & 0x000000000000ff00ULL ) << 40 ) |
+ ( ( source & 0x00000000000000ffULL ) << 56 );
+ #endif
+ }
+
+ constexpr uint128_t bswap(uint128_t const & source) noexcept {
+ uint128_t dest;
+ uint8_t const * const s = source.data;
+ uint8_t * const d = dest.data;
+ for(nsize_t i=0; i<16; i++) {
+ d[i] = s[15-i];
+ }
+ return dest;
+ }
+
+ constexpr uint192_t bswap(uint192_t const & source) noexcept {
+ uint192_t dest;
+ uint8_t const * const s = source.data;
+ uint8_t * const d = dest.data;
+ for(nsize_t i=0; i<24; i++) {
+ d[i] = s[23-i];
+ }
+ return dest;
+ }
+
+ constexpr uint256_t bswap(uint256_t const & source) noexcept {
+ uint256_t dest;
+ uint8_t const * const s = source.data;
+ uint8_t * const d = dest.data;
+ for(nsize_t i=0; i<32; i++) {
+ d[i] = s[31-i];
+ }
+ return dest;
+ }
+
+ /**
+ // *************************************************
+ // *************************************************
+ // *************************************************
+ */
+
+ // The pragma to stop multichar warning == error `-Werror=multichar` doesn't seem to work with GCC <= 10.2
+ // Hence we have to disable this specific warning via: `-Wno-multichar`
+ // until all our compiler support `__builtin_bit_cast(T, a)`
+
+ PRAGMA_DISABLE_WARNING_PUSH
+ PRAGMA_DISABLE_WARNING_MULTICHAR
+
+ namespace impl {
+ constexpr uint32_t get_host_order() noexcept {
+ if( jau::is_builtin_bit_cast_available() ) {
+ constexpr uint8_t b[4] { 0x44, 0x43, 0x42, 0x41 }; // h->l: 41 42 43 44 = 'ABCD' hex ASCII code
+ return jau::bit_cast<uint32_t, uint8_t[4]>( b );
+ } else {
+ return 'ABCD'; // h->l: 41 42 43 44 = 'ABCD' hex ASCII code
+ }
+ }
+ }
+
+ /**
+ * Endian identifier, indicating endianess of all scaler types.
+ * <p>
+ * Inspired by C++20 std::endian
+ * </p>
+ * <p>
+ * Corner case platforms currently not supported,
+ * i.e. unified endianess and mixed endianess.
+ * </p>
+ * <p>
+ * All endian API entries are of `constexpr` and hence evaluated at compile time.<br>
+ * Therefore, if-branches and expressions are also of `constexpr` and optimized 'away' at compile time.<br>
+ * This includes the `cpu_to_<endian>(..)` and `<endian>_to_cpu(..)` etc utility functions.
+ * </p>
+ */
+ enum class endian : uint32_t
+ {
+ /** Identifier for little endian. */
+ little = 0x41424344U, // h->l: 41 42 43 44 = 'ABCD' hex ASCII code
+
+ /** Identifier for big endian. */
+ big = 0x44434241U, // h->l: 44 43 42 41 = 'DCBA' hex ASCII code
+
+ /** Identifier for DEC PDP-11, aka `ENDIAN_LITTLE_WORD`. */
+ pdp = 0x43444142U, // h->l: 43 44 41 42 = 'CDAB' hex ASCII code
+
+ /** Identifier for Honeywell 316, aka `ENDIAN_BIG_WORD`. */
+ honeywell = 0x42414443U, // h->l: 42 41 44 43 = 'BADC' hex ASCII code
+
+ /** Undetermined endian */
+ undefined = 0x00000000U,
+
+ /** Identifier for native platform type, one of the above. */
+ native = impl::get_host_order()
+ };
+
+ PRAGMA_DISABLE_WARNING_POP
+
+ /**
+ * Return std::string representation of the given jau::endian.
+ * @param v the jau::endian value
+ * @return the std::string representation
+ */
+ constexpr_func_cxx20 std::string to_string(const endian& v) noexcept {
+ switch(v) {
+ case endian::little: return "little";
+ case endian::big: return "big";
+ case endian::pdp: return "pdb";
+ case endian::honeywell: return "honeywell";
+ case endian::undefined: return "undefined";
+ }
+ return "unlisted";
+ }
+
+ /**
+ * Evaluates `true` if the given endian is defined,
+ * i.e. `little`, `big`, `pdp` or `honeywell`.
+ */
+ constexpr bool isDefinedEndian(const endian &v) noexcept {
+ switch(v) {
+ case endian::little:
+ [[fallthrough]];
+ case endian::big:
+ [[fallthrough]];
+ case endian::pdp:
+ [[fallthrough]];
+ case endian::honeywell:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Evaluates `true` if platform is running in little endian mode,
+ * i.e. `jau::endian::little == jau::endian::native`.
+ */
+ constexpr bool isLittleEndian() noexcept {
+ return endian::little == endian::native;
+ }
+
+ /**
+ * Evaluates `true` if platform is running in big endian mode,
+ * i.e. `jau::endian::big == jau::endian::native`.
+ */
+ constexpr bool isBigEndian() noexcept {
+ return endian::big == endian::native;
+ }
+
+ /**
+ * Evaluates `true` if platform is running in little or big endian mode,
+ * i.e. `jau::endian::little == jau::endian::native || jau::endian::big == jau::endian::native`.
+ */
+ constexpr bool isLittleOrBigEndian() noexcept {
+ return jau::endian::little == jau::endian::native || jau::endian::big == jau::endian::native;
+ }
+
+ /**
+ * A little-endian type trait for convenience ..
+ * <p>
+ * Since all endian definitions are of `constexpr`, code can simply use expressions of these
+ * for compile-time evaluation and optimization. A template `SFINAE` is not required.
+ * </p>
+ * @tparam Dummy_type just to make template `SFINAE` happy
+ */
+ template <typename Dummy_type> struct has_endian_little : std::integral_constant<bool, endian::little == endian::native> {};
+
+ /**
+ * Value access of little-endian type trait for convenience ..
+ * <p>
+ * Since all endian definitions are of `constexpr`, code can simply use expressions of these
+ * for compile-time evaluation and optimization. A template `SFINAE` is not required.
+ * </p>
+ * @tparam Dummy_type just to make template `SFINAE` happy
+ */
+ template <typename Dummy_type> inline constexpr bool has_endian_little_v = has_endian_little<Dummy_type>::value;
+
+ /**
+ * A big-endian type trait for convenience ..
+ * <p>
+ * Since all endian definitions are of `constexpr`, code can simply use expressions of these
+ * for compile-time evaluation and optimization. A template `SFINAE` is not required.
+ * </p>
+ * @tparam Dummy_type just to make template `SFINAE` happy
+ */
+ struct has_endian_big : std::integral_constant<bool, endian::big == endian::native> {};
+
+ /**
+ * Value access of big-endian type trait for convenience ..
+ * <p>
+ * Since all endian definitions are of `constexpr`, code can simply use expressions of these
+ * for compile-time evaluation and optimization. A template `SFINAE` is not required.
+ * </p>
+ * @tparam Dummy_type just to make template `SFINAE` happy
+ */
+ inline constexpr bool has_endian_big_v = has_endian_big::value;
+
+ /**
+ // *************************************************
+ // *************************************************
+ // *************************************************
+ */
+
+ /**
+ * On the i386 the host byte order is Least Significant Byte first (LSB) or Little-Endian,
+ * whereas the network byte order, as used on the Internet, is Most Significant Byte first (MSB) or Big-Endian.
+ * See #include <arpa/inet.h>
+ *
+ * Bluetooth is LSB or Little-Endian!
+ */
+
+ constexpr uint16_t be_to_cpu(uint16_t const n) noexcept {
+ static_assert(isLittleOrBigEndian()); // one static_assert is sufficient for whole compilation unit
+ if( isLittleEndian() ) {
+ return bswap(n);
+ } else if( isBigEndian() ) {
+ return bswap(n);
+ } else {
+ return 0; // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint16_t cpu_to_be(uint16_t const h) noexcept {
+ if( isLittleEndian() ) {
+ return bswap(h);
+ } else if( isBigEndian() ) {
+ return h;
+ } else {
+ return 0; // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint16_t le_to_cpu(uint16_t const l) noexcept {
+ if( isLittleEndian() ) {
+ return l;
+ } else if( isBigEndian() ) {
+ return bswap(l);
+ } else {
+ return 0; // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint16_t cpu_to_le(uint16_t const h) noexcept {
+ if( isLittleEndian() ) {
+ return h;
+ } else if( isBigEndian() ) {
+ return bswap(h);
+ } else {
+ return 0; // unreachable -> static_assert(..) above
+ }
+ }
+
+ constexpr uint32_t be_to_cpu(uint32_t const n) noexcept {
+ if( isLittleEndian() ) {
+ return bswap(n);
+ } else if( isBigEndian() ) {
+ return n;
+ } else {
+ return 0; // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint32_t cpu_to_be(uint32_t const h) noexcept {
+ if( isLittleEndian() ) {
+ return bswap(h);
+ } else if( isBigEndian() ) {
+ return h;
+ } else {
+ return 0; // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint32_t le_to_cpu(uint32_t const l) noexcept {
+ if( isLittleEndian() ) {
+ return l;
+ } else if( isBigEndian() ) {
+ return bswap(l);
+ } else {
+ return 0; // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint32_t cpu_to_le(uint32_t const h) noexcept {
+ if( isLittleEndian() ) {
+ return h;
+ } else if( isBigEndian() ) {
+ return bswap(h);
+ } else {
+ return 0; // unreachable -> static_assert(..) above
+ }
+ }
+
+ constexpr uint64_t be_to_cpu(uint64_t const & n) noexcept {
+ if( isLittleEndian() ) {
+ return bswap(n);
+ } else if( isBigEndian() ) {
+ return n;
+ } else {
+ return 0; // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint64_t cpu_to_be(uint64_t const & h) noexcept {
+ if( isLittleEndian() ) {
+ return bswap(h);
+ } else if( isBigEndian() ) {
+ return h;
+ } else {
+ return 0; // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint64_t le_to_cpu(uint64_t const & l) noexcept {
+ if( isLittleEndian() ) {
+ return l;
+ } else if( isBigEndian() ) {
+ return bswap(l);
+ } else {
+ return 0; // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint64_t cpu_to_le(uint64_t const & h) noexcept {
+ if( isLittleEndian() ) {
+ return h;
+ } else if( isBigEndian() ) {
+ return bswap(h);
+ } else {
+ return 0; // unreachable -> static_assert(..) above
+ }
+ }
+
+ constexpr uint128_t be_to_cpu(uint128_t const & n) noexcept {
+ if( isLittleEndian() ) {
+ return bswap(n);
+ } else if( isBigEndian() ) {
+ return n;
+ } else {
+ return uint128_t(); // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint128_t cpu_to_be(uint128_t const & h) noexcept {
+ if( isLittleEndian() ) {
+ return bswap(h);
+ } else if( isBigEndian() ) {
+ return h;
+ } else {
+ return uint128_t(); // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint128_t le_to_cpu(uint128_t const & l) noexcept {
+ if( isLittleEndian() ) {
+ return l;
+ } else if( isBigEndian() ) {
+ return bswap(l);
+ } else {
+ return uint128_t(); // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint128_t cpu_to_le(uint128_t const & h) noexcept {
+ if( isLittleEndian() ) {
+ return h;
+ } else if( isBigEndian() ) {
+ return bswap(h);
+ } else {
+ return uint128_t(); // unreachable -> static_assert(..) above
+ }
+ }
+
+ constexpr uint192_t be_to_cpu(uint192_t const & n) noexcept {
+ if( isLittleEndian() ) {
+ return bswap(n);
+ } else if( isBigEndian() ) {
+ return n;
+ } else {
+ return uint192_t(); // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint192_t cpu_to_be(uint192_t const & h) noexcept {
+ if( isLittleEndian() ) {
+ return bswap(h);
+ } else if( isBigEndian() ) {
+ return h;
+ } else {
+ return uint192_t(); // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint192_t le_to_cpu(uint192_t const & l) noexcept {
+ if( isLittleEndian() ) {
+ return l;
+ } else if( isBigEndian() ) {
+ return bswap(l);
+ } else {
+ return uint192_t(); // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint192_t cpu_to_le(uint192_t const & h) noexcept {
+ if( isLittleEndian() ) {
+ return h;
+ } else if( isBigEndian() ) {
+ return bswap(h);
+ } else {
+ return uint192_t(); // unreachable -> static_assert(..) above
+ }
+ }
+
+ constexpr uint256_t be_to_cpu(uint256_t const & n) noexcept {
+ if( isLittleEndian() ) {
+ return bswap(n);
+ } else if( isBigEndian() ) {
+ return n;
+ } else {
+ return uint256_t(); // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint256_t cpu_to_be(uint256_t const & h) noexcept {
+ if( isLittleEndian() ) {
+ return bswap(h);
+ } else if( isBigEndian() ) {
+ return h;
+ } else {
+ return uint256_t(); // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint256_t le_to_cpu(uint256_t const & l) noexcept {
+ if( isLittleEndian() ) {
+ return l;
+ } else if( isBigEndian() ) {
+ return bswap(l);
+ } else {
+ return uint256_t(); // unreachable -> static_assert(..) above
+ }
+ }
+ constexpr uint256_t cpu_to_le(uint256_t const & h) noexcept {
+ if( isLittleEndian() ) {
+ return h;
+ } else if( isBigEndian() ) {
+ return bswap(h);
+ } else {
+ return uint256_t(); // unreachable -> static_assert(..) above
+ }
+
+ }
+
+ /**
+ // *************************************************
+ // *************************************************
+ // *************************************************
+ */
+
+ constexpr void put_uint8(uint8_t * buffer, nsize_t const byte_offset, const uint8_t v) noexcept
+ {
+ *pointer_cast<uint8_t *>( buffer + byte_offset ) = v;
+ }
+ constexpr uint8_t get_uint8(uint8_t const * buffer, nsize_t const byte_offset) noexcept
+ {
+ return *pointer_cast<uint8_t const *>( buffer + byte_offset );
+ }
+ constexpr int8_t get_int8(uint8_t const * buffer, nsize_t const byte_offset) noexcept
+ {
+ return *pointer_cast<int8_t const *>( buffer + byte_offset );
+ }
+
+ /**
+ * Safe access to a pointer cast from unaligned memory via __packed__ attribute,
+ * i.e. utilizing compiler generated safe load and store operations.
+ * <p>
+ * This template shall cause no costs, the cast data pointer is identical to 'T & p = &store'.
+ * </p>
+ */
+ template<typename T> __pack ( struct packed_t {
+ T store;
+ constexpr T get(const bool littleEndian) const noexcept { return littleEndian ? le_to_cpu(store) : be_to_cpu(store); }
+ } ) ;
+
+ constexpr void put_uint16(uint8_t * buffer, nsize_t const byte_offset, const uint16_t v) noexcept
+ {
+ /**
+ * Handle potentially misaligned address of buffer + byte_offset, can't just
+ * uint16_t * p = (uint16_t *) ( buffer + byte_offset );
+ * *p = v;
+ * Universal alternative using memcpy is costly:
+ * memcpy(buffer + byte_offset, &v, sizeof(v));
+ * Use compiler magic 'struct __attribute__((__packed__))' access:
+ */
+ pointer_cast<packed_t<uint16_t>*>( buffer + byte_offset )->store = v;
+ }
+ constexpr void put_uint16(uint8_t * buffer, nsize_t const byte_offset, const uint16_t v, const bool littleEndian) noexcept
+ {
+ /**
+ * Handle potentially misaligned address of buffer + byte_offset, can't just
+ * uint16_t * p = (uint16_t *) ( buffer + byte_offset );
+ * *p = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
+ * Universal alternative using memcpy is costly:
+ * const uint16_t v2 = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
+ * memcpy(buffer + byte_offset, &v2, sizeof(v2));
+ * Use compiler magic 'struct __attribute__((__packed__))' access:
+ */
+ pointer_cast<packed_t<uint16_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
+ }
+ constexpr uint16_t get_uint16(uint8_t const * buffer, nsize_t const byte_offset) noexcept
+ {
+ /**
+ * Handle potentially misaligned address of buffer + byte_offset, can't just
+ * uint16_t const * p = (uint16_t const *) ( buffer + byte_offset );
+ * return *p;
+ * Universal alternative using memcpy is costly:
+ * uint16_t v;
+ * memcpy(&v, buffer + byte_offset, sizeof(v));
+ * return v;
+ * Use compiler magic 'struct __attribute__((__packed__))' access:
+ */
+ return pointer_cast<const packed_t<uint16_t>*>( buffer + byte_offset )->store;
+ }
+ constexpr uint16_t get_uint16(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
+ {
+ /**
+ * Handle potentially misaligned address of buffer + byte_offset, can't just
+ * uint16_t const * p = (uint16_t const *) ( buffer + byte_offset );
+ * return littleEndian ? le_to_cpu(*p) : be_to_cpu(*p);
+ * Universal alternative using memcpy is costly:
+ * uint16_t v;
+ * memcpy(&v, buffer + byte_offset, sizeof(v));
+ * return littleEndian ? le_to_cpu(v) : be_to_cpu(v);
+ * Use compiler magic 'struct __attribute__((__packed__))' access:
+ */
+ return pointer_cast<const packed_t<uint16_t>*>( buffer + byte_offset )->get(littleEndian);
+ }
+
+ constexpr void put_uint32(uint8_t * buffer, nsize_t const byte_offset, const uint32_t v) noexcept
+ {
+ pointer_cast<packed_t<uint32_t>*>( buffer + byte_offset )->store = v;
+ }
+ constexpr void put_uint32(uint8_t * buffer, nsize_t const byte_offset, const uint32_t v, const bool littleEndian) noexcept
+ {
+ pointer_cast<packed_t<uint32_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
+ }
+ constexpr uint32_t get_uint32(uint8_t const * buffer, nsize_t const byte_offset) noexcept
+ {
+ return pointer_cast<const packed_t<uint32_t>*>( buffer + byte_offset )->store;
+ }
+ constexpr uint32_t get_uint32(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
+ {
+ return pointer_cast<const packed_t<uint32_t>*>( buffer + byte_offset )->get(littleEndian);
+ }
+
+ constexpr void put_uint64(uint8_t * buffer, nsize_t const byte_offset, const uint64_t & v) noexcept
+ {
+ pointer_cast<packed_t<uint64_t>*>( buffer + byte_offset )->store = v;
+ }
+ constexpr void put_uint64(uint8_t * buffer, nsize_t const byte_offset, const uint64_t & v, const bool littleEndian) noexcept
+ {
+ pointer_cast<packed_t<uint64_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
+ }
+ constexpr uint64_t get_uint64(uint8_t const * buffer, nsize_t const byte_offset) noexcept
+ {
+ return pointer_cast<const packed_t<uint64_t>*>( buffer + byte_offset )->store;
+ }
+ constexpr uint64_t get_uint64(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
+ {
+ return pointer_cast<const packed_t<uint64_t>*>( buffer + byte_offset )->get(littleEndian);
+ }
+
+ constexpr void put_uint128(uint8_t * buffer, nsize_t const byte_offset, const uint128_t & v) noexcept
+ {
+ pointer_cast<packed_t<uint128_t>*>( buffer + byte_offset )->store = v;
+ }
+ constexpr void put_uint128(uint8_t * buffer, nsize_t const byte_offset, const uint128_t & v, const bool littleEndian) noexcept
+ {
+ pointer_cast<packed_t<uint128_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
+ }
+ constexpr uint128_t get_uint128(uint8_t const * buffer, nsize_t const byte_offset) noexcept
+ {
+ return pointer_cast<const packed_t<uint128_t>*>( buffer + byte_offset )->store;
+ }
+ constexpr uint128_t get_uint128(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
+ {
+ return pointer_cast<const packed_t<uint128_t>*>( buffer + byte_offset )->get(littleEndian);
+ }
+
+ constexpr void put_uint192(uint8_t * buffer, nsize_t const byte_offset, const uint192_t & v) noexcept
+ {
+ pointer_cast<packed_t<uint192_t>*>( buffer + byte_offset )->store = v;
+ }
+ constexpr void put_uint192(uint8_t * buffer, nsize_t const byte_offset, const uint192_t & v, const bool littleEndian) noexcept
+ {
+ pointer_cast<packed_t<uint192_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
+ }
+ constexpr uint192_t get_uint192(uint8_t const * buffer, nsize_t const byte_offset) noexcept
+ {
+ return pointer_cast<const packed_t<uint192_t>*>( buffer + byte_offset )->store;
+ }
+ constexpr uint192_t get_uint192(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
+ {
+ return pointer_cast<const packed_t<uint192_t>*>( buffer + byte_offset )->get(littleEndian);
+ }
+
+ constexpr void put_uint256(uint8_t * buffer, nsize_t const byte_offset, const uint256_t & v) noexcept
+ {
+ pointer_cast<packed_t<uint256_t>*>( buffer + byte_offset )->store = v;
+ }
+ constexpr void put_uint256(uint8_t * buffer, nsize_t const byte_offset, const uint256_t & v, const bool littleEndian) noexcept
+ {
+ pointer_cast<packed_t<uint256_t>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
+ }
+ constexpr uint256_t get_uint256(uint8_t const * buffer, nsize_t const byte_offset) noexcept
+ {
+ return pointer_cast<const packed_t<uint256_t>*>( buffer + byte_offset )->store;
+ }
+ constexpr uint256_t get_uint256(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
+ {
+ return pointer_cast<const packed_t<uint256_t>*>( buffer + byte_offset )->get(littleEndian);
+ }
+
+ /**
+ // *************************************************
+ // *************************************************
+ // *************************************************
+ */
+
+ template<typename T>
+ constexpr
+ typename 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
+ {
+ // reinterpret_cast<packed_t<T>*>( buffer + byte_offset )->store = v;
+ pointer_cast<packed_t<T>*>( buffer + byte_offset )->store = v;
+ }
+
+ template<typename T>
+ constexpr
+ typename std::enable_if_t<
+ std::is_standard_layout_v<T>,
+ void>
+ put_value(uint8_t * buffer, nsize_t const byte_offset, const T& v, const bool littleEndian) noexcept
+ {
+ pointer_cast<packed_t<T>*>( buffer + byte_offset )->store = littleEndian ? cpu_to_le(v) : cpu_to_be(v);
+ }
+
+ template<typename T>
+ constexpr
+ typename std::enable_if_t<
+ std::is_standard_layout_v<T>,
+ T>
+ get_value(uint8_t const * buffer, nsize_t const byte_offset) noexcept
+ {
+ return pointer_cast<const packed_t<T>*>( buffer + byte_offset )->store;
+ }
+
+ template<typename T>
+ constexpr
+ typename std::enable_if_t<
+ std::is_standard_layout_v<T>,
+ T>
+ get_value(uint8_t const * buffer, nsize_t const byte_offset, const bool littleEndian) noexcept
+ {
+ return pointer_cast<const packed_t<T>*>( buffer + byte_offset )->get(littleEndian);
+ }
+
+} // namespace jau
+
+/** \example test_basictypeconv.cpp
+ * This C++ unit test validates the jau::bswap and get/set value implementation
+ */
+
+#endif /* JAU_BYTE_UTIL_HPP_ */
diff --git a/include/jau/cow_darray.hpp b/include/jau/cow_darray.hpp
index b59c5d5..d7939d7 100644
--- a/include/jau/cow_darray.hpp
+++ b/include/jau/cow_darray.hpp
@@ -35,7 +35,7 @@
#include <condition_variable>
#include <algorithm>
-#include <jau/cpp_lang_macros.hpp>
+#include <jau/cpp_lang_util.hpp>
#include <jau/debug.hpp>
#include <jau/darray.hpp>
#include <jau/basic_types.hpp>
diff --git a/include/jau/cow_iterator.hpp b/include/jau/cow_iterator.hpp
index 4133c1d..f0dce50 100644
--- a/include/jau/cow_iterator.hpp
+++ b/include/jau/cow_iterator.hpp
@@ -33,7 +33,7 @@
#include <type_traits>
#include <iostream>
-#include <jau/cpp_lang_macros.hpp>
+#include <jau/cpp_lang_util.hpp>
#include <jau/debug.hpp>
#include <jau/basic_types.hpp>
diff --git a/include/jau/cow_vector.hpp b/include/jau/cow_vector.hpp
index 6539e91..e59b349 100644
--- a/include/jau/cow_vector.hpp
+++ b/include/jau/cow_vector.hpp
@@ -37,7 +37,7 @@
#include <vector>
#include <algorithm>
-#include <jau/cpp_lang_macros.hpp>
+#include <jau/cpp_lang_util.hpp>
#include <jau/debug.hpp>
#include <jau/basic_types.hpp>
#include <jau/ordered_atomic.hpp>
diff --git a/include/jau/cpp_lang_macros.hpp b/include/jau/cpp_lang_macros.hpp
deleted file mode 100644
index 7d45922..0000000
--- a/include/jau/cpp_lang_macros.hpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (c) 2020 Gothel Software e.K.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#ifndef CPP_LANG_MACROS_HPP_
-#define CPP_LANG_MACROS_HPP_
-
- /**
- * <code>constexpr</code> enabled for C++20.
- * <p>
- * The alternative qualifier used is `inline`,
- * as it is implied for for `constexpr` used for functions.
- * </p>
- */
-#if __cplusplus > 201703L
- #define constexpr_func_cxx20 constexpr
-#else
- #define constexpr_func_cxx20 inline
-#endif
-
- /**
- * Used when designed to declare a function <code>constexpr</code>,
- * but prohibited by its specific implementation.
- * <p>
- * The alternative qualifier used is `inline`,
- * as it is implied for for `constexpr` used for functions.
- * </p>
- * <p>
- * Here it but uses non-literal variables, such as std::lock_guard etc.
- * As these can't be evaluated at compile time, the standard does
- * not allow using <code>constexpr</code> here.
- * </p>
- * <p>
- * Empty until standard defines otherwise.
- * </p>
- */
- #define constexpr_fun_non_literal_var inline
-
- /**
- * Used when designed to declare a function <code>constexpr</code>,
- * but prohibited by its specific implementation.
- * <p>
- * The alternative qualifier used is `inline`,
- * as it is implied for for `constexpr` used for functions.
- * </p>
- * <p>
- * Here it uses thread-safety related measures like atomic storage
- * or mutex locks, which are non-literal variables and hence
- * prohibit the use of <code>constexpr</code>.
- * </p>
- * @see constexpr_non_literal_var
- */
- #define constexpr_func_atomic inline
-
- /**
- * Set define if RTTI is enabled during compilation,
- * implying its runtime availability.
- * <pre>
- * - clang ('__clang__') may have '__has_feature(cxx_rtti)'
- * - g++ ('__GNUC__') may have '__GXX_RTTI'
- * - msvc (_MSC_VER) may have: '_CPPRTTI'
- * </pre>
- */
- #if defined(__clang__)
- #if __has_feature(cxx_rtti)
- #define __cxx_rtti_available__ 1
- #endif
- #else
- #if defined(__GXX_RTTI) || defined(_CPPRTTI)
- #define __cxx_rtti_available__ 1
- #endif
- #endif
-
-#endif /* CPP_LANG_MACROS_HPP_ */
diff --git a/include/jau/cpp_lang_util.hpp b/include/jau/cpp_lang_util.hpp
new file mode 100644
index 0000000..3a30f05
--- /dev/null
+++ b/include/jau/cpp_lang_util.hpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2020 Gothel Software e.K.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef CPP_LANG_EXT_HPP_
+#define CPP_LANG_EXT_HPP_
+
+#include <type_traits>
+
+namespace jau {
+
+ /**
+ * <code>constexpr</code> enabled for C++20.
+ * <p>
+ * The alternative qualifier used is `inline`,
+ * as it is implied for for `constexpr` used for functions.
+ * </p>
+ */
+#if __cplusplus > 201703L
+ #define constexpr_func_cxx20 constexpr
+#else
+ #define constexpr_func_cxx20 inline
+#endif
+
+ /**
+ * Used when designed to declare a function <code>constexpr</code>,
+ * but prohibited by its specific implementation.
+ * <p>
+ * The alternative qualifier used is `inline`,
+ * as it is implied for for `constexpr` used for functions.
+ * </p>
+ * <p>
+ * Here it but uses non-literal variables, such as std::lock_guard etc.
+ * As these can't be evaluated at compile time, the standard does
+ * not allow using <code>constexpr</code> here.
+ * </p>
+ * <p>
+ * Empty until standard defines otherwise.
+ * </p>
+ */
+ #define constexpr_fun_non_literal_var inline
+
+ /**
+ * Used when designed to declare a function <code>constexpr</code>,
+ * but prohibited by its specific implementation.
+ * <p>
+ * The alternative qualifier used is `inline`,
+ * as it is implied for for `constexpr` used for functions.
+ * </p>
+ * <p>
+ * Here it uses thread-safety related measures like atomic storage
+ * or mutex locks, which are non-literal variables and hence
+ * prohibit the use of <code>constexpr</code>.
+ * </p>
+ * @see constexpr_non_literal_var
+ */
+ #define constexpr_func_atomic inline
+
+ #if defined(__clang__)
+ #if __has_feature(cxx_rtti)
+ /**
+ * Set define if RTTI is enabled during compilation,
+ * implying its runtime availability.
+ * <pre>
+ * - clang ('__clang__') may have '__has_feature(cxx_rtti)'
+ * - g++ ('__GNUC__') may have '__GXX_RTTI'
+ * - msvc (_MSC_VER) may have: '_CPPRTTI'
+ * </pre>
+ */
+ #define __cxx_rtti_available__ 1
+ #endif
+ #else
+ #if defined(__GXX_RTTI) || defined(_CPPRTTI)
+ /**
+ * Set define if RTTI is enabled during compilation,
+ * implying its runtime availability.
+ * <pre>
+ * - clang ('__clang__') may have '__has_feature(cxx_rtti)'
+ * - g++ ('__GNUC__') may have '__GXX_RTTI'
+ * - msvc (_MSC_VER) may have: '_CPPRTTI'
+ * </pre>
+ */
+ #define __cxx_rtti_available__ 1
+ #endif
+ #endif
+
+ /**
+ // *************************************************
+ // *************************************************
+ // *************************************************
+ */
+
+ #if defined __has_builtin
+ #if __has_builtin(__builtin_bit_cast)
+ #define __has_builtin_bit_cast 1
+ #endif
+ #endif
+
+ /**
+ * Convenience type trait for `__has_builtin(__builtin_bit_cast)`.
+ * @tparam Dummy_type just to make template `SFINAE` happy
+ * @see jau::is_builtin_bit_cast_available()
+ * @see jau::bit_cast()
+ * @see jau::pointer_cast()
+ */
+ template <typename Dummy_type>
+ struct has_builtin_bit_cast
+ #if defined __has_builtin_bit_cast
+ : std::true_type
+ #else
+ : std::false_type
+ #endif
+ {};
+ /**
+ * Value access of has_builtin_bit_cast type trait for convenience ..
+ * @tparam Dummy_type just to make template `SFINAE` happy
+ * @see has_builtin_bit_cast
+ */
+ template <typename Dummy_type> inline constexpr bool has_builtin_bit_cast_v = has_builtin_bit_cast<Dummy_type>::value;
+
+ #if !defined __has_builtin_bit_cast
+ /**
+ * Dummy definition in the absence of this builtin function
+ * as required to have this compilation unit compile clean.
+ * @param Dest_type the target type
+ * @param Value_arg the source value argument
+ */
+ #define __builtin_bit_cast(Dest_type,Value_arg) 0
+ #endif
+
+ namespace impl {
+ template<class Dummy_type>
+ constexpr bool has_builtin_bit_cast_impl(
+ std::enable_if_t< has_builtin_bit_cast_v<Dummy_type>, bool> = true ) noexcept
+ {
+ return true;
+ }
+
+ template<class Dummy_type>
+ constexpr bool has_builtin_bit_cast_impl(
+ std::enable_if_t< !has_builtin_bit_cast_v<Dummy_type>, bool> = true ) noexcept
+ {
+ return false;
+ }
+ }
+
+ /**
+ * Query whether `__builtin_bit_cast(Dest_type, arg)` is available, using jau::has_builtin_bit_cast.
+ *
+ * - - - - - - - - - - - - - - -
+ *
+ * Availability of `__builtin_bit_cast(Dest_type, arg)`
+ *
+ * Reflecting my manual platform tests using `test_basictypeconv.cpp`
+ *
+ * Compiler | Version | Architecture | Available |
+ * :--------- | -------: | :------------------ | :-------- |
+ * GCC | 8.3.0 | amd64, arm64, arm32 | no |
+ * GCC | 10.2.1 | amd64 | no |
+ * clang | 9.0.1 | amd64, arm64 | yes |
+ * clang | 11.0.1 | amd64 | yes |
+ *
+ * @return `true` if query subject is available, otherwise not.
+ * @see has_builtin_bit_cast
+ * @see bit_cast()
+ * @see pointer_cast()
+ */
+ constexpr bool is_builtin_bit_cast_available() noexcept {
+ return impl::has_builtin_bit_cast_impl<bool>();
+ }
+
+ /**
+ * C++20 `bit_cast<>(arg)` implementation for C++17.
+ * <p>
+ * Functional if is_builtin_bit_cast_available() evaluates `true`.
+ * </p>
+ * @tparam Dest the target type
+ * @tparam Source the source argument type
+ * @param src the value to convert to Dest type
+ * @return the converted Dest type value
+ * @see jau::has_builtin_bit_cast
+ * @see is_builtin_bit_cast_available()
+ * @see pointer_cast()
+ */
+ template <class Dest, class Source>
+ constexpr
+ typename 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
+ {
+ if( is_builtin_bit_cast_available() ) {
+ return __builtin_bit_cast(Dest, src);
+ } else {
+ (void)src;
+ return 0;
+ }
+ }
+
+ /**
+ * A `constexpr` pointer cast implementation for C++17,
+ * inspired by C++20 `bit_cast<>(arg)`.
+ * <p>
+ * If is_builtin_bit_cast_available() evaluates `true`,
+ * implementation uses `__builtin_bit_cast(Dest, src)`.<br>
+ *
+ * Otherwise a simple `reinterpret_cast<Dest>(src)` is utilized,
+ * which officially is questionable to deliver a `constexpr`.
+ * </p>
+ * @tparam Dest the target pointer type
+ * @tparam Source the source pointer argument type
+ * @param src the pointer to convert to Dest pointer type
+ * @return the converted Dest pointer type value
+ * @see jau::has_builtin_bit_cast
+ * @see is_builtin_bit_cast_available()
+ * @see bit_cast()
+ */
+ template <class Dest, class Source>
+ constexpr
+ typename 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
+ {
+ if( is_builtin_bit_cast_available() ) {
+ return __builtin_bit_cast(Dest, src);
+ } else {
+ // not 'really' constexpr .. oops, working though
+ return reinterpret_cast<Dest>(src);
+ }
+ }
+
+
+} // namespace jau
+
+#endif /* CPP_LANG_EXT_HPP_ */
diff --git a/include/jau/cpp_pragma.hpp b/include/jau/cpp_pragma.hpp
new file mode 100644
index 0000000..771d261
--- /dev/null
+++ b/include/jau/cpp_pragma.hpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2020 Gothel Software e.K.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef CPP_PRAGMA_HPP_
+#define CPP_PRAGMA_HPP_
+
+namespace jau {
+
+#if defined(_MSC_VER)
+ #define PRAGMA_DISABLE_WARNING_PUSH __pragma(warning( push ))
+ #define PRAGMA_DISABLE_WARNING_POP __pragma(warning( pop ))
+ #define PRAGMA_DISABLE_WARNING(warningNumber) __pragma(warning( disable : warningNumber ))
+
+ #define PRAGMA_DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER PRAGMA_DISABLE_WARNING(4100)
+ #define PRAGMA_DISABLE_WARNING_UNREFERENCED_FUNCTION PRAGMA_DISABLE_WARNING(4505)
+ #define PRAGMA_DISABLE_WARNING_CPP
+ #define PRAGMA_DISABLE_WARNING_MULTICHAR
+
+#elif defined(__GNUC__) || defined(__clang__)
+ #define DO_PRAGMA(X) _Pragma(#X)
+ #define PRAGMA_DISABLE_WARNING_PUSH DO_PRAGMA(GCC diagnostic push)
+ #define PRAGMA_DISABLE_WARNING_POP DO_PRAGMA(GCC diagnostic pop)
+ #define PRAGMA_DISABLE_WARNING(warningName) DO_PRAGMA(GCC diagnostic ignored #warningName)
+ #define PRAGMA_WARNING_ONLY(warningName) DO_PRAGMA(GCC diagnostic warning #warningName)
+
+ #define PRAGMA_DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER PRAGMA_DISABLE_WARNING(-Wunused-parameter)
+ #define PRAGMA_DISABLE_WARNING_UNREFERENCED_FUNCTION PRAGMA_DISABLE_WARNING(-Wunused-function)
+ #define PRAGMA_DISABLE_WARNING_CPP PRAGMA_DISABLE_WARNING(-Wcpp)
+ #define PRAGMA_DISABLE_WARNING_MULTICHAR PRAGMA_DISABLE_WARNING(-Wmultichar)
+
+#else
+ #define PRAGMA_DISABLE_WARNING_PUSH
+ #define PRAGMA_DISABLE_WARNING_POP
+ #define PRAGMA_DISABLE_WARNING_UNREFERENCED_FORMAL_PARAMETER
+ #define PRAGMA_DISABLE_WARNING_UNREFERENCED_FUNCTION
+ #define PRAGMA_DISABLE_WARNING_CPP
+ #define PRAGMA_DISABLE_WARNING_MULTICHAR
+#endif
+
+} // namespace jau
+
+#endif /* CPP_PRAGMA_HPP_ */
diff --git a/include/jau/int_math.hpp b/include/jau/int_math.hpp
index cd37795..1d0e926 100644
--- a/include/jau/int_math.hpp
+++ b/include/jau/int_math.hpp
@@ -26,38 +26,12 @@
#ifndef JAU_BASIC_INT_MATH_HPP_
#define JAU_BASIC_INT_MATH_HPP_
+#include <cstdint>
#include <cmath>
-namespace jau {
- /**
- // *************************************************
- // *************************************************
- // *************************************************
- */
-
- /**
- * Natural 'size_t' alternative using 'unsigned int' as its natural sized type.
- * <p>
- * The leading 'n' stands for natural.
- * </p>
- * <p>
- * This is a compromise to indicate intend,
- * but to avoid handling a multiple sized 'size_t' footprint where not desired.
- * </p>
- */
- typedef unsigned int nsize_t;
+#include <jau/int_types.hpp>
- /**
- * Natural 'ssize_t' alternative using 'signed int' as its natural sized type.
- * <p>
- * The leading 'n' stands for natural.
- * </p>
- * <p>
- * This is a compromise to indicate intend,
- * but to avoid handling a multiple sized 'ssize_t' footprint where not desired.
- * </p>
- */
- typedef signed int snsize_t;
+namespace jau {
/**
// *************************************************
diff --git a/include/jau/int_types.hpp b/include/jau/int_types.hpp
new file mode 100644
index 0000000..edebcb6
--- /dev/null
+++ b/include/jau/int_types.hpp
@@ -0,0 +1,133 @@
+/*
+ * Author: Sven Gothel <[email protected]>
+ * Copyright (c) 2021 Gothel Software e.K.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef JAU_INT_TYPES_HPP_
+#define JAU_INT_TYPES_HPP_
+
+#include <cstdint>
+#include <cstring>
+
+#include <jau/packed_attribute.hpp>
+
+namespace jau {
+ /**
+ * Natural 'size_t' alternative using `uint_fast32_t` as its natural sized type.
+ * <p>
+ * The leading 'n' stands for natural.
+ * </p>
+ * <p>
+ * This is a compromise to indicate intend,
+ * but to avoid handling a multiple sized `size_t` footprint where not desired.
+ * </p>
+ */
+ typedef uint_fast32_t nsize_t;
+
+ /**
+ * Natural 'ssize_t' alternative using `int_fast32_t` as its natural sized type.
+ * <p>
+ * The leading 'n' stands for natural.
+ * </p>
+ * <p>
+ * This is a compromise to indicate intend,
+ * but to avoid handling a multiple sized `ssize_t` footprint where not desired.
+ * </p>
+ */
+ typedef int_fast32_t snsize_t;
+
+ /**
+ // *************************************************
+ // *************************************************
+ // *************************************************
+ */
+
+ __pack( struct uint128_t {
+ uint8_t data[16];
+
+ constexpr uint128_t() noexcept : data{0} {}
+ constexpr uint128_t(const uint128_t &o) noexcept = default;
+ uint128_t(uint128_t &&o) noexcept = default;
+ constexpr uint128_t& operator=(const uint128_t &o) noexcept = default;
+ uint128_t& operator=(uint128_t &&o) noexcept = default;
+
+ void clear() noexcept { bzero(data, sizeof(data)); }
+
+ constexpr bool operator==(uint128_t const &o) const noexcept {
+ if( this == &o ) {
+ return true;
+ }
+ return !std::memcmp(data, o.data, sizeof(data));
+ }
+ constexpr bool operator!=(uint128_t const &o) const noexcept
+ { return !(*this == o); }
+ } ) ;
+
+ __pack( struct uint192_t {
+ uint8_t data[24];
+
+ constexpr uint192_t() noexcept : data{0} {}
+ constexpr uint192_t(const uint192_t &o) noexcept = default;
+ uint192_t(uint192_t &&o) noexcept = default;
+ constexpr uint192_t& operator=(const uint192_t &o) noexcept = default;
+ uint192_t& operator=(uint192_t &&o) noexcept = default;
+
+ void clear() noexcept { bzero(data, sizeof(data)); }
+
+ constexpr bool operator==(uint192_t const &o) const noexcept {
+ if( this == &o ) {
+ return true;
+ }
+ return !std::memcmp(data, o.data, sizeof(data));
+ }
+ constexpr bool operator!=(uint192_t const &o) const noexcept
+ { return !(*this == o); }
+ } );
+
+ __pack( struct uint256_t {
+ uint8_t data[32];
+
+ constexpr uint256_t() noexcept : data{0} {}
+ constexpr uint256_t(const uint256_t &o) noexcept = default;
+ uint256_t(uint256_t &&o) noexcept = default;
+ constexpr uint256_t& operator=(const uint256_t &o) noexcept = default;
+ uint256_t& operator=(uint256_t &&o) noexcept = default;
+
+ void clear() noexcept { bzero(data, sizeof(data)); }
+
+ constexpr bool operator==(uint256_t const &o) const noexcept {
+ if( this == &o ) {
+ return true;
+ }
+ return !std::memcmp(data, o.data, sizeof(data));
+ }
+ constexpr bool operator!=(uint256_t const &o) const noexcept
+ { return !(*this == o); }
+ } );
+
+} // namespace jau
+
+/** \example test_basictypeconv.cpp
+ * This C++ unit test validates the jau::bswap and get/set value implementation
+ */
+
+#endif /* JAU_INT_TYPES_HPP_ */
diff --git a/include/jau/string_util.hpp b/include/jau/string_util.hpp
new file mode 100644
index 0000000..54578a8
--- /dev/null
+++ b/include/jau/string_util.hpp
@@ -0,0 +1,329 @@
+/*
+ * Author: Sven Gothel <[email protected]>
+ * Copyright (c) 2021 Gothel Software e.K.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef JAU_STRING_UTIL_HPP_
+#define JAU_STRING_UTIL_HPP_
+
+#include <cstdint>
+#include <cstring>
+#include <string>
+#include <memory>
+#include <type_traits>
+
+#include <jau/cpp_lang_util.hpp>
+#include <jau/packed_attribute.hpp>
+#include <jau/type_traits_queries.hpp>
+
+#include <jau/int_types.hpp>
+#include <jau/int_math.hpp>
+
+namespace jau {
+
+ /**
+ * Returns a C++ String taken from buffer with maximum length of min(max_len, max_len).
+ * <p>
+ * The maximum length only delimits the string length and does not contain the EOS null byte.
+ * An EOS null byte will will be added.
+ * </p>
+ * <p>
+ * The source string within buffer is not required to contain an EOS null byte;
+ * </p>
+ */
+ std::string get_string(const uint8_t *buffer, nsize_t const buffer_len, nsize_t const max_len) noexcept;
+
+ /** trim in place */
+ void trimInPlace(std::string &s) noexcept;
+
+ /** trim copy */
+ std::string trimCopy(const std::string &s) noexcept;
+
+ /**
+ // *************************************************
+ // *************************************************
+ // *************************************************
+ */
+
+ /**
+ * Produce a hexadecimal string representation of the given byte values.
+ * <p>
+ * If lsbFirst is true, orders LSB left -> MSB right, usual for byte streams. Result will not have a leading `0x`.<br>
+ * Otherwise orders MSB left -> LSB right, usual for readable integer values. Result will have a leading `0x`.
+ * </p>
+ * @param bytes pointer to the first byte to print, less offset
+ * @param offset offset to bytes pointer to the first byte to print
+ * @param length number of bytes to print
+ * @param lsbFirst true having the least significant byte printed first (lowest addressed byte to highest),
+ * otherwise have the most significant byte printed first (highest addressed byte to lowest).
+ * A leading `0x` will be prepended if `lsbFirst == false`.
+ * @param lowerCase true to use lower case hex-chars, otherwise capital letters are being used.
+ * @return the hex-string representation of the data
+ */
+ std::string bytesHexString(const uint8_t * bytes, const nsize_t offset, const nsize_t length,
+ const bool lsbFirst, const bool lowerCase=true) noexcept;
+
+ /**
+ * Produce a hexadecimal string representation of the given byte value.
+ * @param dest the std::string reference destination to append
+ * @param value the byte value to represent
+ * @param lowerCase true to use lower case hex-chars, otherwise capital letters are being used.
+ * @return the given std::string reference for chaining
+ */
+ std::string& byteHexString(std::string& dest, const uint8_t value, const bool lowerCase) noexcept;
+
+ /**
+ * Produce a lower-case hexadecimal string representation of the given uint8_t values.
+ * @param v the value
+ * @return the hex-string representation of the value
+ */
+ inline std::string uint8HexString(const uint8_t v) noexcept {
+ return bytesHexString(pointer_cast<const uint8_t*>(&v), 0, sizeof(v), false /* lsbFirst */);
+ }
+
+ /**
+ * Produce a lower-case hexadecimal string representation of the given uint16_t value.
+ * @param v the value
+ * @return the hex-string representation of the value
+ */
+ inline std::string uint16HexString(const uint16_t v) noexcept {
+ return bytesHexString(pointer_cast<const uint8_t*>(&v), 0, sizeof(v), false /* lsbFirst */);
+ }
+
+ /**
+ * Produce a lower-case hexadecimal string representation of the given uint32_t value.
+ * @param v the value
+ * @return the hex-string representation of the value
+ */
+ inline std::string uint32HexString(const uint32_t v) noexcept {
+ return bytesHexString(pointer_cast<const uint8_t*>(&v), 0, sizeof(v), false /* lsbFirst */);
+ }
+
+ /**
+ * Produce a lower-case hexadecimal string representation of the given uint64_t value.
+ * @param v the value
+ * @return the hex-string representation of the value
+ */
+ inline std::string uint64HexString(const uint64_t& v) noexcept {
+ return bytesHexString(pointer_cast<const uint8_t*>(&v), 0, sizeof(v), false /* lsbFirst */);
+ }
+
+ /**
+ * Produce a lower-case hexadecimal string representation of the given 'void *' value.
+ * @param v the value
+ * @return the hex-string representation of the value
+ */
+ inline std::string aptrHexString(const void * v) noexcept {
+ return uint64HexString(reinterpret_cast<uint64_t>(v));
+ }
+
+ /**
+ * Produce a lower-case hexadecimal string representation of the given uint128_t value.
+ * @param v the value
+ * @return the hex-string representation of the value
+ */
+ inline std::string uint128HexString(const uint128_t& v) noexcept {
+ return bytesHexString(v.data, 0, sizeof(v.data), false /* lsbFirst */);
+ }
+
+ /**
+ * Produce a lower-case hexadecimal string representation of the given uint256_t value.
+ * @param v the value
+ * @return the hex-string representation of the value
+ */
+ inline std::string uint256HexString(const uint256_t& v) noexcept {
+ return bytesHexString(v.data, 0, sizeof(v.data), false /* lsbFirst */);
+ }
+
+ template<typename T>
+ inline
+ typename std::enable_if_t<
+ std::is_standard_layout_v<T>,
+ std::string>
+ to_hex_string(T const & v) noexcept
+ {
+ return bytesHexString(pointer_cast<const uint8_t*>(&v), 0, sizeof(v), false /* lsbFirst */);
+ }
+
+ /**
+ // *************************************************
+ // *************************************************
+ // *************************************************
+ */
+
+ /**
+ * Produce a decimal string representation of an integral integer value.
+ * @tparam T an integral integer type
+ * @param v the integral integer value
+ * @param separator if not 0, use as separation character, otherwise no separation characters are being used
+ * @param width the minimum number of characters to be printed. Add padding with blank space if result is shorter.
+ * @return the string representation of the integral integer value
+ */
+ template<class T>
+ std::string to_decimal_string(const T& v, const char separator=',', const nsize_t width=0) noexcept {
+ const snsize_t v_sign = jau::sign<T>(v);
+ const nsize_t digit10_count1 = jau::digits10<T>(v, v_sign, true /* sign_is_digit */);
+ const nsize_t digit10_count2 = v_sign < 0 ? digit10_count1 - 1 : digit10_count1; // less sign
+
+ const nsize_t comma_count = 0 == separator ? 0 : ( digit10_count1 - 1 ) / 3;
+ const nsize_t net_chars = digit10_count1 + comma_count;
+ const nsize_t total_chars = std::max<nsize_t>(width, net_chars);
+ std::string res(total_chars, ' ');
+
+ T n = v;
+ nsize_t char_iter = 0;
+
+ for(nsize_t digit10_iter = 0; digit10_iter < digit10_count2 /* && char_iter < total_chars */; digit10_iter++ ) {
+ const int digit = v_sign < 0 ? invert_sign( n % 10 ) : n % 10;
+ n /= 10;
+ if( 0 < digit10_iter && 0 == digit10_iter % 3 ) {
+ res[total_chars-1-(char_iter++)] = separator;
+ }
+ res[total_chars-1-(char_iter++)] = '0' + digit;
+ }
+ if( v_sign < 0 /* && char_iter < total_chars */ ) {
+ res[total_chars-1-(char_iter++)] = '-';
+ }
+ return res;
+ }
+
+ /**
+ * Produce a decimal string representation of an int32_t value.
+ * @param v the value
+ * @param separator if not 0, use as separation character, otherwise no separation characters are being used
+ * @param width the minimum number of characters to be printed. Add padding with blank space if result is shorter.
+ * @return the string representation of the value
+ */
+ inline std::string int32DecString(const int32_t v, const char separator=',', const nsize_t width=0) noexcept {
+ return to_decimal_string<int32_t>(v, separator, width);
+ }
+
+ /**
+ * Produce a decimal string representation of a uint32_t value.
+ * @param v the value
+ * @param separator if not 0, use as separation character, otherwise no separation characters are being used
+ * @param width the minimum number of characters to be printed. Add padding with blank space if result is shorter.
+ * @return the string representation of the value
+ */
+ inline std::string uint32DecString(const uint32_t v, const char separator=',', const nsize_t width=0) noexcept {
+ return to_decimal_string<uint32_t>(v, separator, width);
+ }
+
+ /**
+ * Produce a decimal string representation of an int64_t value.
+ * @param v the value
+ * @param separator if not 0, use as separation character, otherwise no separation characters are being used
+ * @param width the minimum number of characters to be printed. Add padding with blank space if result is shorter.
+ * @return the string representation of the value
+ */
+ inline std::string int64DecString(const int64_t& v, const char separator=',', const nsize_t width=0) noexcept {
+ return to_decimal_string<int64_t>(v, separator, width);
+ }
+
+ /**
+ * Produce a decimal string representation of a uint64_t value.
+ * @param v the value
+ * @param separator if not 0, use as separation character, otherwise no separation characters are being used
+ * @param width the minimum number of characters to be printed. Add padding with blank space if result is shorter.
+ * @return the string representation of the value
+ */
+ inline std::string uint64DecString(const uint64_t& v, const char separator=',', const nsize_t width=0) noexcept {
+ return to_decimal_string<uint64_t>(v, separator, width);
+ }
+
+ /**
+ // *************************************************
+ // *************************************************
+ // *************************************************
+ */
+
+ template< class value_type,
+ std::enable_if_t< std::is_integral_v<value_type> ||
+ std::is_floating_point_v<value_type>,
+ bool> = true>
+ std::string to_string(const value_type & ref)
+ {
+ return std::to_string(ref);
+ }
+ template< class value_type,
+ std::enable_if_t<!std::is_integral_v<value_type> &&
+ !std::is_floating_point_v<value_type> &&
+ std::is_pointer_v<value_type>,
+ bool> = true>
+ std::string to_string(const value_type & ref)
+ {
+ return aptrHexString((void*)ref);
+ }
+
+ template< class value_type,
+ std::enable_if_t<!std::is_integral_v<value_type> &&
+ !std::is_floating_point_v<value_type> &&
+ !std::is_pointer_v<value_type> &&
+ jau::has_toString_v<value_type>,
+ bool> = true>
+ std::string to_string(const value_type & ref) {
+ return ref.toString();
+ }
+
+ template< class value_type,
+ std::enable_if_t<!std::is_integral_v<value_type> &&
+ !std::is_floating_point_v<value_type> &&
+ !std::is_pointer_v<value_type> &&
+ !jau::has_toString_v<value_type> &&
+ jau::has_to_string_v<value_type>,
+ bool> = true>
+ std::string to_string(const value_type & ref) {
+ return ref.to_string();
+ }
+
+ template< class value_type,
+ std::enable_if_t<!std::is_integral_v<value_type> &&
+ !std::is_floating_point_v<value_type> &&
+ !std::is_pointer_v<value_type> &&
+ !jau::has_toString_v<value_type> &&
+ !jau::has_to_string_v<value_type> &&
+ jau::has_member_of_pointer_v<value_type>,
+ bool> = true>
+ std::string to_string(const value_type & ref) {
+ return aptrHexString((void*)ref.operator->());
+ }
+
+ template< class value_type,
+ std::enable_if_t<!std::is_integral_v<value_type> &&
+ !std::is_floating_point_v<value_type> &&
+ !std::is_pointer_v<value_type> &&
+ !jau::has_toString_v<value_type> &&
+ !jau::has_to_string_v<value_type> &&
+ !jau::has_member_of_pointer_v<value_type>,
+ bool> = true>
+ std::string to_string(const value_type & ref) {
+ (void)ref;
+ return "jau::to_string<T> not available for "+type_cue<value_type>::print("unknown", TypeTraitGroup::ALL);
+ }
+
+} // namespace jau
+
+/** \example test_intdecstring01.cpp
+ * This C++ unit test validates the jau::to_decimal_string implementation
+ */
+
+#endif /* JAU_STRING_UTIL_HPP_ */
diff --git a/include/jau/type_traits_queries.hpp b/include/jau/type_traits_queries.hpp
index 42fdec8..d2db3db 100644
--- a/include/jau/type_traits_queries.hpp
+++ b/include/jau/type_traits_queries.hpp
@@ -32,20 +32,9 @@
#include <cstring>
#include <string>
-#include <memory>
#include <cstdint>
-#include <vector>
#include <type_traits>
-extern "C" {
- #include <endian.h>
- #include <byteswap.h>
-}
-
-#include <jau/int_math.hpp>
-#include <jau/cpp_lang_macros.hpp>
-#include <jau/packed_attribute.hpp>
-
namespace jau {
// Author: Sven Gothel