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 const uintptr_t v_le =
jau::cpu_to_le(
reinterpret_cast<uintptr_t
>(v));
341 byteOrder, capitalization,
prefix);
356 template<
class u
int8_container_type>
358 std::convertible_to<typename uint8_container_type::value_type, uint8_t>
363 return toHexString((
const uint8_t *)bytes.data(), bytes.size(), byteOrder, capitalization, skipPrefix);
378 template<
class value_type>
388 byteOrder, capitalization,
prefix);
392 byteOrder, capitalization,
prefix);
424 SizeBoolPair
fromBitString(std::vector<uint8_t> &out,
const uint8_t bitstr[],
const size_t bitstr_len,
457 UInt8PtrSizeBoolPair
fromBitString(uint8_t *out,
size_t out_len,
const uint8_t bitstr[],
const size_t bitstr_len,
499 size_t bit_len=0) noexcept;
517 size_t bit_len=0) noexcept {
535 template<
class u
int8_container_type>
537 std::convertible_to<typename uint8_container_type::value_type, uint8_t>
540 return toBitString((
const uint8_t *)bytes.data(), bytes.size(), bitOrder,
prefix, bit_len);
555 template<
class value_type>
565 bitOrder,
prefix, bit_len);
569 bitOrder,
prefix, bit_len);
602 template<std::
integral value_type>
607 std::string_view::const_iterator str_begin = str.cbegin();
608 std::string_view::const_iterator str_end = str.cend();
609 std::string_view::const_iterator begin = str_begin;
613 while( begin < str_end &&
jau::is_space(*begin)) { ++begin; }
615 if (begin < str_end ) {
617 if constexpr (std::is_unsigned_v<value_type>) {
618 return { .s = size_t(begin-str_begin), .b =
false };
622 }
else if (*begin ==
'+') {
627 if( 16 == radix && begin < str_end-1 ) {
628 if ( *begin ==
'0' && (*(begin+1) ==
'x' || *(begin+1) ==
'X') ) {
631 }
else if( 8 == radix && begin < str_end ) {
632 if ( *begin ==
'0' ) {
635 }
else if( 2 == radix && begin < str_end-1 ) {
636 if ( *begin ==
'0' && *(begin+1) ==
'b' ) {
640 if (begin == str_end || !
jau::is_digit(*begin, radix, separator)) {
641 return { .s = size_t(begin-str_begin), .b =
false };
644 std::string_view::const_iterator end = begin;
645 while( end < str_end &&
jau::is_digit(*end, radix, separator)) { ++end; }
646 const size_t len = end-str_begin;
647 std::string_view::const_iterator iter = end;
649 value_type multiplier = 1;
650 while( iter > begin ) {
651 const int32_t d =
digit(*(--iter), radix);
655 const value_type sum = d * multiplier *
sign;
656 if(
sign > 0 && result > std::numeric_limits<value_type>::max() - sum ) {
658 return { .s = len, .b =
false };
660 if constexpr (std::is_signed_v<value_type>) {
661 if(
sign < 0 && result < std::numeric_limits<value_type>::min() - sum ) {
663 return { .s = len, .b =
false };
671 return { .s = size_t(end-str_begin), .b =
true };
674 template<std::
integral value_type>
675 constexpr SizeBoolPair fromIntString(value_type &result,
const char *str,
size_t str_len, uint32_t radix=10,
const char separator = 0) noexcept {
676 return fromIntString(result, std::string_view(str, str_len), radix, separator);
696 template<std::
integral value_type>
700 const uint32_t min_width = 0,
const char separator = 0,
const char padding =
'0') noexcept
702 const size_t dest_start_len = dest.size();
705 case 16: shift = 4;
break;
706 case 10: shift = 0;
break;
707 case 8: shift = 3;
break;
708 case 2: shift = 1;
break;
709 default:
return dest;
711 using unsigned_value_type = std::make_unsigned_t<value_type>;
716 const uint32_t sep_gap = 10 == radix ? 3 : 4;
717 uint32_t sep_count, space_left;
718 if (
'0' == padding) {
722 sep_count = (val_digits - 1) / sep_gap;
723 const uint32_t len0 = sign_len + prefix_len + val_digits + sep_count;
724 if (min_width > len0 && val_digits > 0) {
725 const uint32_t len1 = min_width - sign_len - prefix_len;
726 sep_count = (len1 - 1) / sep_gap;
727 if ( sign_len + prefix_len + (val_digits + sep_count) > min_width ) {
735 sep_count = separator ? (val_digits - 1) / sep_gap : 0;
736 const uint32_t len0 = sign_len + prefix_len + val_digits + sep_count;
737 space_left = min_width > len0 ? min_width - len0 : 0;
740 std::exception_ptr eptr;
742 const uint32_t added_len = std::max(min_width, space_left + sign_len + prefix_len + (val_digits + sep_count));
745 dest.reserve(dest_start_len + added_len + 1);
746 dest.resize(dest_start_len + added_len,
' ');
748 eptr = std::current_exception();
754 const char *
const d_start = dest.data() + dest_start_len;
755 const char *
const d_start_num = d_start + space_left + sign_len + prefix_len;
756 char *d = dest.data()+dest.size();
760 const unsigned_value_type mask = unsigned_value_type(radix - 1);
761 uint32_t digit_cnt = 0, separator_idx = 0;
762 while (d > d_start_num) {
763 if (separator_idx < sep_count && 0 < digit_cnt && 0 == digit_cnt % sep_gap) {
767 if (d > d_start_num) {
768 if (digit_cnt >= val_digits) {
770 }
else if (10 == radix) {
771 *(--d) =
'0' + (v % 10);
774 *(--d) = hex_array[v & mask];
781 if ( prefix_len && d > d_start ) {
783 case 16: *(--d) =
'x';
break;
784 case 2: *(--d) =
'b';
break;
790 if ( sign_len && d > d_start ) {
812 template<std::
integral value_type>
813 std::string
to_string(value_type v,
const uint32_t radix,
816 const uint32_t min_width = 0,
const char separator = 0,
const char padding =
'0') noexcept
835 template<
class value_type,
836 std::enable_if_t<std::is_integral_v<value_type>,
838 std::string&
appendDecString(std::string &dest,
const value_type &val,
const char separator =
'\'',
const uint32_t min_width = 0) noexcept {
839 const size_t dest_start_len = dest.size();
840 using unsigned_value_type = std::make_unsigned_t<value_type>;
844 constexpr uint32_t sep_gap = 3;
845 const uint32_t sep_count = separator ? (val_digits - 1) / sep_gap : 0;
846 const uint32_t num_chars = sign_len + (val_digits + sep_count);
847 const uint32_t added_len = std::max(min_width, num_chars);
848 const uint32_t space_left = added_len - num_chars;
850 std::exception_ptr eptr;
854 dest.reserve(dest_start_len + added_len + 1);
855 dest.resize(dest_start_len + added_len,
' ');
857 eptr = std::current_exception();
863 const char *
const d_start = dest.data() + dest_start_len;
864 const char *
const d_start_num = d_start + space_left + sign_len;
865 char *d = dest.data()+dest.size();
868 uint32_t digit_cnt = 0, separator_idx = 0;
869 while (d > d_start_num) {
870 if (separator_idx < sep_count && 0 < digit_cnt && 0 == digit_cnt % sep_gap) {
874 if (d > d_start_num) {
875 *(--d) =
'0' + (v % 10);
881 if ( sign_len && d > d_start ) {
898 template<
class value_type,
899 std::enable_if_t<std::is_integral_v<value_type>,
901 std::string
to_decstring(
const value_type &v,
const char separator =
'\'',
const nsize_t min_width = 0) noexcept {
913 template<
typename CharT, std::
size_t N>
914 constexpr std::string
to_string(
const CharT (&ref)[N]) {
915 return std::string(ref);
918 template<
class value_type>
919 requires std::is_same_v<jau::StringLiteral<value_type::size>, value_type>
920 constexpr std::string
to_string(
const value_type &ref) {
921 return std::string(ref);
924 template<
class value_type,
925 std::enable_if_t<(std::is_integral_v<value_type> && !std::is_same_v<bool, std::remove_cv_t<value_type>>) ||
926 std::is_floating_point_v<value_type>,
929 return std::to_string(ref);
932 template<
class value_type,
933 std::enable_if_t<std::is_same_v<bool, std::remove_cv_t<value_type>>,
935 inline std::string
to_string(
const value_type &ref) {
936 return ref ?
"T" :
"F";
939 template<
class value_type,
940 std::enable_if_t<!std::is_integral_v<value_type> &&
941 !std::is_floating_point_v<value_type> &&
942 std::is_base_of_v<std::string, value_type>,
944 inline std::string
to_string(
const value_type &ref) {
948 template<
class value_type,
949 std::enable_if_t<!std::is_integral_v<value_type> &&
950 !std::is_floating_point_v<value_type> &&
951 !std::is_base_of_v<std::string, value_type> &&
952 std::is_base_of_v<std::string_view, value_type>,
954 inline std::string
to_string(
const value_type &ref) {
955 return std::string(ref);
958 template<
class value_type,
959 std::enable_if_t<!std::is_integral_v<value_type> &&
960 !std::is_floating_point_v<value_type> &&
961 !std::is_base_of_v<std::string, value_type> &&
962 !std::is_base_of_v<std::string_view, value_type> &&
963 std::is_same_v<char*, jau::req::base_pointer<value_type>>,
965 inline std::string
to_string(
const value_type &ref) {
966 return std::string(ref);
969 template<
class value_type,
970 std::enable_if_t<!std::is_integral_v<value_type> &&
971 !std::is_floating_point_v<value_type> &&
972 !std::is_base_of_v<std::string, value_type> &&
973 !std::is_base_of_v<std::string_view, value_type> &&
974 !std::is_same_v<char*, jau::req::base_pointer<value_type>> &&
975 std::is_pointer_v<value_type>,
977 inline std::string
to_string(
const value_type &ref) {
981 template<
class value_type,
982 std::enable_if_t<!std::is_integral_v<value_type> &&
983 !std::is_floating_point_v<value_type> &&
984 !std::is_base_of_v<std::string, value_type> &&
985 !std::is_base_of_v<std::string_view, value_type> &&
986 !std::is_pointer_v<value_type> &&
989 inline std::string
to_string(
const value_type &ref) {
990 return ref.toString();
993 template<
class value_type,
994 std::enable_if_t<!std::is_integral_v<value_type> &&
995 !std::is_floating_point_v<value_type> &&
996 !std::is_base_of_v<std::string, value_type> &&
997 !std::is_base_of_v<std::string_view, value_type> &&
998 !std::is_pointer_v<value_type> &&
1002 inline std::string
to_string(
const value_type &ref) {
1003 return ref.to_string();
1006 template<
class value_type,
1007 std::enable_if_t<!std::is_integral_v<value_type> &&
1008 !std::is_floating_point_v<value_type> &&
1009 !std::is_base_of_v<std::string, value_type> &&
1010 !std::is_base_of_v<std::string_view, value_type> &&
1011 !std::is_pointer_v<value_type> &&
1016 inline std::string
to_string(
const value_type &ref) {
1020 template<
class value_type,
1021 std::enable_if_t<!std::is_integral_v<value_type> &&
1022 !std::is_floating_point_v<value_type> &&
1023 !std::is_base_of_v<std::string, value_type> &&
1024 !std::is_base_of_v<std::string_view, value_type> &&
1025 !std::is_pointer_v<value_type> &&
1031 inline std::string
to_string(
const value_type &ref) {
1035 template<
class value_type,
1036 std::enable_if_t<!std::is_integral_v<value_type> &&
1037 !std::is_floating_point_v<value_type> &&
1038 !std::is_base_of_v<std::string, value_type> &&
1039 !std::is_base_of_v<std::string_view, value_type> &&
1040 !std::is_pointer_v<value_type> &&
1046 inline std::string
to_string(
const value_type &ref) {
1051 template<
typename T>
1052 std::string
to_string(std::vector<T>
const &list,
const std::string &delim) {
1053 if ( list.empty() ) {
1054 return std::string();
1056 bool need_delim =
false;
1058 for (
const T &e : list ) {
1067 template<
typename T>
1070 template<
typename T>
1071 std::string
to_string(std::vector<T>
const &list,
const std::string &delim,
const nsize_t radix) {
1072 if ( list.empty() ) {
1073 return std::string();
1075 bool need_delim =
false;
1077 for (
const T &e : list ) {
1086 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.
std::string_view to_string(const endian_t v) noexcept
Return std::string representation of the given endian.
constexpr T bswap(T const &source) noexcept
lb_endian_t
Simplified reduced endian type only covering little- and big-endian.
constexpr T cpu_to_le(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_free_to_string_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...