jaulib v1.5.0
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
string_util.hpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2021-2026 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#ifndef JAU_STRING_UTIL_HPP_
26#define JAU_STRING_UTIL_HPP_
27
28#include <algorithm>
29#include <concepts>
30#include <cstdarg>
31#include <cstdint>
32#include <cstring>
33#include <exception>
34#include <limits>
35#include <string>
36#include <string_view>
37#include <type_traits>
38#include <vector>
39
41#include "jau/type_info.hpp"
42
43#include <jau/byte_util.hpp>
44#include <jau/cpp_lang_util.hpp>
45#include <jau/exceptions.hpp>
47
48#include <jau/int_math.hpp>
49#include <jau/int_types.hpp>
51
53#include <jau/type_concepts.hpp>
54
55namespace jau {
56
57 /** @defgroup StringUtils String Utilities
58 * String utilities for type conversion and manipulation.
59 *
60 * @{
61 */
62
63 inline bool is_ascii_code(int c) noexcept {
64 return 0 != std::iscntrl(c) || 0 != std::isprint(c);
65 }
66
67 /**
68 * Returns true if given char `c` is one of the following whitespace character:
69 * - space (0x20, `` ``)
70 * - form feed (0x0c, ``\f``)
71 * - line feed (0x0a, ``\n``)
72 * - carriage return (0x0d, ``\r``)
73 * - horizontal tab (0x09, ``\t``)
74 * - vertical tab (0x0b, ``\v``)
75 */
76 constexpr bool is_space(const char c) noexcept {
77 switch(c) {
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;
85 }
86 }
87
88 /// Returns true if given char `c` matches the char symbol range with the radix 16, 10 (default), 8 or 2
89 constexpr bool is_digit(const char c, const uint32_t radix=10, const char separator = 0) noexcept {
90 if( separator && separator == c ) {
91 return true;
92 }
93 switch (radix) {
94 case 16:
95 return ('0' <= c && c <= '9')
96 || ('A' <= c && c <= 'F')
97 || ('a' <= c && c <= 'f');
98 case 10:
99 return '0' <= c && c <= '9';
100 case 8:
101 return '0' <= c && c <= '7';
102 case 2:
103 return '0' <= c && c <= '1';
104 default:
105 break;
106 }
107 return false;
108 }
109 /// Returns digit value of given char `c` matching the radix 16, 10, 8 or 2, `-1` on no match
110 constexpr int32_t digit(const uint8_t c, const uint32_t radix=10) noexcept {
111 switch (radix) {
112 case 16:
113 if ('0' <= c && c <= '9') {
114 return c - '0';
115 }
116 if ('A' <= c && c <= 'F') {
117 return c - 'A' + 10;
118 }
119 if ('a' <= c && c <= 'f') {
120 return c - 'a' + 10;
121 }
122 break;
123 case 10:
124 if ('0' <= c && c <= '9') {
125 return c - '0';
126 }
127 break;
128 case 8:
129 if ('0' <= c && c <= '7') {
130 return c - '0';
131 }
132 break;
133 case 2:
134 if ('0' <= c && c <= '1') {
135 return c - '0';
136 }
137 break;
138 default:
139 break;
140 }
141 return -1;
142 }
143 constexpr int32_t hexDigit(const uint8_t c) noexcept {
144 return digit(c, 16);
145 }
146
147 /**
148 * Returns a C++ String taken from buffer with maximum length of min(max_len, max_len).
149 * <p>
150 * The maximum length only delimits the string length and does not contain the EOS null byte.
151 * An EOS null byte will will be added.
152 * </p>
153 * <p>
154 * The source string within buffer is not required to contain an EOS null byte;
155 * </p>
156 */
157 std::string get_string(const uint8_t *buffer, nsize_t const buffer_len, nsize_t const max_len);
158
159 /** trim in place */
160 void trimInPlace(std::string &s) noexcept;
161
162 /** trim copy */
163 std::string trim(const std::string &s);
164
165 /** Split given string `str` at `separator` into the resulting std::vector excluding the separator sequence . */
166 std::vector<std::string> split_string(const std::string &str, const std::string &separator);
167
168 std::string &toLowerInPlace(std::string &s) noexcept;
169
170 std::string toLower(const std::string &s);
171
172 /**
173 // *************************************************
174 // *************************************************
175 // *************************************************
176 */
177
178 enum class LoUpCase : bool {
179 lower = false,
180 upper = true
181 };
182
183 enum class PrefixOpt : bool {
184 none = false,
185 prefix = true
186 };
187
188 /**
189 * Converts a given hexadecimal string representation, appending to a byte vector (lsb-first).
190 *
191 * In case a non valid hexadecimal digit appears in the given string,
192 * conversion ends and fills the byte vector up until the violation.
193 *
194 * In case hexstr contains an odd number of hex-nibbles, it will be interpreted as follows
195 * - 0xf[12] = 0x0f12 = { 0x12, 0x0f } - msb, 1st single low-nibble is most significant
196 * - [12]f = 0xf012 = { 0x12, 0xf0 } - lsb, last single high-nibble is most significant
197 *
198 * Even if complete==false, result holds the partial value if consumed_chars>0.
199 *
200 * You may use C++17 structured bindings to handle the pair.
201 *
202 * @param out the byte vector sink to append, lsb-first
203 * @param hexstr the hexadecimal string representation
204 * @param hexstr_len length of hextstr
205 * @param byteOrder lb_endian_t::big for big-endian bytes in `hexstr` (default)
206 * @param checkPrefix if True, checks for a leading `0x` and removes it, otherwise not.
207 * @return pair [size_t consumed_chars, bool complete], i.e. consumed characters of string and completed=false if not fully consumed.
208 */
209 SizeBoolPair fromHexString(std::vector<uint8_t> &out, const uint8_t hexstr[], const size_t hexstr_len,
210 const lb_endian_t byteOrder = lb_endian_t::big, const Bool checkPrefix = Bool::True);
211
212 /** See hexStringBytes() */
213 inline SizeBoolPair fromHexString(std::vector<uint8_t> &out, const std::string_view hexstr,
214 const lb_endian_t byteOrder = lb_endian_t::big, const Bool checkPrefix = Bool::True) {
215 return jau::fromHexString(out, cast_char_ptr_to_uint8(hexstr.data()), hexstr.length(), byteOrder, checkPrefix); // NOLINT(bugprone-suspicious-stringview-data-usage)
216 }
217
218 /**
219 * Converts a given hexadecimal string representation, storing into a byte array(lsb-first).
220 *
221 * In case a non valid hexadecimal digit appears in the given string,
222 * conversion ends and fills the byte vector up until the violation.
223 *
224 * In case hexstr contains an odd number of hex-nibbles, it will be interpreted as follows
225 * - 0xf[12] = 0x0f12 = { 0x12, 0x0f } - msb, 1st single low-nibble is most significant
226 * - [12]f = 0xf012 = { 0x12, 0xf0 } - lsb, last single high-nibble is most significant
227 *
228 * Even if complete==false, result holds the partial value if consumed_chars>0.
229 *
230 * You may use C++17 structured bindings to handle the triple.
231 *
232 * @param out byte array pointer to store result, lsb-first
233 * @param out_len size of byte array
234 * @param hexstr the hexadecimal string representation
235 * @param hexstr_len length of hextstr
236 * @param byteOrder lb_endian_t::big for big-endian bytes in `hexstr` (default)
237 * @param checkPrefix if True, checks for a leading `0x` and removes it, otherwise not.
238 * @return triple [uint8_t* out_end, size_t consumed_chars, bool complete],
239 * i.e. end pointer of out (last write + 1), consumed characters of string and completed=false if not fully consumed.
240 */
241 UInt8PtrSizeBoolPair fromHexString(uint8_t *out, size_t out_len, const uint8_t hexstr[], const size_t hexstr_len,
242 const lb_endian_t byteOrder = lb_endian_t::big, const Bool checkPrefix = Bool::True) noexcept;
243
244 /** See hexStringBytes() */
245 inline UInt8PtrSizeBoolPair fromHexString(uint8_t *out, size_t out_len, const std::string_view hexstr,
246 const lb_endian_t byteOrder = lb_endian_t::big, const Bool checkPrefix = Bool::True) noexcept {
247 return jau::fromHexString(out, out_len, cast_char_ptr_to_uint8(hexstr.data()), hexstr.length(), byteOrder, checkPrefix); // NOLINT(bugprone-suspicious-stringview-data-usage)
248 }
249
250 /**
251 * Converts a given hexadecimal string representation appending to a uint64_t value according to hexStringBytes().
252 *
253 * Even if complete==false, result holds the partial value if consumed_chars>0.
254 *
255 * You may use C++17 structured bindings to handle the tuple.
256 *
257 * @param hexstr the hexadecimal string representation
258 * @param byteOrder lb_endian_t::big for big-endian bytes in `hexstr` (default)
259 * @param checkPrefix if True, checks for a leading `0x` and removes it, otherwise not.
260 * @return tuple [uint64_t result, size_t consumed_chars, bool complete], i.e. consumed characters of string and completed=false if not fully consumed.
261 * @see hexStringBytes()
262 * @see to_hexstring()
263 */
264 UInt64SizeBoolTuple fromHexString(std::string_view const hexstr, const lb_endian_t byteOrder = lb_endian_t::big,
265 const Bool checkPrefix = Bool::True) noexcept;
266
267 inline constexpr const char *HexadecimalArrayLow = "0123456789abcdef";
268 inline constexpr const char *HexadecimalArrayBig = "0123456789ABCDEF";
269
270 /**
271 * Appends a hexadecimal string representation of the given lsb-first byte values.
272 *
273 * If byteOrder is lb_endian_t::little, orders lsb-byte left, usual for byte streams. Result will not have a leading `0x`.
274 * Otherwise, lb_endian_t::big (default), orders msb-byte left for integer values. Result will have a leading `0x` if !skipPrefix.
275 *
276 * @param dest the std::string to append to
277 * @param data pointer to the first byte to print, lsb-first
278 * @param length number of bytes to print
279 * @param byteOrder lb_endian_t::big for big-endian bytes in resulting hex-string (default).
280 * A leading `0x` will be prepended if `byteOrder == lb_endian_t::big` and `PrefixOpt::prefix` given.
281 * @param capitalization LoUpCase capitalization, default is LoUpCase::lower
282 * @param prefix pass PrefixOpt::prefix (default) to add leading `0x` if `byteOrder == lb_endian_t::big` (default)
283 * @return the given string buffer for concatenation
284 */
285 std::string& appendHexString(std::string& dest, const void *data, const nsize_t length,
286 const lb_endian_t byteOrder = lb_endian_t::big, const LoUpCase capitalization = LoUpCase::lower,
287 const PrefixOpt prefix = PrefixOpt::prefix) noexcept;
288
289 /**
290 * Produce a hexadecimal string representation of the given lsb-first byte values.
291 *
292 * If byteOrder is lb_endian_t::little, orders lsb-byte left, usual for byte streams. Result will not have a leading `0x`.
293 * Otherwise, lb_endian_t::big (default), orders msb-byte left for integer values. Result will have a leading `0x` if !skipPrefix.
294 *
295 * @param data pointer to the first byte to print, lsb-first
296 * @param length number of bytes to print
297 * @param byteOrder lb_endian_t::big for big-endian bytes in resulting hex-string (default).
298 * A leading `0x` will be prepended if `byteOrder == lb_endian_t::big` and `PrefixOpt::prefix` given.
299 * @param capitalization LoUpCase capitalization, default is LoUpCase::lower
300 * @param prefix pass PrefixOpt::prefix (default) to add leading `0x` if `byteOrder == lb_endian_t::big` (default)
301 * @return the hex-string representation of the data
302 */
303 inline std::string toHexString(const void *data, const nsize_t length,
304 const lb_endian_t byteOrder = lb_endian_t::big, const LoUpCase capitalization = LoUpCase::lower,
305 const PrefixOpt prefix = PrefixOpt::prefix) noexcept {
306 std::string s;
307 appendHexString(s, data, length, byteOrder, capitalization, prefix);
308 return s;
309 }
310
311 /**
312 * Produce a hexadecimal string representation of the given byte value and appends it to the given string
313 * @param dest the std::string reference destination to append
314 * @param value the byte value to represent
315 * @param capitalization LoUpCase capitalization, default is LoUpCase::lower
316 * @return the given std::string reference for chaining
317 */
318 std::string &appendHexString(std::string &dest, const uint8_t value, const LoUpCase capitalization = LoUpCase::lower) noexcept;
319
320 /**
321 * Produce a lower-case hexadecimal string representation with leading `0x` in MSB of the given pointer.
322 * @tparam value_type a pointer type
323 * @param v the pointer of given pointer type
324 * @param byteOrder lb_endian_t::big for big-endian bytes in resulting hex-string (default).
325 * A leading `0x` will be prepended if `byteOrder == lb_endian_t::big` and `PrefixOpt::prefix` given.
326 * @param capitalization LoUpCase capitalization, default is LoUpCase::lower
327 * @param prefix pass PrefixOpt::prefix (default) to add leading `0x` if `byteOrder == lb_endian_t::big` (default)
328 * @return the hex-string representation of the value
329 * @see toHexString()
330 * @see fromHexString()
331 */
332 template<class value_type>
335 inline std::string toHexString(value_type const &v, const lb_endian_t byteOrder = lb_endian_t::big,
336 const LoUpCase capitalization = LoUpCase::lower,
337 const PrefixOpt prefix = PrefixOpt::prefix) noexcept
338 {
339#if defined(__EMSCRIPTEN__) // jau::os::is_generic_wasm()
340 static_assert(is_little_endian()); // Bug in emscripten, unable to deduce uint16_t, uint32_t or uint64_t override of cpu_to_le() or bswap()
341 const uintptr_t v_le = reinterpret_cast<uintptr_t>(v);
342 return toHexString(pointer_cast<const uint8_t *>(&v_le), sizeof(v), // NOLINT(bugprone-sizeof-expression): Intended
343 byteOrder, capitalization, prefix);
344#else
345 const uintptr_t v_le = jau::cpu_to_le(reinterpret_cast<uintptr_t>(v));
346 return toHexString(pointer_cast<const uint8_t *>(&v_le), sizeof(v), // NOLINT(bugprone-sizeof-expression): Intended
347 byteOrder, capitalization, prefix);
348#endif
349 }
350
351 /**
352 * Produce a lower-case hexadecimal string representation with leading `0x` in MSB of the given uint8_t continuous container values.
353 * @tparam uint8_container_type a uint8_t continuous container type
354 * @param bytes the value of given uint8_t continuous container type
355 * @param byteOrder lb_endian_t::big for big-endian bytes in resulting hex-string (default).
356 * A leading `0x` will be prepended if `byteOrder == lb_endian_t::big` and `PrefixOpt::prefix` given.
357 * @param capitalization LoUpCase capitalization, default is LoUpCase::lower
358 * @param prefix pass PrefixOpt::prefix (default) to add leading `0x` if `byteOrder == lb_endian_t::big` (default)
359 * @return the hex-string representation of the value
360 * @see toHexString()
361 * @see fromHexString()
362 */
363 template<class uint8_container_type>
365 std::convertible_to<typename uint8_container_type::value_type, uint8_t>
366 inline std::string toHexString(const uint8_container_type &bytes,
367 const lb_endian_t byteOrder = lb_endian_t::big, const LoUpCase capitalization = LoUpCase::lower,
368 const PrefixOpt skipPrefix = PrefixOpt::prefix) noexcept
369 {
370 return toHexString((const uint8_t *)bytes.data(), bytes.size(), byteOrder, capitalization, skipPrefix);
371 }
372
373 /**
374 * Produce a lower-case hexadecimal string representation with leading `0x` in MSB of the given value with standard layout.
375 * @tparam value_type a standard layout value type
376 * @param v the value of given standard layout type
377 * @param byteOrder lb_endian_t::big for big-endian bytes in resulting hex-string (default).
378 * A leading `0x` will be prepended if `byteOrder == lb_endian_t::big` and `PrefixOpt::prefix` given.
379 * @param capitalization LoUpCase capitalization, default is LoUpCase::lower
380 * @param prefix pass PrefixOpt::prefix (default) to add leading `0x` if `byteOrder == lb_endian_t::big` (default)
381 * @return the hex-string representation of the value
382 * @see toHexString()
383 * @see fromHexString()
384 */
385 template<class value_type>
390 inline std::string toHexString(value_type const &v, const lb_endian_t byteOrder = lb_endian_t::big,
391 const LoUpCase capitalization = LoUpCase::lower,
392 const PrefixOpt prefix = PrefixOpt::prefix) noexcept {
393 if constexpr ( is_little_endian() ) {
394 return toHexString(pointer_cast<const uint8_t *>(&v), sizeof(v),
395 byteOrder, capitalization, prefix);
396 } else {
397 const value_type v_le = jau::bswap(v);
398 return toHexString(pointer_cast<const uint8_t *>(&v_le), sizeof(v),
399 byteOrder, capitalization, prefix);
400 }
401 }
402
403 /**
404 // *************************************************
405 // *************************************************
406 // *************************************************
407 */
408
409 /**
410 * Converts a given binary string representation, appending to a byte vector (lsb-first).
411 *
412 * In case a non valid binary digit appears in the given string,
413 * conversion ends and fills the byte vector up until the violation.
414 *
415 * In case bitstr contains an incomplete number of bit-nibbles, it will be interpreted as follows
416 * - 0b11[00000001] = 0x0301 = { 0x01, 0x03 } - msb, 1st single low-nibble is most significant
417 * - 0b[01000000]11 = 0xC040 = { 0x40, 0xC0 } - lsb, last single high-nibble is most significant
418 * - 11 -> 11000000 -> C0
419 *
420 * Even if complete==false, result holds the partial value if consumed_chars>0.
421 *
422 * You may use C++17 structured bindings to handle the pair.
423 *
424 * @param out the byte vector sink to append, lsb-first
425 * @param bitstr the binary string representation
426 * @param bitstr_len length of bitstr
427 * @param bitOrder bit_order_t::msb for most significant bits in `bitstr` first (default)
428 * @param checkPrefix if True, checks for a leading `0b` and removes it, otherwise not.
429 * @return pair [size_t consumed_chars, bool complete], i.e. consumed characters of string and completed=false if not fully consumed.
430 */
431 SizeBoolPair fromBitString(std::vector<uint8_t> &out, const uint8_t bitstr[], const size_t bitstr_len,
432 const bit_order_t bitOrder = bit_order_t::msb, const Bool checkPrefix = Bool::True);
433
434 /** See fromBitString() */
435 inline SizeBoolPair fromBitString(std::vector<uint8_t> &out, const std::string_view bitstr,
436 const bit_order_t bitOrder = bit_order_t::msb, const Bool checkPrefix = Bool::True) {
437 return jau::fromBitString(out, cast_char_ptr_to_uint8(bitstr.data()), bitstr.length(), bitOrder, checkPrefix); // NOLINT(bugprone-suspicious-stringview-data-usage)
438 }
439
440 /**
441 * Converts a given binary string representation, storing into a byte array(lsb-first).
442 *
443 * In case a non valid binary digit appears in the given string,
444 * conversion ends and fills the byte vector up until the violation.
445 *
446 * In case bitstr contains an incomplete number of bit-nibbles, it will be interpreted as follows
447 * - 0b11[00000001] = 0x0301 = { 0x01, 0x03 } - msb, 1st single low-nibble is most significant
448 * - 0b[01000000]11 = 0xC040 = { 0x40, 0xC0 } - lsb, last single high-nibble is most significant
449 * - 11 -> 11000000 -> C0
450 *
451 * Even if complete==false, result holds the partial value if consumed_chars>0.
452 *
453 * You may use C++17 structured bindings to handle the triple.
454 *
455 * @param out byte array pointer to store result, lsb-first
456 * @param out_len size of byte array
457 * @param bitstr the binary string representation
458 * @param bitstr_len length of bitstr
459 * @param bitOrder bit_order_t::msb for most significant bits in `bitstr` first (default)
460 * @param checkPrefix if True, checks for a leading `0b` and removes it, otherwise not.
461 * @return triple [uint8_t* out_end, size_t consumed_chars, bool complete],
462 * i.e. end pointer of out (last write + 1), consumed characters of string and completed=false if not fully consumed.
463 */
464 UInt8PtrSizeBoolPair fromBitString(uint8_t *out, size_t out_len, const uint8_t bitstr[], const size_t bitstr_len,
465 const bit_order_t bitOrder = bit_order_t::msb, const Bool checkPrefix = Bool::True) noexcept;
466
467 /** See fromBitString() */
468 inline UInt8PtrSizeBoolPair fromBitString(uint8_t *out, size_t out_len, const std::string_view bitstr,
469 const bit_order_t bitOrder = bit_order_t::msb, const Bool checkPrefix = Bool::True) noexcept {
470 return jau::fromBitString(out, out_len, cast_char_ptr_to_uint8(bitstr.data()), bitstr.length(), bitOrder, checkPrefix); // NOLINT(bugprone-suspicious-stringview-data-usage)
471 }
472
473 /**
474 * Converts a given binary string representation into a uint64_t value according to bitStringBytes().
475 *
476 * Even if complete==false, result holds the partial value if consumed_chars>0.
477 *
478 * You may use C++17 structured bindings to handle the tuple.
479 *
480 * @param bitstr the binary string representation
481 * @param checkPrefix if true, checks for a leading `0b` and removes it, otherwise not.
482 * @param bitOrder bit_order_t::msb for most significant bits in `bitstr` first (default)
483 * @return tuple [uint64_t result, size_t consumed_chars, bool complete], i.e. consumed characters of string and completed=false if not fully consumed.
484 * @see bitStringBytes()
485 * @see to_bitstring()
486 */
487 UInt64SizeBoolTuple fromBitString(std::string_view const bitstr, const bit_order_t bitOrder = bit_order_t::msb, const Bool checkPrefix = Bool::True) noexcept;
488
489 /**
490 * Appends a binary string representation of the given lsb-first byte values.
491 *
492 * If byteOrder is lb_endian_t::little, orders lsb-byte left, usual for byte streams. Result will not have a leading `0b`.
493 * Otherwise, lb_endian_t::big (default), orders msb-byte left for integer values. Result will have a leading `0b` if !skipPrefix.
494 *
495 * @param dest the std::string to append to
496 * @param data pointer to the first byte to print, lsb-first
497 * @param length number of bytes to print
498 * @param bitOrder bit_order_t::msb for most-significant-bit first in resulting bit-string, bit_order_t::msb is default
499 * A leading `0b` will be prepended if `bitOrder == bit_order_t::msb` and `PrefixOpt::prefix` given.
500 * @param prefix pass PrefixOpt::prefix (default) to add leading `0b` if `bitOrder == bit_order_t::msb` (default)
501 * @param bit_len optional fixed number of bits to be printed counting from lsb excluding prefix. Pass zero for dropping zero leading bytes (default).
502 * @return the given string buffer for concatenation
503 */
504 std::string& appendBitString(std::string& dest, const void *data, const nsize_t length,
506 size_t bit_len=0) noexcept;
507
508 /**
509 * Produce a binary string representation of the given lsb-first byte values.
510 *
511 * If byteOrder is lb_endian_t::little, orders lsb-byte left, usual for byte streams. Result will not have a leading `0b`.
512 * Otherwise, lb_endian_t::big (default), orders msb-byte left for integer values. Result will have a leading `0b` if !skipPrefix.
513 *
514 * @param data pointer to the first byte to print, lsb-first
515 * @param length number of bytes to print
516 * @param bitOrder bit_order_t::msb for most-significant-bit first in resulting bit-string, bit_order_t::msb is default
517 * A leading `0b` will be prepended if `bitOrder == bit_order_t::msb` and `PrefixOpt::prefix` given.
518 * @param prefix pass PrefixOpt::prefix (default) to add leading `0b` if `bitOrder == bit_order_t::msb` (default)
519 * @param bit_len optional fixed number of bits to be printed counting from lsb excluding prefix. Pass zero for dropping zero leading bytes (default).
520 * @return the bit-string representation of the data
521 */
522 inline std::string toBitString(const void *data, const nsize_t length,
523 const bit_order_t bitOrder = bit_order_t::msb, const PrefixOpt prefix = PrefixOpt::prefix,
524 size_t bit_len=0) noexcept {
525 std::string s;
526 appendBitString(s, data, length, bitOrder, prefix, bit_len);
527 return s;
528 }
529
530 /**
531 * Produce a binary string representation with leading `0b` in MSB of the given uint8_t continuous container values.
532 * @tparam uint8_container_type a uint8_t continuous container type
533 * @param bytes the value of given uint8_t continuous container type
534 * @param bitOrder bit_order_t::msb for most-significant-bit first in resulting bit-string, bit_order_t::msb is default
535 * A leading `0b` will be prepended if `bitOrder == bit_order_t::msb` and `PrefixOpt::prefix` given.
536 * @param prefix pass PrefixOpt::prefix (default) to add leading `0b` if `bitOrder == bit_order_t::msb` (default)
537 * @param bit_len optional fixed number of bits to be printed counting from lsb excluding prefix. Pass zero for dropping zero leading bytes (default).
538 * @return the bit-string representation of the value
539 * @see toBitString()
540 * @see fromBitString()
541 */
542 template<class uint8_container_type>
544 std::convertible_to<typename uint8_container_type::value_type, uint8_t>
545 inline std::string toBitString(const uint8_container_type &bytes,
546 const bit_order_t bitOrder = bit_order_t::msb, const PrefixOpt prefix = PrefixOpt::prefix, size_t bit_len=0) noexcept {
547 return toBitString((const uint8_t *)bytes.data(), bytes.size(), bitOrder, prefix, bit_len);
548 }
549
550 /**
551 * Produce a binary string representation with leading `0b` in MSB of the given value with standard layout.
552 * @tparam value_type a standard layout value type
553 * @param v the value of given standard layout type
554 * @param bitOrder bit_order_t::msb for most-significant-bit first in resulting bit-string, bit_order_t::msb is default
555 * A leading `0b` will be prepended if `bitOrder == bit_order_t::msb` and `PrefixOpt::prefix` given.
556 * @param prefix pass PrefixOpt::prefix (default) to add leading `0b` if `bitOrder == bit_order_t::msb` (default)
557 * @param bit_len optional fixed number of bits to be printed counting from lsb excluding prefix. Pass zero for dropping zero leading bytes (default).
558 * @return the bit-string representation of the value
559 * @see toBitString()
560 * @see fromBitString()
561 */
562 template<class value_type>
567 inline std::string toBitString(value_type const &v, const bit_order_t bitOrder = bit_order_t::msb,
568 const PrefixOpt prefix = PrefixOpt::prefix, size_t bit_len=0) noexcept
569 {
570 if constexpr ( is_little_endian() ) {
571 return toBitString(pointer_cast<const uint8_t *>(&v), sizeof(v),
572 bitOrder, prefix, bit_len);
573 } else {
574 const value_type v_le = jau::bswap(v);
575 return toBitString(pointer_cast<const uint8_t *>(&v_le), sizeof(v),
576 bitOrder, prefix, bit_len);
577 }
578 }
579
580 /**
581 // *************************************************
582 // *************************************************
583 // *************************************************
584 */
585
586 /**
587 * Converts a given integer string representation to the given result reference,
588 * compatible with `::strtoll()`
589 *
590 * - Signed value_type: `[space][+-][prefix][digits+sep]`
591 * - Unsigned value_type: `[space][+][prefix][digits+sep]`
592 *
593 * Even if complete==false due to empty string, under- or overflow,
594 * the result holds the partial value if consumed_chars>0.
595 *
596 * Whitespace and non-matching chars
597 * - Leading and tailing whitespace chars are consumed, see jau::is_space()
598 * - Tail non-matching chars are ignored: complete is true but consumed_chars is < str.length()
599 *
600 * You may use C++17 structured bindings to handle the pair.
601 * - `[size_t consumed_chars, bool complete]`
602 *
603 * @param result the integral reference for the result
604 * @param str the decimal string representation
605 * @param radix base of the number system, supported: 2 binary, 8 octal, 10 decimal, 16 hexadecimal
606 * @param separator separator character (default 0, none), allowing to ignore like thousand separator characters
607 * @return pair [size_t consumed_chars, bool complete], i.e. consumed characters of string and completed=false if not fully consumed.
608 */
609 template<std::integral value_type>
610 constexpr SizeBoolPair fromIntString(value_type &result, std::string_view str, uint32_t radix=10, const char separator = 0) noexcept {
611 using namespace jau::int_literals;
612 result = 0;
613
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; // begin of digits
617 value_type sign = 1;
618
619 // consume leading whitespace
620 while( begin < str_end && jau::is_space(*begin)) { ++begin; }
621 // sign
622 if (begin < str_end ) {
623 if (*begin == '-') {
624 if constexpr (std::is_unsigned_v<value_type>) {
625 return { .s = size_t(begin-str_begin), .b = false }; // invalid
626 }
627 sign = -1;
628 ++begin;
629 } else if (*begin == '+') {
630 ++begin;
631 }
632 }
633 // prefix
634 if( 16 == radix && begin < str_end-1 ) {
635 if ( *begin == '0' && (*(begin+1) == 'x' || *(begin+1) == 'X') ) {
636 begin+=2;
637 }
638 } else if( 8 == radix && begin < str_end ) {
639 if ( *begin == '0' ) {
640 begin+=1;
641 }
642 } else if( 2 == radix && begin < str_end-1 ) {
643 if ( *begin == '0' && *(begin+1) == 'b' ) {
644 begin+=2;
645 }
646 }
647 if (begin == str_end || !jau::is_digit(*begin, radix, separator)) {
648 return { .s = size_t(begin-str_begin), .b = false }; // no number (empty or no digit)
649 }
650
651 std::string_view::const_iterator end = begin;
652 while( end < str_end && jau::is_digit(*end, radix, separator)) { ++end; } // position to last digit, ignore tail
653 const size_t len = end-str_begin; // consumed length w/o tail
654 std::string_view::const_iterator iter = end;
655
656 value_type multiplier = 1;
657 while( iter > begin ) {
658 const int32_t d = digit(*(--iter), radix);
659 if ( 0 > d ) {
660 continue; // skip seperator
661 }
662 const value_type sum = d * multiplier * sign;
663 if( sign > 0 && result > std::numeric_limits<value_type>::max() - sum ) {
664 // overflow
665 return { .s = len, .b = false };
666 }
667 if constexpr (std::is_signed_v<value_type>) {
668 if( sign < 0 && result < std::numeric_limits<value_type>::min() - sum ) {
669 // underflow
670 return { .s = len, .b = false };
671 }
672 }
673 result += sum;
674 multiplier *= radix;
675 }
676 // consume tailing whitespace
677 while( end < str_end && jau::is_space(*end)) { ++end; }
678 return { .s = size_t(end-str_begin), .b = true };
679 }
680 /// See fromIntString
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);
684 }
685
686 /**
687 * Appends an integer string representation of an integral integer value with given radix.
688 *
689 * `[space][-][prefix][zero_padding+sep][digits+sep]`
690 *
691 * @tparam value_type an integral integer type
692 * @param dest the std::string to append to
693 * @param val the unsigned integral integer value
694 * @param radix base of the number system, supported: 2 binary, 8 octal, 10 decimal, 16 hexadecimal
695 * @param capitalization LoUpCase capitalization, default is LoUpCase::lower
696 * @param prefix pass PrefixOpt::prefix (default) to add leading prefix for radix. Prefixes: `0x` hex, `0` octal and `0b` binary.
697 * @param min_width the minimum number of characters to be printed including sign and prefix. Add padding if sign+prefix+val-digits are shorter.
698 * @param separator separator character for each decimal 3 or other radix 4. Defaults to 0 for no separator.
699 * @param padding padding character, defaults to '0'.
700 * Zero padding w/ '0' includes separator and comes before prefix, otherwise added to the left. See 'min_width' above.
701 * @return the given string buffer for concatenation
702 */
703 template<std::integral value_type>
704 std::string& appendIntString(std::string &dest, value_type val, const uint32_t radix,
705 const LoUpCase capitalization = LoUpCase::lower,
707 const uint32_t min_width = 0, const char separator = 0, const char padding = '0') noexcept
708 {
709 const size_t dest_start_len = dest.size();
710 uint32_t shift;
711 switch ( radix ) {
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;
717 }
718 using unsigned_value_type = std::make_unsigned_t<value_type>;
719 unsigned_value_type v = jau::unsigned_value( val );
720 const uint32_t val_digits = jau::digits<unsigned_value_type>(v, radix);
721 const uint32_t sign_len = jau::is_positive(val) ? 0 : 1;
722 const uint32_t prefix_len = (PrefixOpt::none == prefix || 10 == radix) ? 0 : (8 == radix ? 1 : 2);
723 const uint32_t sep_gap = 10 == radix ? 3 : 4;
724 uint32_t sep_count, space_left;
725 if ('0' == padding) {
726 space_left = 0;
727 if (separator) {
728 // separator inside zero-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 ) {
735 --sep_count; // fix down
736 }
737 }
738 } else {
739 sep_count = 0;
740 }
741 } else {
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;
745 }
746 {
747 std::exception_ptr eptr;
748 try {
749 const uint32_t added_len = std::max(min_width, space_left + sign_len + prefix_len + (val_digits + sep_count));
750 // fprintf(stderr, "XXX: space_left %u, sign_len %u, prefix_len %u digits %u, sep_count %u; min_width %u; added_len %u\n",
751 // space_left, sign_len, prefix_len, val_digits, sep_count, min_width, added_len);
752 dest.reserve(dest_start_len + added_len + 1); // w/ EOS
753 dest.resize(dest_start_len + added_len, ' '); // w/o EOS
754 } catch (...) {
755 eptr = std::current_exception();
756 }
757 if (handle_exception(eptr, E_FILE_LINE)) {
758 return dest;
759 }
760 }
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();
764 *d = 0; // EOS (is reserved)
765 {
766 const char *hex_array = LoUpCase::lower == capitalization ? HexadecimalArrayLow : HexadecimalArrayBig;
767 const unsigned_value_type mask = unsigned_value_type(radix - 1); // ignored for radix 10
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) {
771 *(--d) = separator;
772 ++separator_idx;
773 }
774 if (d > d_start_num) {
775 if (digit_cnt >= val_digits) {
776 *(--d) = padding;
777 } else if (10 == radix) {
778 *(--d) = '0' + (v % 10);
779 v /= 10;
780 } else {
781 *(--d) = hex_array[v & mask];
782 v >>= shift;
783 }
784 ++digit_cnt;
785 }
786 }
787 }
788 if ( prefix_len && d > d_start ) {
789 switch ( radix ) { // NOLINT(bugprone-switch-missing-default-case)
790 case 16: *(--d) = 'x'; break;
791 case 2: *(--d) = 'b'; break;
792 }
793 if ( d > d_start ) {
794 *(--d) = '0';
795 }
796 }
797 if ( sign_len && d > d_start ) {
798 *(--d) = '-';
799 }
800 return dest;
801 }
802
803 /**
804 * Produces an integer string representation of an integral integer value with given radix.
805 *
806 * `[space][-][prefix][zero_padding+sep][digits+sep]`
807 *
808 * @tparam value_type an unsigned integral integer type
809 * @param v the integral integer value
810 * @param radix base of the number system, supported: 2 binary, 8 octal, 10 decimal, 16 hexadecimal
811 * @param capitalization LoUpCase capitalization, default is LoUpCase::lower
812 * @param prefix pass PrefixOpt::prefix (default) to add leading prefix for radix. Prefixes: `0x` hex, `0` octal and `0b` binary.
813 * @param min_width the minimum number of characters to be printed including sign and prefix. Add padding if sign+prefix+val-digits are shorter.
814 * @param separator separator character for each decimal 3 or other radix 4. Defaults to 0 for no separator.
815 * @param padding padding character, defaults to '0'.
816 * Zero padding w/ '0' includes separator and comes before prefix, otherwise added to the left. See 'min_width' above.
817 * @return the string representation of the integral integer value with given radix
818 */
819 template<std::integral value_type>
820 std::string to_string(value_type v, const uint32_t radix,
821 const LoUpCase capitalization = LoUpCase::lower,
823 const uint32_t min_width = 0, const char separator = 0, const char padding = '0') noexcept
824 {
825 std::string str;
826 appendIntString(str, v, radix, capitalization, prefix, min_width, separator, padding);
827 return str;
828 }
829
830 /**
831 * Appends a decimal integer string representation of an integral integer value with given radix.
832 *
833 * `[space][-][digits+sep]`
834 *
835 * @tparam value_type an integral integer type
836 * @param dest the std::string to append to
837 * @param val the unsigned integral integer value
838 * @param separator separator character for each decimal 3. Defaults to `'` for no separator.
839 * @param min_width the minimum number of characters to be printed including sign. Add left space if sign+val-digits are shorter.
840 * @return the given string buffer for concatenation
841 */
842 template<class value_type,
843 std::enable_if_t<std::is_integral_v<value_type>,
844 bool> = true>
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>;
848 unsigned_value_type v = jau::unsigned_value( val );
849 const uint32_t val_digits = jau::digits10<unsigned_value_type>(v);
850 const uint32_t sign_len = jau::is_positive(val) ? 0 : 1;
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;
856 {
857 std::exception_ptr eptr;
858 try {
859 // fprintf(stderr, "XXX: space_left %u, sign_len %u, digits %u, sep_count %u; min_width %u; added_len %u\n",
860 // space_left, sign_len, val_digits, sep_count, min_width, added_len);
861 dest.reserve(dest_start_len + added_len + 1); // w/ EOS
862 dest.resize(dest_start_len + added_len, ' '); // w/o EOS
863 } catch (...) {
864 eptr = std::current_exception();
865 }
866 if (handle_exception(eptr, E_FILE_LINE)) {
867 return dest;
868 }
869 }
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();
873 *d = 0; // EOS (is reserved)
874 {
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) {
878 *(--d) = separator;
879 ++separator_idx;
880 }
881 if (d > d_start_num) {
882 *(--d) = '0' + (v % 10);
883 v /= 10;
884 ++digit_cnt;
885 }
886 }
887 }
888 if ( sign_len && d > d_start ) {
889 *(--d) = '-';
890 }
891 return dest;
892 }
893
894 /**
895 * Produces a decimal integer string representation of an integral integer value with given radix.
896 *
897 * `[space][-][digits+sep]`
898 *
899 * @tparam value_type an integral integer type
900 * @param v the unsigned integral integer value
901 * @param separator separator character for each decimal 3. Defaults to `'` for no separator.
902 * @param min_width the minimum number of characters to be printed including sign. Add left space if sign+val-digits are shorter.
903 * @return the decimal string representation of the integral integer
904 */
905 template<class value_type,
906 std::enable_if_t<std::is_integral_v<value_type>,
907 bool> = true>
908 std::string to_decstring(const value_type &v, const char separator = '\'', const nsize_t min_width = 0) noexcept {
909 std::string str;
910 appendDecString(str, v, separator, min_width);
911 return str;
912 }
913
914 /**
915 // *************************************************
916 // *************************************************
917 // *************************************************
918 */
919
920 template<typename CharT, std::size_t N>
921 constexpr std::string to_string(const CharT (&ref)[N]) {
922 return std::string(ref);
923 }
924
925 template<class value_type>
926 requires std::is_same_v<jau::StringLiteral<value_type::size>, value_type> // jau::req::string_alike<value_type>
927 constexpr std::string to_string(const value_type &ref) {
928 return std::string(ref);
929 }
930
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>,
934 bool> = true>
935 inline std::string to_string(const value_type &ref) {
936 return std::to_string(ref);
937 }
938
939 template<class value_type,
940 std::enable_if_t<std::is_same_v<bool, std::remove_cv_t<value_type>>,
941 bool> = true>
942 inline std::string to_string(const value_type &ref) {
943 return ref ? "T" : "F";
944 }
945
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>,
950 bool> = true>
951 inline std::string to_string(const value_type &ref) {
952 return ref;
953 }
954
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>,
960 bool> = true>
961 inline std::string to_string(const value_type &ref) {
962 return std::string(ref);
963 }
964
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>>,
971 bool> = true>
972 inline std::string to_string(const value_type &ref) {
973 return std::string(ref);
974 }
975
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>,
983 bool> = true>
984 inline std::string to_string(const value_type &ref) {
985 return toHexString((void *)ref); // NOLINT(bugprone-multi-level-implicit-pointer-conversion)
986 }
987
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> &&
995 bool> = true>
996 inline std::string to_string(const value_type &ref) {
997 return ref.toString();
998 }
999
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> &&
1008 bool> = true>
1009 inline std::string to_string(const value_type &ref) {
1010 return ref.to_string();
1011 }
1012
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> &&
1022 bool> = true>
1023 inline std::string to_string(const value_type &ref) {
1024 return toHexString((void *)ref.operator->());
1025 }
1026
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> &&
1036 bool> = true>
1037 inline std::string to_string(const value_type &ref) {
1038 (void)ref;
1039 return "jau::to_string<T> n/a for type " + jau::static_ctti<value_type>().toString();
1040 }
1041
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();
1046 }
1047 bool need_delim = false;
1048 std::string res;
1049 for ( const T &e : list ) {
1050 if ( need_delim ) {
1051 res.append(delim);
1052 }
1053 res.append(to_string(e));
1054 need_delim = true;
1055 }
1056 return res;
1057 }
1058 template<typename T>
1059 std::string to_string(std::vector<T> const &list) { return to_string<T>(list, ", "); }
1060
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();
1065 }
1066 bool need_delim = false;
1067 std::string res;
1068 for ( const T &e : list ) {
1069 if ( need_delim ) {
1070 res.append(delim);
1071 }
1072 res.append(to_string(e, radix));
1073 need_delim = true;
1074 }
1075 return res;
1076 }
1077 template<typename T>
1078 std::string to_string(std::vector<T> const &list, const nsize_t radix) { return to_string<T>(list, ", ", radix); }
1079
1080 /**@}*/
1081
1082} // namespace jau
1083
1084/** \example test_intdecstring01.cpp
1085 * This C++ unit test validates the jau::to_decstring implementation
1086 */
1087
1088#endif /* JAU_STRING_UTIL_HPP_ */
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
Definition byte_util.hpp:88
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
#define E_FILE_LINE
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>().
Definition int_math.hpp:436
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.
Definition int_math.hpp:513
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...
Definition int_types.hpp:85
constexpr bool is_positive(const T a) noexcept
Returns true of the given integral is positive, i.e.
Definition base_math.hpp:70
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.
Definition backtrace.hpp:32
STL namespace.
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...
Definition int_types.hpp:85