25#ifndef JAU_STRING_UTIL_HPP_
26#define JAU_STRING_UTIL_HPP_
64 return 0 != std::iscntrl(c) || 0 != std::isprint(c);
76 constexpr bool is_space(
const char c)
noexcept {
78 case ' ':
return true;
79 case '\f':
return true;
80 case '\n':
return true;
81 case '\r':
return true;
82 case '\t':
return true;
83 case '\v':
return true;
84 default:
return false;
89 constexpr bool is_digit(
const char c,
const uint32_t radix=10,
const char separator = 0) noexcept {
90 if( separator && separator == c ) {
95 return (
'0' <= c && c <=
'9')
96 || (
'A' <= c && c <=
'F')
97 || (
'a' <= c && c <=
'f');
99 return '0' <= c && c <=
'9';
101 return '0' <= c && c <=
'7';
103 return '0' <= c && c <=
'1';
110 constexpr int32_t
digit(
const uint8_t c,
const uint32_t radix=10) noexcept {
113 if (
'0' <= c && c <=
'9') {
116 if (
'A' <= c && c <=
'F') {
119 if (
'a' <= c && c <=
'f') {
124 if (
'0' <= c && c <=
'9') {
129 if (
'0' <= c && c <=
'7') {
134 if (
'0' <= c && c <=
'1') {
143 constexpr int32_t
hexDigit(
const uint8_t c)
noexcept {
163 std::string
trim(
const std::string &s);
166 std::vector<std::string>
split_string(
const std::string &str,
const std::string &separator);
170 std::string
toLower(
const std::string &s);
209 SizeBoolPair
fromHexString(std::vector<uint8_t> &out,
const uint8_t hexstr[],
const size_t hexstr_len,
241 UInt8PtrSizeBoolPair
fromHexString(uint8_t *out,
size_t out_len,
const uint8_t hexstr[],
const size_t hexstr_len,
332 template<
class value_type>
339#if defined(__EMSCRIPTEN__)
341 const uintptr_t v_le =
reinterpret_cast<uintptr_t
>(v);
343 byteOrder, capitalization,
prefix);
345 const uintptr_t v_le =
jau::cpu_to_le(
reinterpret_cast<uintptr_t
>(v));
347 byteOrder, capitalization,
prefix);
363 template<
class u
int8_container_type>
365 std::convertible_to<typename uint8_container_type::value_type, uint8_t>
370 return toHexString((
const uint8_t *)bytes.data(), bytes.size(), byteOrder, capitalization, skipPrefix);
385 template<
class value_type>
395 byteOrder, capitalization,
prefix);
399 byteOrder, capitalization,
prefix);
431 SizeBoolPair
fromBitString(std::vector<uint8_t> &out,
const uint8_t bitstr[],
const size_t bitstr_len,
464 UInt8PtrSizeBoolPair
fromBitString(uint8_t *out,
size_t out_len,
const uint8_t bitstr[],
const size_t bitstr_len,
506 size_t bit_len=0) noexcept;
524 size_t bit_len=0) noexcept {
542 template<
class u
int8_container_type>
544 std::convertible_to<typename uint8_container_type::value_type, uint8_t>
547 return toBitString((
const uint8_t *)bytes.data(), bytes.size(), bitOrder,
prefix, bit_len);
562 template<
class value_type>
572 bitOrder,
prefix, bit_len);
576 bitOrder,
prefix, bit_len);
609 template<std::
integral value_type>
614 std::string_view::const_iterator str_begin = str.cbegin();
615 std::string_view::const_iterator str_end = str.cend();
616 std::string_view::const_iterator begin = str_begin;
620 while( begin < str_end &&
jau::is_space(*begin)) { ++begin; }
622 if (begin < str_end ) {
624 if constexpr (std::is_unsigned_v<value_type>) {
625 return { .s = size_t(begin-str_begin), .b =
false };
629 }
else if (*begin ==
'+') {
634 if( 16 == radix && begin < str_end-1 ) {
635 if ( *begin ==
'0' && (*(begin+1) ==
'x' || *(begin+1) ==
'X') ) {
638 }
else if( 8 == radix && begin < str_end ) {
639 if ( *begin ==
'0' ) {
642 }
else if( 2 == radix && begin < str_end-1 ) {
643 if ( *begin ==
'0' && *(begin+1) ==
'b' ) {
647 if (begin == str_end || !
jau::is_digit(*begin, radix, separator)) {
648 return { .s = size_t(begin-str_begin), .b =
false };
651 std::string_view::const_iterator end = begin;
652 while( end < str_end &&
jau::is_digit(*end, radix, separator)) { ++end; }
653 const size_t len = end-str_begin;
654 std::string_view::const_iterator iter = end;
656 value_type multiplier = 1;
657 while( iter > begin ) {
658 const int32_t d =
digit(*(--iter), radix);
662 const value_type sum = d * multiplier *
sign;
663 if(
sign > 0 && result > std::numeric_limits<value_type>::max() - sum ) {
665 return { .s = len, .b =
false };
667 if constexpr (std::is_signed_v<value_type>) {
668 if(
sign < 0 && result < std::numeric_limits<value_type>::min() - sum ) {
670 return { .s = len, .b =
false };
678 return { .s = size_t(end-str_begin), .b =
true };
681 template<std::
integral value_type>
682 constexpr SizeBoolPair fromIntString(value_type &result,
const char *str,
size_t str_len, uint32_t radix=10,
const char separator = 0) noexcept {
683 return fromIntString(result, std::string_view(str, str_len), radix, separator);
703 template<std::
integral value_type>
707 const uint32_t min_width = 0,
const char separator = 0,
const char padding =
'0') noexcept
709 const size_t dest_start_len = dest.size();
712 case 16: shift = 4;
break;
713 case 10: shift = 0;
break;
714 case 8: shift = 3;
break;
715 case 2: shift = 1;
break;
716 default:
return dest;
718 using unsigned_value_type = std::make_unsigned_t<value_type>;
723 const uint32_t sep_gap = 10 == radix ? 3 : 4;
724 uint32_t sep_count, space_left;
725 if (
'0' == padding) {
729 sep_count = (val_digits - 1) / sep_gap;
730 const uint32_t len0 = sign_len + prefix_len + val_digits + sep_count;
731 if (min_width > len0 && val_digits > 0) {
732 const uint32_t len1 = min_width - sign_len - prefix_len;
733 sep_count = (len1 - 1) / sep_gap;
734 if ( sign_len + prefix_len + (val_digits + sep_count) > min_width ) {
742 sep_count = separator ? (val_digits - 1) / sep_gap : 0;
743 const uint32_t len0 = sign_len + prefix_len + val_digits + sep_count;
744 space_left = min_width > len0 ? min_width - len0 : 0;
747 std::exception_ptr eptr;
749 const uint32_t added_len = std::max(min_width, space_left + sign_len + prefix_len + (val_digits + sep_count));
752 dest.reserve(dest_start_len + added_len + 1);
753 dest.resize(dest_start_len + added_len,
' ');
755 eptr = std::current_exception();
761 const char *
const d_start = dest.data() + dest_start_len;
762 const char *
const d_start_num = d_start + space_left + sign_len + prefix_len;
763 char *d = dest.data()+dest.size();
767 const unsigned_value_type mask = unsigned_value_type(radix - 1);
768 uint32_t digit_cnt = 0, separator_idx = 0;
769 while (d > d_start_num) {
770 if (separator_idx < sep_count && 0 < digit_cnt && 0 == digit_cnt % sep_gap) {
774 if (d > d_start_num) {
775 if (digit_cnt >= val_digits) {
777 }
else if (10 == radix) {
778 *(--d) =
'0' + (v % 10);
781 *(--d) = hex_array[v & mask];
788 if ( prefix_len && d > d_start ) {
790 case 16: *(--d) =
'x';
break;
791 case 2: *(--d) =
'b';
break;
797 if ( sign_len && d > d_start ) {
819 template<std::
integral value_type>
820 std::string
to_string(value_type v,
const uint32_t radix,
823 const uint32_t min_width = 0,
const char separator = 0,
const char padding =
'0') noexcept
842 template<
class value_type,
843 std::enable_if_t<std::is_integral_v<value_type>,
845 std::string&
appendDecString(std::string &dest,
const value_type &val,
const char separator =
'\'',
const uint32_t min_width = 0) noexcept {
846 const size_t dest_start_len = dest.size();
847 using unsigned_value_type = std::make_unsigned_t<value_type>;
851 constexpr uint32_t sep_gap = 3;
852 const uint32_t sep_count = separator ? (val_digits - 1) / sep_gap : 0;
853 const uint32_t num_chars = sign_len + (val_digits + sep_count);
854 const uint32_t added_len = std::max(min_width, num_chars);
855 const uint32_t space_left = added_len - num_chars;
857 std::exception_ptr eptr;
861 dest.reserve(dest_start_len + added_len + 1);
862 dest.resize(dest_start_len + added_len,
' ');
864 eptr = std::current_exception();
870 const char *
const d_start = dest.data() + dest_start_len;
871 const char *
const d_start_num = d_start + space_left + sign_len;
872 char *d = dest.data()+dest.size();
875 uint32_t digit_cnt = 0, separator_idx = 0;
876 while (d > d_start_num) {
877 if (separator_idx < sep_count && 0 < digit_cnt && 0 == digit_cnt % sep_gap) {
881 if (d > d_start_num) {
882 *(--d) =
'0' + (v % 10);
888 if ( sign_len && d > d_start ) {
905 template<
class value_type,
906 std::enable_if_t<std::is_integral_v<value_type>,
908 std::string
to_decstring(
const value_type &v,
const char separator =
'\'',
const nsize_t min_width = 0) noexcept {
920 template<
typename CharT, std::
size_t N>
921 constexpr std::string
to_string(
const CharT (&ref)[N]) {
922 return std::string(ref);
925 template<
class value_type>
926 requires std::is_same_v<jau::StringLiteral<value_type::size>, value_type>
927 constexpr std::string
to_string(
const value_type &ref) {
928 return std::string(ref);
931 template<
class value_type,
932 std::enable_if_t<(std::is_integral_v<value_type> && !std::is_same_v<bool, std::remove_cv_t<value_type>>) ||
933 std::is_floating_point_v<value_type>,
936 return std::to_string(ref);
939 template<
class value_type,
940 std::enable_if_t<std::is_same_v<bool, std::remove_cv_t<value_type>>,
942 inline std::string
to_string(
const value_type &ref) {
943 return ref ?
"T" :
"F";
946 template<
class value_type,
947 std::enable_if_t<!std::is_integral_v<value_type> &&
948 !std::is_floating_point_v<value_type> &&
949 std::is_base_of_v<std::string, value_type>,
951 inline std::string
to_string(
const value_type &ref) {
955 template<
class value_type,
956 std::enable_if_t<!std::is_integral_v<value_type> &&
957 !std::is_floating_point_v<value_type> &&
958 !std::is_base_of_v<std::string, value_type> &&
959 std::is_base_of_v<std::string_view, value_type>,
961 inline std::string
to_string(
const value_type &ref) {
962 return std::string(ref);
965 template<
class value_type,
966 std::enable_if_t<!std::is_integral_v<value_type> &&
967 !std::is_floating_point_v<value_type> &&
968 !std::is_base_of_v<std::string, value_type> &&
969 !std::is_base_of_v<std::string_view, value_type> &&
970 std::is_same_v<char*, jau::req::base_pointer<value_type>>,
972 inline std::string
to_string(
const value_type &ref) {
973 return std::string(ref);
976 template<
class value_type,
977 std::enable_if_t<!std::is_integral_v<value_type> &&
978 !std::is_floating_point_v<value_type> &&
979 !std::is_base_of_v<std::string, value_type> &&
980 !std::is_base_of_v<std::string_view, value_type> &&
981 !std::is_same_v<char*, jau::req::base_pointer<value_type>> &&
982 std::is_pointer_v<value_type>,
984 inline std::string
to_string(
const value_type &ref) {
988 template<
class value_type,
989 std::enable_if_t<!std::is_integral_v<value_type> &&
990 !std::is_floating_point_v<value_type> &&
991 !std::is_base_of_v<std::string, value_type> &&
992 !std::is_base_of_v<std::string_view, value_type> &&
993 !std::is_pointer_v<value_type> &&
996 inline std::string
to_string(
const value_type &ref) {
997 return ref.toString();
1000 template<
class value_type,
1001 std::enable_if_t<!std::is_integral_v<value_type> &&
1002 !std::is_floating_point_v<value_type> &&
1003 !std::is_base_of_v<std::string, value_type> &&
1004 !std::is_base_of_v<std::string_view, value_type> &&
1005 !std::is_pointer_v<value_type> &&
1009 inline std::string
to_string(
const value_type &ref) {
1010 return ref.to_string();
1013 template<
class value_type,
1014 std::enable_if_t<!std::is_integral_v<value_type> &&
1015 !std::is_floating_point_v<value_type> &&
1016 !std::is_base_of_v<std::string, value_type> &&
1017 !std::is_base_of_v<std::string_view, value_type> &&
1018 !std::is_pointer_v<value_type> &&
1023 inline std::string
to_string(
const value_type &ref) {
1027 template<
class value_type,
1028 std::enable_if_t<!std::is_integral_v<value_type> &&
1029 !std::is_floating_point_v<value_type> &&
1030 !std::is_base_of_v<std::string, value_type> &&
1031 !std::is_base_of_v<std::string_view, value_type> &&
1032 !std::is_pointer_v<value_type> &&
1037 inline std::string
to_string(
const value_type &ref) {
1042 template<
typename T>
1043 std::string
to_string(std::vector<T>
const &list,
const std::string &delim) {
1044 if ( list.empty() ) {
1045 return std::string();
1047 bool need_delim =
false;
1049 for (
const T &e : list ) {
1058 template<
typename T>
1061 template<
typename T>
1062 std::string
to_string(std::vector<T>
const &list,
const std::string &delim,
const nsize_t radix) {
1063 if ( list.empty() ) {
1064 return std::string();
1066 bool need_delim =
false;
1068 for (
const T &e : list ) {
1077 template<
typename T>
std::string toString() const noexcept
C++ Named Requirement Container (partial)
C++ Named Requirement ContiguousContainer (partial)
Concept of type-trait std::is_pointer.
Concept of type-trait std::is_standard_layout.
Concept of type-trait std::is_trivially_copyable.
constexpr bool is_little_endian() noexcept
Evaluates true if platform is running in little endian mode, i.e.
bit_order_t
Bit order type, i.e.
constexpr uint16_t bswap(uint16_t const source) noexcept
std::string_view to_string(const endian_t v) noexcept
Return std::string representation of the given endian.
lb_endian_t
Simplified reduced endian type only covering little- and big-endian.
constexpr uint16_t cpu_to_le(uint16_t const h) noexcept
const uint8_t * cast_char_ptr_to_uint8(const char *s) noexcept
@ msb
Identifier for most-significant-bit (msb) first.
@ big
Identifier for big endian.
@ big
Identifier for big endian, equivalent to endian::big.
constexpr bool value(const Bool rhs) noexcept
constexpr bool has_toString_v
constexpr bool has_member_of_pointer_v
constexpr bool has_to_string_v
constexpr std::enable_if_t< sizeof(Dest)==sizeof(Source) &&std::is_pointer_v< Source > &&std::is_pointer_v< Dest >, Dest > pointer_cast(const Source &src) noexcept
A constexpr pointer cast implementation for C++17, inspired by C++20 bit_cast<>(arg).
const jau::type_info & static_ctti() noexcept
Returns a static global reference of make_ctti<T>(true) w/ identity instance.
Bool
Boolean type without implicit conversion, safe for function parameter.
bool handle_exception(std::exception_ptr eptr, const char *file, int line) noexcept
Handle given optional exception (nullable std::exception_ptr) and send std::exception::what() message...
constexpr uint32_t digits10(const T x, const int x_sign, const bool sign_is_digit=true) noexcept
Returns the number of decimal digits of the given integral value number using std::log10<T>().
constexpr uint32_t digits(const T x, const uint32_t radix) noexcept
Returns the number of digits of the given unsigned integral value number and the given radix.
constexpr int sign(const T x) noexcept
Returns the value of the sign function (w/o branching ?) in O(1).
uint_bytes_t< sizeof(unsigned long int)> nsize_t
Natural 'size_t' alternative using uint<XX>_t with xx = sizeof(unsigned long int)*8 as its natural si...
constexpr bool is_positive(const T a) noexcept
Returns true of the given integral is positive, i.e.
constexpr std::make_unsigned_t< T > unsigned_value(const T x) noexcept
Returns the unsigned typed absolute value of an arithmetic number (w/ branching) in O(1)
std::string & toLowerInPlace(std::string &s) noexcept
std::string to_decstring(const value_type &v, const char separator='\'', const nsize_t min_width=0) noexcept
Produces a decimal integer string representation of an integral integer value with given radix.
std::string toLower(const std::string &s)
void trimInPlace(std::string &s) noexcept
trim in place
std::string toBitString(const void *data, const nsize_t length, const bit_order_t bitOrder=bit_order_t::msb, const PrefixOpt prefix=PrefixOpt::prefix, size_t bit_len=0) noexcept
Produce a binary string representation of the given lsb-first byte values.
std::string & appendDecString(std::string &dest, const value_type &val, const char separator='\'', const uint32_t min_width=0) noexcept
Appends a decimal integer string representation of an integral integer value with given radix.
SizeBoolPair fromHexString(std::vector< uint8_t > &out, const uint8_t hexstr[], const size_t hexstr_len, const lb_endian_t byteOrder=lb_endian_t::big, const Bool checkPrefix=Bool::True)
Converts a given hexadecimal string representation, appending to a byte vector (lsb-first).
std::string get_string(const uint8_t *buffer, nsize_t const buffer_len, nsize_t const max_len)
Returns a C++ String taken from buffer with maximum length of min(max_len, max_len).
constexpr SizeBoolPair fromIntString(value_type &result, std::string_view str, uint32_t radix=10, const char separator=0) noexcept
Converts a given integer string representation to the given result reference, compatible with ::strto...
constexpr bool is_digit(const char c, const uint32_t radix=10, const char separator=0) noexcept
Returns true if given char c matches the char symbol range with the radix 16, 10 (default),...
std::string & appendBitString(std::string &dest, const void *data, const nsize_t length, const bit_order_t bitOrder=bit_order_t::msb, const PrefixOpt prefix=PrefixOpt::prefix, size_t bit_len=0) noexcept
Appends a binary string representation of the given lsb-first byte values.
std::vector< std::string > split_string(const std::string &str, const std::string &separator)
Split given string str at separator into the resulting std::vector excluding the separator sequence .
constexpr bool is_space(const char c) noexcept
Returns true if given char c is one of the following whitespace character:
constexpr const char * HexadecimalArrayBig
std::string & appendIntString(std::string &dest, value_type val, const uint32_t radix, const LoUpCase capitalization=LoUpCase::lower, const PrefixOpt prefix=PrefixOpt::prefix, const uint32_t min_width=0, const char separator=0, const char padding='0') noexcept
Appends an integer string representation of an integral integer value with given radix.
std::string trim(const std::string &s)
trim copy
constexpr int32_t digit(const uint8_t c, const uint32_t radix=10) noexcept
Returns digit value of given char c matching the radix 16, 10, 8 or 2, -1 on no match.
constexpr int32_t hexDigit(const uint8_t c) noexcept
std::string & appendHexString(std::string &dest, const void *data, const nsize_t length, const lb_endian_t byteOrder=lb_endian_t::big, const LoUpCase capitalization=LoUpCase::lower, const PrefixOpt prefix=PrefixOpt::prefix) noexcept
Appends a hexadecimal string representation of the given lsb-first byte values.
bool is_ascii_code(int c) noexcept
SizeBoolPair fromBitString(std::vector< uint8_t > &out, const uint8_t bitstr[], const size_t bitstr_len, const bit_order_t bitOrder=bit_order_t::msb, const Bool checkPrefix=Bool::True)
Converts a given binary string representation, appending to a byte vector (lsb-first).
constexpr const char * HexadecimalArrayLow
std::string toHexString(const void *data, const nsize_t length, const lb_endian_t byteOrder=lb_endian_t::big, const LoUpCase capitalization=LoUpCase::lower, const PrefixOpt prefix=PrefixOpt::prefix) noexcept
Produce a hexadecimal string representation of the given lsb-first byte values.
__pack(...): Produces MSVC, clang and gcc compatible lead-in and -out macros.
Simple pre-defined value pair [size_t, bool] for structured bindings to multi-values.
Simple pre-defined value pair [uint8_t*, size_t, bool] for structured bindings to multi-values.
uint_bytes_t< sizeof(unsigned long int)> nsize_t
Natural 'size_t' alternative using uint<XX>_t with xx = sizeof(unsigned long int)*8 as its natural si...