1#ifndef C4_CHARCONV_HPP_
2#define C4_CHARCONV_HPP_
8#include "c4/language.hpp"
15#include "c4/config.hpp"
17#include "c4/std/std_fwd.hpp"
18#include "c4/memory_util.hpp"
20#ifndef C4CORE_NO_FAST_FLOAT
23# if (C4_MSVC_VERSION >= C4_MSVC_VERSION_2019)
25# define C4CORE_HAVE_STD_TOCHARS 1
26# define C4CORE_HAVE_STD_FROMCHARS 0
27# define C4CORE_HAVE_FAST_FLOAT 1
29# define C4CORE_HAVE_STD_TOCHARS 0
30# define C4CORE_HAVE_STD_FROMCHARS 0
31# define C4CORE_HAVE_FAST_FLOAT 1
34# if __has_include(<charconv>)
36# if defined(__cpp_lib_to_chars)
37# define C4CORE_HAVE_STD_TOCHARS 1
38# define C4CORE_HAVE_STD_FROMCHARS 0
39# define C4CORE_HAVE_FAST_FLOAT 1
41# define C4CORE_HAVE_STD_TOCHARS 0
42# define C4CORE_HAVE_STD_FROMCHARS 0
43# define C4CORE_HAVE_FAST_FLOAT 1
46# define C4CORE_HAVE_STD_TOCHARS 0
47# define C4CORE_HAVE_STD_FROMCHARS 0
48# define C4CORE_HAVE_FAST_FLOAT 1
52# define C4CORE_HAVE_STD_TOCHARS 0
53# define C4CORE_HAVE_STD_FROMCHARS 0
54# define C4CORE_HAVE_FAST_FLOAT 1
56# if C4CORE_HAVE_FAST_FLOAT
57# include "c4/ext/fast_float.hpp"
60# define C4CORE_HAVE_FAST_FLOAT 0
62# if (C4_MSVC_VERSION >= C4_MSVC_VERSION_2019)
64# define C4CORE_HAVE_STD_TOCHARS 1
65# define C4CORE_HAVE_STD_FROMCHARS 1
67# define C4CORE_HAVE_STD_TOCHARS 0
68# define C4CORE_HAVE_STD_FROMCHARS 0
71# if __has_include(<charconv>)
73# if defined(__cpp_lib_to_chars)
74# define C4CORE_HAVE_STD_TOCHARS 1
75# define C4CORE_HAVE_STD_FROMCHARS 1
77# define C4CORE_HAVE_STD_TOCHARS 0
78# define C4CORE_HAVE_STD_FROMCHARS 0
81# define C4CORE_HAVE_STD_TOCHARS 0
82# define C4CORE_HAVE_STD_FROMCHARS 0
86# define C4CORE_HAVE_STD_TOCHARS 0
87# define C4CORE_HAVE_STD_FROMCHARS 0
88# define C4CORE_HAVE_FAST_FLOAT 0
92#if !C4CORE_HAVE_STD_FROMCHARS
97#if defined(_MSC_VER) && !defined(__clang__)
99# pragma warning(disable: 4996)
100# if C4_MSVC_VERSION != C4_MSVC_VERSION_2017
101# pragma warning(disable: 4800)
103#elif defined(__clang__)
104# pragma clang diagnostic push
105# pragma clang diagnostic ignored "-Wtautological-constant-out-of-range-compare"
106# pragma clang diagnostic ignored "-Wformat-nonliteral"
107# pragma clang diagnostic ignored "-Wdouble-promotion"
108# pragma clang diagnostic ignored "-Wold-style-cast"
109#elif defined(__GNUC__)
110# pragma GCC diagnostic push
111# pragma GCC diagnostic ignored "-Wformat-nonliteral"
112# pragma GCC diagnostic ignored "-Wdouble-promotion"
113# pragma GCC diagnostic ignored "-Wuseless-cast"
114# pragma GCC diagnostic ignored "-Wold-style-cast"
117#if defined(__clang__)
118#define C4_NO_UBSAN_IOVRFLW __attribute__((no_sanitize("signed-integer-overflow")))
119#elif defined(__GNUC__)
121#define C4_NO_UBSAN_IOVRFLW __attribute__((no_sanitize("signed-integer-overflow")))
123#define C4_NO_UBSAN_IOVRFLW
126#define C4_NO_UBSAN_IOVRFLW
178#if C4CORE_HAVE_STD_TOCHARS
180typedef enum : std::underlying_type<std::chars_format>::type {
182 FTOA_FLOAT =
static_cast<std::underlying_type<std::chars_format>::type
>(std::chars_format::fixed),
184 FTOA_SCIENT =
static_cast<std::underlying_type<std::chars_format>::type
>(std::chars_format::scientific),
186 FTOA_FLEX =
static_cast<std::underlying_type<std::chars_format>::type
>(std::chars_format::general),
188 FTOA_HEXA =
static_cast<std::underlying_type<std::chars_format>::type
>(std::chars_format::hex),
209struct is_fixed_length
213 value_i = (std::is_integral<T>::value
214 && (std::is_same<T, int8_t>::value
215 || std::is_same<T, int16_t>::value
216 || std::is_same<T, int32_t>::value
217 || std::is_same<T, int64_t>::value)),
219 value_u = (std::is_integral<T>::value
220 && (std::is_same<T, uint8_t>::value
221 || std::is_same<T, uint16_t>::value
222 || std::is_same<T, uint32_t>::value
223 || std::is_same<T, uint64_t>::value)),
225 value = value_i || value_u
235#if defined(_MSC_VER) && !defined(__clang__)
236# pragma warning(push)
237#elif defined(__clang__)
238# pragma clang diagnostic push
239#elif defined(__GNUC__)
240# pragma GCC diagnostic push
241# pragma GCC diagnostic ignored "-Wconversion"
243# pragma GCC diagnostic ignored "-Wnull-dereference"
263template<
size_t num_
bytes,
bool is_
signed>
struct charconv_digits_;
264template<
class T>
using charconv_digits = charconv_digits_<
sizeof(T), std::is_signed<T>::value>;
266template<>
struct charconv_digits_<1u, true>
269 maxdigits_bin = 1 + 2 + 8,
270 maxdigits_oct = 1 + 2 + 3,
271 maxdigits_dec = 1 + 3,
272 maxdigits_hex = 1 + 2 + 2,
273 maxdigits_bin_nopfx = 8,
274 maxdigits_oct_nopfx = 3,
275 maxdigits_dec_nopfx = 3,
276 maxdigits_hex_nopfx = 2,
279 static constexpr csubstr min_value_dec() noexcept {
return csubstr(
"128"); }
280 static constexpr csubstr min_value_hex() noexcept {
return csubstr(
"80"); }
281 static constexpr csubstr min_value_oct() noexcept {
return csubstr(
"200"); }
282 static constexpr csubstr min_value_bin() noexcept {
return csubstr(
"10000000"); }
283 static constexpr csubstr max_value_dec() noexcept {
return csubstr(
"127"); }
284 static constexpr bool is_oct_overflow(csubstr str)
noexcept {
return !((str.len < 3) || (str.len == 3 && str.str[0] <=
'1')); }
286template<>
struct charconv_digits_<1u, false>
289 maxdigits_bin = 2 + 8,
290 maxdigits_oct = 2 + 3,
292 maxdigits_hex = 2 + 2,
293 maxdigits_bin_nopfx = 8,
294 maxdigits_oct_nopfx = 3,
295 maxdigits_dec_nopfx = 3,
296 maxdigits_hex_nopfx = 2,
298 static constexpr csubstr max_value_dec() noexcept {
return csubstr(
"255"); }
299 static constexpr bool is_oct_overflow(csubstr str)
noexcept {
return !((str.len < 3) || (str.len == 3 && str.str[0] <=
'3')); }
301template<>
struct charconv_digits_<2u, true>
304 maxdigits_bin = 1 + 2 + 16,
305 maxdigits_oct = 1 + 2 + 6,
306 maxdigits_dec = 1 + 5,
307 maxdigits_hex = 1 + 2 + 4,
308 maxdigits_bin_nopfx = 16,
309 maxdigits_oct_nopfx = 6,
310 maxdigits_dec_nopfx = 5,
311 maxdigits_hex_nopfx = 4,
314 static constexpr csubstr min_value_dec() noexcept {
return csubstr(
"32768"); }
315 static constexpr csubstr min_value_hex() noexcept {
return csubstr(
"8000"); }
316 static constexpr csubstr min_value_oct() noexcept {
return csubstr(
"100000"); }
317 static constexpr csubstr min_value_bin() noexcept {
return csubstr(
"1000000000000000"); }
318 static constexpr csubstr max_value_dec() noexcept {
return csubstr(
"32767"); }
319 static constexpr bool is_oct_overflow(csubstr str)
noexcept {
return !(str.len < 6); }
321template<>
struct charconv_digits_<2u, false>
324 maxdigits_bin = 2 + 16,
325 maxdigits_oct = 2 + 6,
327 maxdigits_hex = 2 + 4,
328 maxdigits_bin_nopfx = 16,
329 maxdigits_oct_nopfx = 6,
330 maxdigits_dec_nopfx = 6,
331 maxdigits_hex_nopfx = 4,
333 static constexpr csubstr max_value_dec() noexcept {
return csubstr(
"65535"); }
334 static constexpr bool is_oct_overflow(csubstr str)
noexcept {
return !((str.len < 6) || (str.len == 6 && str.str[0] <=
'1')); }
336template<>
struct charconv_digits_<4u, true>
339 maxdigits_bin = 1 + 2 + 32,
340 maxdigits_oct = 1 + 2 + 11,
341 maxdigits_dec = 1 + 10,
342 maxdigits_hex = 1 + 2 + 8,
343 maxdigits_bin_nopfx = 32,
344 maxdigits_oct_nopfx = 11,
345 maxdigits_dec_nopfx = 10,
346 maxdigits_hex_nopfx = 8,
349 static constexpr csubstr min_value_dec() noexcept {
return csubstr(
"2147483648"); }
350 static constexpr csubstr min_value_hex() noexcept {
return csubstr(
"80000000"); }
351 static constexpr csubstr min_value_oct() noexcept {
return csubstr(
"20000000000"); }
352 static constexpr csubstr min_value_bin() noexcept {
return csubstr(
"10000000000000000000000000000000"); }
353 static constexpr csubstr max_value_dec() noexcept {
return csubstr(
"2147483647"); }
354 static constexpr bool is_oct_overflow(csubstr str)
noexcept {
return !((str.len < 11) || (str.len == 11 && str.str[0] <=
'1')); }
356template<>
struct charconv_digits_<4u, false>
359 maxdigits_bin = 2 + 32,
360 maxdigits_oct = 2 + 11,
362 maxdigits_hex = 2 + 8,
363 maxdigits_bin_nopfx = 32,
364 maxdigits_oct_nopfx = 11,
365 maxdigits_dec_nopfx = 10,
366 maxdigits_hex_nopfx = 8,
368 static constexpr csubstr max_value_dec() noexcept {
return csubstr(
"4294967295"); }
369 static constexpr bool is_oct_overflow(csubstr str)
noexcept {
return !((str.len < 11) || (str.len == 11 && str.str[0] <=
'3')); }
371template<>
struct charconv_digits_<8u, true>
374 maxdigits_bin = 1 + 2 + 64,
375 maxdigits_oct = 1 + 2 + 22,
376 maxdigits_dec = 1 + 19,
377 maxdigits_hex = 1 + 2 + 16,
378 maxdigits_bin_nopfx = 64,
379 maxdigits_oct_nopfx = 22,
380 maxdigits_dec_nopfx = 19,
381 maxdigits_hex_nopfx = 16,
383 static constexpr csubstr min_value_dec() noexcept {
return csubstr(
"9223372036854775808"); }
384 static constexpr csubstr min_value_hex() noexcept {
return csubstr(
"8000000000000000"); }
385 static constexpr csubstr min_value_oct() noexcept {
return csubstr(
"1000000000000000000000"); }
386 static constexpr csubstr min_value_bin() noexcept {
return csubstr(
"1000000000000000000000000000000000000000000000000000000000000000"); }
387 static constexpr csubstr max_value_dec() noexcept {
return csubstr(
"9223372036854775807"); }
388 static constexpr bool is_oct_overflow(csubstr str)
noexcept {
return !(str.len < 22); }
390template<>
struct charconv_digits_<8u, false>
393 maxdigits_bin = 2 + 64,
394 maxdigits_oct = 2 + 22,
396 maxdigits_hex = 2 + 16,
397 maxdigits_bin_nopfx = 64,
398 maxdigits_oct_nopfx = 22,
399 maxdigits_dec_nopfx = 20,
400 maxdigits_hex_nopfx = 16,
402 static constexpr csubstr max_value_dec() noexcept {
return csubstr(
"18446744073709551615"); }
403 static constexpr bool is_oct_overflow(csubstr str)
noexcept {
return !((str.len < 22) || (str.len == 22 && str.str[0] <=
'1')); }
408#define c4append_(c) { if C4_LIKELY(pos < buf.len) { buf.str[pos++] = static_cast<char>(c); } else { ++pos; } }
431C4_CONSTEXPR14 C4_ALWAYS_INLINE
433 ->
typename std::enable_if<
sizeof(T) == 1u,
unsigned>::type
435 C4_STATIC_ASSERT(std::is_integral<T>::value);
437 return ((v >= 100) ? 3u : ((v >= 10) ? 2u : 1u));
442C4_CONSTEXPR14 C4_ALWAYS_INLINE
444 ->
typename std::enable_if<
sizeof(T) == 2u,
unsigned>::type
446 C4_STATIC_ASSERT(std::is_integral<T>::value);
448 return ((v >= 10000) ? 5u : (v >= 1000) ? 4u : (v >= 100) ? 3u : (v >= 10) ? 2u : 1u);
453C4_CONSTEXPR14 C4_ALWAYS_INLINE
455 ->
typename std::enable_if<
sizeof(T) == 4u,
unsigned>::type
457 C4_STATIC_ASSERT(std::is_integral<T>::value);
459 return ((v >= 1000000000) ? 10u : (v >= 100000000) ? 9u : (v >= 10000000) ? 8u :
460 (v >= 1000000) ? 7u : (v >= 100000) ? 6u : (v >= 10000) ? 5u :
461 (v >= 1000) ? 4u : (v >= 100) ? 3u : (v >= 10) ? 2u : 1u);
466C4_CONSTEXPR14 C4_ALWAYS_INLINE
468 ->
typename std::enable_if<
sizeof(T) == 8u,
unsigned>::type
472 C4_STATIC_ASSERT(std::is_integral<T>::value);
476 if(v >= 100000000000000)
478 if(v >= 100000000000000000)
480 if((
typename std::make_unsigned<T>::type)v >= 10000000000000000000u)
483 return (v >= 1000000000000000000) ? 19u : 18u;
485 else if(v >= 10000000000000000)
491 return(v >= 1000000000000000) ? 16u : 15u;
494 else if(v >= 1000000000000)
496 return (v >= 10000000000000) ? 14u : 13u;
498 else if(v >= 100000000000)
504 return(v >= 10000000000) ? 11u : 10u;
510 return (v >= 100000000) ? 9u : 8u;
511 else if(v >= 1000000)
514 return (v >= 100000) ? 6u : 5u;
518 return (v >= 1000) ? 4u : 3u;
522 return (v >= 10) ? 2u : 1u;
529C4_CONSTEXPR14 C4_ALWAYS_INLINE
unsigned digits_hex(T v)
noexcept
531 C4_STATIC_ASSERT(std::is_integral<T>::value);
533 return v ? 1u + (msb((
typename std::make_unsigned<T>::type)v) >> 2u) : 1u;
538C4_CONSTEXPR14 C4_ALWAYS_INLINE
unsigned digits_bin(T v)
noexcept
540 C4_STATIC_ASSERT(std::is_integral<T>::value);
542 return v ? 1u + msb((
typename std::make_unsigned<T>::type)v) : 1u;
547C4_CONSTEXPR14 C4_ALWAYS_INLINE
unsigned digits_oct(T v_)
noexcept
550 C4_STATIC_ASSERT(std::is_integral<T>::value);
552 using U =
typename std::conditional<
sizeof(T) <=
sizeof(
unsigned),
554 typename std::make_unsigned<T>::type>::type;
586C4_INLINE_CONSTEXPR
const char hexchars[] =
"0123456789abcdef";
587C4_INLINE_CONSTEXPR
const char digits0099[] =
588 "0001020304050607080910111213141516171819"
589 "2021222324252627282930313233343536373839"
590 "4041424344454647484950515253545556575859"
591 "6061626364656667686970717273747576777879"
592 "8081828384858687888990919293949596979899";
596C4_SUPPRESS_WARNING_GCC_PUSH
597C4_SUPPRESS_WARNING_GCC(
"-Warray-bounds")
598#if (defined(__GNUC__) && (__GNUC__ >= 7))
599C4_SUPPRESS_WARNING_GCC(
"-Wstringop-overflow")
613C4_HOT C4_ALWAYS_INLINE
616 C4_STATIC_ASSERT(std::is_integral<T>::value);
618 C4_ASSERT(buf.len >= digits_v);
625 const auto num = (v - quo * T(100)) << 1u;
627 buf.str[--digits_v] = detail::digits0099[num + 1];
628 buf.str[--digits_v] = detail::digits0099[num];
632 C4_ASSERT(digits_v == 2);
633 const auto num = v << 1u;
634 buf.str[1] = detail::digits0099[num + 1];
635 buf.str[0] = detail::digits0099[num];
639 C4_ASSERT(digits_v == 1);
640 buf.str[0] = (char)(
'0' + v);
646C4_HOT C4_ALWAYS_INLINE
649 C4_STATIC_ASSERT(std::is_integral<T>::value);
651 C4_ASSERT(buf.len >= digits_v);
654 buf.str[--digits_v] = detail::hexchars[v & T(15)];
657 C4_ASSERT(digits_v == 0);
662C4_HOT C4_ALWAYS_INLINE
665 C4_STATIC_ASSERT(std::is_integral<T>::value);
667 C4_ASSERT(buf.len >= digits_v);
670 buf.str[--digits_v] = (char)(
'0' + (v & T(7)));
673 C4_ASSERT(digits_v == 0);
678C4_HOT C4_ALWAYS_INLINE
681 C4_STATIC_ASSERT(std::is_integral<T>::value);
683 C4_ASSERT(buf.len >= digits_v);
686 buf.str[--digits_v] = (char)(
'0' + (v & T(1)));
689 C4_ASSERT(digits_v == 0);
716 C4_STATIC_ASSERT(std::is_integral<T>::value);
719 if C4_LIKELY(buf.len >= digits)
735 C4_STATIC_ASSERT(std::is_integral<T>::value);
738 if C4_LIKELY(buf.len >= digits)
754 C4_STATIC_ASSERT(std::is_integral<T>::value);
757 if C4_LIKELY(buf.len >= digits)
773 C4_STATIC_ASSERT(std::is_integral<T>::value);
776 C4_ASSERT(digits > 0);
777 if C4_LIKELY(buf.len >= digits)
785template<
class U>
using NumberWriter = size_t (*)(
substr, U);
786template<
class T, NumberWriter<T> writer>
787size_t write_num_digits(
substr buf, T v,
size_t num_digits)
noexcept
789 C4_STATIC_ASSERT(std::is_integral<T>::value);
790 const size_t ret = writer(buf, v);
791 if(ret >= num_digits)
793 else if(ret >= buf.len || num_digits > buf.len)
795 C4_ASSERT(num_digits >= ret);
796 const size_t delta =
static_cast<size_t>(num_digits - ret);
797 C4_ASSERT(ret + delta <= buf.len);
799 memmove(buf.str + delta, buf.str, ret);
801 memset(buf.str,
'0', delta);
814 return detail::write_num_digits<T, &write_dec<T>>(buf, val, num_digits);
823 return detail::write_num_digits<T, &write_hex<T>>(buf, val, num_digits);
832 return detail::write_num_digits<T, &write_bin<T>>(buf, val, num_digits);
841 return detail::write_num_digits<T, &write_oct<T>>(buf, val, num_digits);
846C4_SUPPRESS_WARNING_GCC_POP
854C4_SUPPRESS_WARNING_MSVC_PUSH
855C4_SUPPRESS_WARNING_MSVC(4365)
876 C4_STATIC_ASSERT(std::is_integral<I>::value);
877 C4_ASSERT(!s.empty());
881 if C4_UNLIKELY(c <
'0' || c >
'9')
883 *v = ((*v) * I(10)) + (I(c) - I(
'0'));
904 C4_STATIC_ASSERT(std::is_integral<I>::value);
905 C4_ASSERT(!s.empty());
910 if(c >=
'0' && c <=
'9')
912 else if(c >=
'a' && c <=
'f')
913 cv = I(10) + (I(c) - I(
'a'));
914 else if(c >=
'A' && c <=
'F')
915 cv = I(10) + (I(c) - I(
'A'));
918 *v = ((*v) * I(16)) + cv;
939 C4_STATIC_ASSERT(std::is_integral<I>::value);
940 C4_ASSERT(!s.empty());
969 C4_STATIC_ASSERT(std::is_integral<I>::value);
970 C4_ASSERT(!s.empty());
974 if C4_UNLIKELY(c <
'0' || c >
'7')
976 *v = ((*v) * I(8)) + (I(c) - I(
'0'));
983C4_SUPPRESS_WARNING_MSVC_POP
990C4_SUPPRESS_WARNING_GCC_WITH_PUSH(
"-Wswitch-default")
994inline size_t _itoa2buf(
substr buf,
size_t pos,
csubstr val)
noexcept
996 C4_ASSERT(pos < buf.len);
997 C4_ASSERT(pos + val.len <= buf.len);
998 C4_ASSERT(val.len > 0);
999 memcpy(buf.str + pos, val.str, val.len);
1000 return pos + val.len;
1002inline size_t _itoa2bufwithdigits(
substr buf,
size_t pos,
size_t num_digits,
csubstr val)
noexcept
1004 num_digits = num_digits > val.len ? num_digits - val.len : 0;
1005 C4_ASSERT(num_digits + val.len <= buf.len);
1006 for(
size_t i = 0; i < num_digits; ++i)
1008 return detail::_itoa2buf(buf, pos, val);
1011C4_NO_INLINE
size_t _itoadec2buf(
substr buf)
noexcept
1013 using digits_type = detail::charconv_digits<I>;
1014 if C4_UNLIKELY(buf.len < digits_type::maxdigits_dec)
1015 return digits_type::maxdigits_dec;
1017 return detail::_itoa2buf(buf, 1, digits_type::min_value_dec());
1020C4_NO_INLINE
size_t _itoa2buf(
substr buf, I radix)
noexcept
1022 using digits_type = detail::charconv_digits<I>;
1024 if C4_LIKELY(buf.len > 0)
1025 buf.str[pos++] =
'-';
1029 if C4_UNLIKELY(buf.len < digits_type::maxdigits_dec)
1030 return digits_type::maxdigits_dec;
1031 pos =_itoa2buf(buf, pos, digits_type::min_value_dec());
1034 if C4_UNLIKELY(buf.len < digits_type::maxdigits_hex)
1035 return digits_type::maxdigits_hex;
1036 buf.str[pos++] =
'0';
1037 buf.str[pos++] =
'x';
1038 pos = _itoa2buf(buf, pos, digits_type::min_value_hex());
1041 if C4_UNLIKELY(buf.len < digits_type::maxdigits_bin)
1042 return digits_type::maxdigits_bin;
1043 buf.str[pos++] =
'0';
1044 buf.str[pos++] =
'b';
1045 pos = _itoa2buf(buf, pos, digits_type::min_value_bin());
1048 if C4_UNLIKELY(buf.len < digits_type::maxdigits_oct)
1049 return digits_type::maxdigits_oct;
1050 buf.str[pos++] =
'0';
1051 buf.str[pos++] =
'o';
1052 pos = _itoa2buf(buf, pos, digits_type::min_value_oct());
1058C4_NO_INLINE
size_t _itoa2buf(
substr buf, I radix,
size_t num_digits)
noexcept
1060 using digits_type = detail::charconv_digits<I>;
1062 size_t needed_digits = 0;
1063 if C4_LIKELY(buf.len > 0)
1064 buf.str[pos++] =
'-';
1069 needed_digits = num_digits+1 > digits_type::maxdigits_dec ? num_digits+1 : digits_type::maxdigits_dec;
1070 if C4_UNLIKELY(buf.len < needed_digits)
1071 return needed_digits;
1072 pos = _itoa2bufwithdigits(buf, pos, num_digits, digits_type::min_value_dec());
1076 needed_digits = num_digits+3 > digits_type::maxdigits_hex ? num_digits+3 : digits_type::maxdigits_hex;
1077 if C4_UNLIKELY(buf.len < needed_digits)
1078 return needed_digits;
1079 buf.str[pos++] =
'0';
1080 buf.str[pos++] =
'x';
1081 pos = _itoa2bufwithdigits(buf, pos, num_digits, digits_type::min_value_hex());
1085 needed_digits = num_digits+3 > digits_type::maxdigits_bin ? num_digits+3 : digits_type::maxdigits_bin;
1086 if C4_UNLIKELY(buf.len < needed_digits)
1087 return needed_digits;
1088 C4_ASSERT(buf.len >= digits_type::maxdigits_bin);
1089 buf.str[pos++] =
'0';
1090 buf.str[pos++] =
'b';
1091 pos = _itoa2bufwithdigits(buf, pos, num_digits, digits_type::min_value_bin());
1095 needed_digits = num_digits+3 > digits_type::maxdigits_oct ? num_digits+3 : digits_type::maxdigits_oct;
1096 if C4_UNLIKELY(buf.len < needed_digits)
1097 return needed_digits;
1098 C4_ASSERT(buf.len >= digits_type::maxdigits_oct);
1099 buf.str[pos++] =
'0';
1100 buf.str[pos++] =
'o';
1101 pos = _itoa2bufwithdigits(buf, pos, num_digits, digits_type::min_value_oct());
1122 C4_STATIC_ASSERT(std::is_signed<T>::value);
1130 if C4_LIKELY(v != std::numeric_limits<T>::min())
1134 if C4_LIKELY(buf.len >= digits + 1u)
1141 return detail::_itoadec2buf<T>(buf);
1154 C4_STATIC_ASSERT(std::is_signed<T>::value);
1155 C4_ASSERT(radix == 2 || radix == 8 || radix == 10 || radix == 16);
1156 C4_SUPPRESS_WARNING_GCC_PUSH
1157 #if (defined(__GNUC__) && (__GNUC__ >= 7))
1158 C4_SUPPRESS_WARNING_GCC(
"-Wstringop-overflow")
1162 if C4_LIKELY(v != std::numeric_limits<T>::min())
1168 if C4_LIKELY(buf.len > 0)
1172 unsigned digits = 0;
1177 if C4_LIKELY(buf.len >= pos + digits)
1182 if C4_LIKELY(buf.len >= pos + 2u + digits)
1184 buf.str[pos + 0] =
'0';
1185 buf.str[pos + 1] =
'x';
1192 if C4_LIKELY(buf.len >= pos + 2u + digits)
1194 buf.str[pos + 0] =
'0';
1195 buf.str[pos + 1] =
'b';
1202 if C4_LIKELY(buf.len >= pos + 2u + digits)
1204 buf.str[pos + 0] =
'0';
1205 buf.str[pos + 1] =
'o';
1211 return pos + digits;
1213 C4_SUPPRESS_WARNING_GCC_POP
1216 return detail::_itoa2buf<T>(buf, radix);
1229C4_ALWAYS_INLINE
size_t itoa(
substr buf, T v, T radix,
size_t num_digits)
noexcept
1231 C4_STATIC_ASSERT(std::is_signed<T>::value);
1232 C4_ASSERT(radix == 2 || radix == 8 || radix == 10 || radix == 16);
1233 C4_SUPPRESS_WARNING_GCC_PUSH
1234 #if (defined(__GNUC__) && (__GNUC__ >= 7))
1235 C4_SUPPRESS_WARNING_GCC(
"-Wstringop-overflow")
1239 if C4_LIKELY(v != std::numeric_limits<T>::min())
1245 if C4_LIKELY(buf.len > 0)
1249 unsigned total_digits = 0;
1254 total_digits = pos + (unsigned)(num_digits > total_digits ? num_digits : total_digits);
1255 if C4_LIKELY(buf.len >= total_digits)
1260 total_digits = pos + 2u + (unsigned)(num_digits > total_digits ? num_digits : total_digits);
1261 if C4_LIKELY(buf.len >= total_digits)
1263 buf.str[pos + 0] =
'0';
1264 buf.str[pos + 1] =
'x';
1265 write_hex(buf.sub(pos + 2), v, num_digits);
1270 total_digits = pos + 2u + (unsigned)(num_digits > total_digits ? num_digits : total_digits);
1271 if C4_LIKELY(buf.len >= total_digits)
1273 buf.str[pos + 0] =
'0';
1274 buf.str[pos + 1] =
'b';
1275 write_bin(buf.sub(pos + 2), v, num_digits);
1280 total_digits = pos + 2u + (unsigned)(num_digits > total_digits ? num_digits : total_digits);
1281 if C4_LIKELY(buf.len >= total_digits)
1283 buf.str[pos + 0] =
'0';
1284 buf.str[pos + 1] =
'o';
1285 write_oct(buf.sub(pos + 2), v, num_digits);
1289 return total_digits;
1291 C4_SUPPRESS_WARNING_GCC_POP
1294 return detail::_itoa2buf<T>(buf, radix, num_digits);
1317 C4_STATIC_ASSERT(std::is_unsigned<T>::value);
1332 C4_STATIC_ASSERT(std::is_unsigned<T>::value);
1333 C4_ASSERT(radix == 10 || radix == 16 || radix == 2 || radix == 8);
1334 unsigned digits = 0;
1339 if C4_LIKELY(buf.len >= digits)
1344 if C4_LIKELY(buf.len >= digits+2u)
1354 if C4_LIKELY(buf.len >= digits+2u)
1364 if C4_LIKELY(buf.len >= digits+2u)
1385C4_ALWAYS_INLINE
size_t utoa(
substr buf, T v, T radix,
size_t num_digits)
noexcept
1387 C4_STATIC_ASSERT(std::is_unsigned<T>::value);
1388 C4_ASSERT(radix == 10 || radix == 16 || radix == 2 || radix == 8);
1389 unsigned total_digits = 0;
1394 total_digits = (unsigned)(num_digits > total_digits ? num_digits : total_digits);
1395 if C4_LIKELY(buf.len >= total_digits)
1400 total_digits = 2u + (unsigned)(num_digits > total_digits ? num_digits : total_digits);
1401 if C4_LIKELY(buf.len >= total_digits)
1410 total_digits = 2u + (unsigned)(num_digits > total_digits ? num_digits : total_digits);
1411 if C4_LIKELY(buf.len >= total_digits)
1420 total_digits = 2u + (unsigned)(num_digits > total_digits ? num_digits : total_digits);
1421 if C4_LIKELY(buf.len >= total_digits)
1429 return total_digits;
1431C4_SUPPRESS_WARNING_GCC_POP
1468 C4_STATIC_ASSERT(std::is_integral<T>::value);
1469 C4_STATIC_ASSERT(std::is_signed<T>::value);
1471 if C4_UNLIKELY(str.len == 0)
1479 if(str.str[0] ==
'-')
1481 if C4_UNLIKELY(str.len == ++start)
1486 bool parsed_ok =
true;
1487 if(str.str[start] !=
'0')
1489 parsed_ok =
read_dec(str.sub(start), v);
1491 else if(str.len > start + 1)
1494 const char pfx = str.str[start + 1];
1495 if(pfx ==
'x' || pfx ==
'X')
1496 parsed_ok = str.len > start + 2 &&
read_hex(str.sub(start + 2), v);
1497 else if(pfx ==
'b' || pfx ==
'B')
1498 parsed_ok = str.len > start + 2 &&
read_bin(str.sub(start + 2), v);
1499 else if(pfx ==
'o' || pfx ==
'O')
1500 parsed_ok = str.len > start + 2 &&
read_oct(str.sub(start + 2), v);
1502 parsed_ok =
read_dec(str.sub(start + 1), v);
1506 parsed_ok =
read_dec(str.sub(start), v);
1508 if C4_LIKELY(parsed_ok)
1524 if(trimmed.
len &&
atoi(trimmed, v))
1525 return static_cast<size_t>(trimmed.
end() - str.
begin());
1560 C4_STATIC_ASSERT(std::is_integral<T>::value);
1562 if C4_UNLIKELY(str.len == 0 || str.front() ==
'-')
1565 bool parsed_ok =
true;
1566 if(str.str[0] !=
'0')
1574 const char pfx = str.str[1];
1575 if(pfx ==
'x' || pfx ==
'X')
1576 parsed_ok = str.len > 2 &&
read_hex(str.sub(2), v);
1577 else if(pfx ==
'b' || pfx ==
'B')
1578 parsed_ok = str.len > 2 &&
read_bin(str.sub(2), v);
1579 else if(pfx ==
'o' || pfx ==
'O')
1580 parsed_ok = str.len > 2 &&
read_oct(str.sub(2), v);
1603 if(trimmed.
len &&
atou(trimmed, v))
1604 return static_cast<size_t>(trimmed.
end() - str.
begin());
1611#if defined(_MSC_VER) && !defined(__clang__)
1612# pragma warning(pop)
1613#elif defined(__clang__)
1614# pragma clang diagnostic pop
1615#elif defined(__GNUC__)
1616# pragma GCC diagnostic pop
1628 if(str.len != limit.len)
1629 return str.len > limit.len;
1630 for(
size_t i = 0; i < limit.len; ++i)
1632 if(str.str[i] < limit.str[i])
1634 else if(str.str[i] > limit.str[i])
1655 ->
typename std::enable_if<std::is_unsigned<T>::value,
bool>::type
1657 C4_STATIC_ASSERT(std::is_integral<T>::value);
1659 if C4_UNLIKELY(str.len == 0)
1663 else if(str.str[0] ==
'0')
1672 size_t fno = str.first_not_of(
'0', 2);
1675 return !(str.len <= fno + (
sizeof(T) * 2));
1680 size_t fno = str.first_not_of(
'0', 2);
1683 return !(str.len <= fno +(
sizeof(T) * 8));
1688 size_t fno = str.first_not_of(
'0', 2);
1691 return detail::charconv_digits<T>::is_oct_overflow(str.sub(fno));
1695 size_t fno = str.first_not_of(
'0', 1);
1698 return detail::check_overflow(str.sub(fno), detail::charconv_digits<T>::max_value_dec());
1702 else if C4_UNLIKELY(str.str[0] ==
'-')
1708 return detail::check_overflow(str, detail::charconv_digits<T>::max_value_dec());
1722 ->
typename std::enable_if<std::is_signed<T>::value,
bool>::type
1724 C4_STATIC_ASSERT(std::is_integral<T>::value);
1725 if C4_UNLIKELY(str.len == 0)
1727 if(str.str[0] ==
'-')
1729 if(str.str[1] ==
'0')
1738 size_t fno = str.first_not_of(
'0', 3);
1741 return detail::check_overflow(str.sub(fno), detail::charconv_digits<T>::min_value_hex());
1746 size_t fno = str.first_not_of(
'0', 3);
1749 return detail::check_overflow(str.sub(fno), detail::charconv_digits<T>::min_value_bin());
1754 size_t fno = str.first_not_of(
'0', 3);
1757 return detail::check_overflow(str.sub(fno), detail::charconv_digits<T>::min_value_oct());
1761 size_t fno = str.first_not_of(
'0', 2);
1764 return detail::check_overflow(str.sub(fno), detail::charconv_digits<T>::min_value_dec());
1770 return detail::check_overflow(str.sub(1), detail::charconv_digits<T>::min_value_dec());
1773 else if(str.str[0] ==
'0')
1782 size_t fno = str.first_not_of(
'0', 2);
1785 const size_t len = str.len - fno;
1786 return !((len <
sizeof (T) * 2) || (len ==
sizeof(T) * 2 && str.str[fno] <=
'7'));
1791 size_t fno = str.first_not_of(
'0', 2);
1794 return !(str.len <= fno + (
sizeof(T) * 8 - 1));
1799 size_t fno = str.first_not_of(
'0', 2);
1802 return detail::charconv_digits<T>::is_oct_overflow(str.sub(fno));
1806 size_t fno = str.first_not_of(
'0', 1);
1809 return detail::check_overflow(str.sub(fno), detail::charconv_digits<T>::max_value_dec());
1815 return detail::check_overflow(str, detail::charconv_digits<T>::max_value_dec());
1830#if (!C4CORE_HAVE_STD_FROMCHARS)
1833void get_real_format_str(
char (& C4_RESTRICT fmt)[N],
int precision,
RealFormat_e formatting,
const char* length_modifier=
"")
1837 iret = snprintf(fmt,
sizeof(fmt),
"%%%s%c", length_modifier, formatting);
1838 else if(precision == 0)
1839 iret = snprintf(fmt,
sizeof(fmt),
"%%.%s%c", length_modifier, formatting);
1841 iret = snprintf(fmt,
sizeof(fmt),
"%%.%d%s%c", precision, length_modifier, formatting);
1842 C4_ASSERT(iret >= 2 &&
size_t(iret) <
sizeof(fmt));
1860size_t print_one(
substr str,
const char* full_fmt, T v)
1866 int iret = _snprintf(str.str, str.len, full_fmt, v);
1872 iret = snprintf(
nullptr, 0, full_fmt, v);
1873 C4_ASSERT(iret > 0);
1875 size_t ret = (size_t) iret;
1878 int iret = snprintf(str.str, str.len, full_fmt, v);
1879 C4_ASSERT(iret >= 0);
1880 size_t ret = (size_t) iret;
1889#if (!C4CORE_HAVE_STD_FROMCHARS) && (!C4CORE_HAVE_FAST_FLOAT)
1895inline size_t scan_one(
csubstr str,
const char *type_fmt, T *v)
1914 int iret = std::snprintf(fmt,
sizeof(fmt),
"%%" "%zu" "%s" "%%n", str.len, type_fmt);
1916 C4_ASSERT(iret >= 0 &&
size_t(iret) < C4_COUNTOF(fmt));
1920 iret = std::sscanf(str.str, fmt, v, &num_chars);
1923 C4_ASSERT(num_chars >= 0);
1924 return (
size_t)(num_chars);
1929#if C4CORE_HAVE_STD_TOCHARS
1933 std::to_chars_result result;
1937 if(buf.len >
size_t(2))
1945 result = std::to_chars(buf.str + pos, buf.str + buf.len, v, (std::chars_format)formatting);
1947 result = std::to_chars(buf.str + pos, buf.str + buf.len, v, (std::chars_format)formatting, precision);
1948 if(result.ec == std::errc())
1951 C4_ASSERT(result.ptr >= buf.str);
1952 ptrdiff_t delta = result.ptr - buf.str;
1953 return static_cast<size_t>(delta);
1955 C4_ASSERT(result.ec == std::errc::value_too_large);
1966 size_t ret =
static_cast<size_t>(std::numeric_limits<T>::max_digits10);
1967 return ret > buf.len ? ret : buf.len + 1;
1972#if C4CORE_HAVE_FAST_FLOAT
1974C4_ALWAYS_INLINE
bool scan_rhex(
csubstr s, T *C4_RESTRICT val)
noexcept
1985 for( ; pos < s.len; ++pos)
1987 const char c = s.str[pos];
1988 if(c >=
'0' && c <=
'9')
1989 *val = (*val * T(16)) + T(c -
'0');
1990 else if(c >=
'a' && c <=
'f')
1991 *val = (*val * T(16)) + T(c -
'a');
1992 else if(c >=
'A' && c <=
'F')
1993 *val = (*val * T(16)) + T(c -
'A');
1999 else if(c ==
'p' || c ==
'P')
2012 for(T digit = T(0.0625); pos < s.len; ++pos, digit /= T(16))
2014 const char c = s.str[pos];
2015 if(c >=
'0' && c <=
'9')
2016 *val += digit * T(c -
'0');
2017 else if(c >=
'a' && c <=
'f')
2018 *val += digit * T(c -
'a');
2019 else if(c >=
'A' && c <=
'F')
2020 *val += digit * T(c -
'A');
2021 else if(c ==
'p' || c ==
'P')
2034 if C4_LIKELY(pos < s.len)
2036 if(s.str[pos] ==
'+')
2038 if C4_LIKELY(pos < s.len)
2040 int16_t powval = {};
2041 if C4_LIKELY(
atoi(s.sub(pos), &powval))
2043 *val *= ipow<T, int16_t, 16>(powval);
2073#if C4CORE_HAVE_STD_TOCHARS
2074 return detail::rtoa(str, v, precision, formatting);
2077 detail::get_real_format_str(
fmt, precision, formatting,
"");
2078 return detail::print_one(str,
fmt, v);
2099#if C4CORE_HAVE_STD_TOCHARS
2100 return detail::rtoa(str, v, precision, formatting);
2103 detail::get_real_format_str(
fmt, precision, formatting,
"l");
2104 return detail::print_one(str,
fmt, v);
2121C4_ALWAYS_INLINE
bool atof(
csubstr str,
float * C4_RESTRICT v)
noexcept
2123 C4_ASSERT(str.len > 0);
2124 C4_ASSERT(str.triml(
" \r\t\n").len == str.len);
2125#if C4CORE_HAVE_FAST_FLOAT
2127 bool isneg = (str.str[0] ==
'-');
2128 csubstr rem = str.sub(isneg || str.str[0] ==
'+');
2129 if( ! (rem.
len >= 2 && (rem.
str[0] ==
'0' && (rem.
str[1] ==
'x' || rem.
str[1] ==
'X'))))
2131 fast_float::from_chars_result result;
2132 result = fast_float::from_chars(str.str, str.str + str.len, *v);
2133 return result.ec == std::errc();
2135 else if(detail::scan_rhex(rem.
sub(2), v))
2137 *v *= isneg ? -1.f : 1.f;
2141#elif C4CORE_HAVE_STD_FROMCHARS
2142 std::from_chars_result result;
2143 result = std::from_chars(str.str, str.str + str.len, *v);
2144 return result.ec == std::errc();
2146 csubstr rem = str.
sub(str.str[0] ==
'-' || str.str[0] ==
'+');
2147 if(!(rem.
len >= 2 && (rem.
str[0] ==
'0' && (rem.
str[1] ==
'x' || rem.
str[1] ==
'X'))))
2161 csubstr trimmed = str.first_real_span();
2162 if(trimmed.
len == 0)
2164 if(
atof(trimmed, v))
2165 return static_cast<size_t>(trimmed.
end() - str.begin());
2182C4_ALWAYS_INLINE
bool atod(
csubstr str,
double * C4_RESTRICT v)
noexcept
2184 C4_ASSERT(str.len > 0);
2185 C4_ASSERT(str.triml(
" \r\t\n").len == str.len);
2186#if C4CORE_HAVE_FAST_FLOAT
2188 bool isneg = (str.str[0] ==
'-');
2189 csubstr rem = str.sub(isneg || str.str[0] ==
'+');
2190 if( ! (rem.
len >= 2 && (rem.
str[0] ==
'0' && (rem.
str[1] ==
'x' || rem.
str[1] ==
'X'))))
2192 fast_float::from_chars_result result;
2194 result = fast_float::from_chars(str.str, str.str + str.len, *v);
2198 return result.ec == std::errc();
2200 else if(detail::scan_rhex(rem.
sub(2), v))
2202 *v *= isneg ? -1. : 1.;
2206#elif C4CORE_HAVE_STD_FROMCHARS
2207 std::from_chars_result result;
2208 result = std::from_chars(str.str, str.str + str.len, *v);
2209 return result.ec == std::errc();
2211 csubstr rem = str.
sub(str.str[0] ==
'-' || str.str[0] ==
'+');
2212 if(!(rem.
len >= 2 && (rem.
str[0] ==
'0' && (rem.
str[1] ==
'x' || rem.
str[1] ==
'X'))))
2226 csubstr trimmed = str.first_real_span();
2227 if(trimmed.
len == 0)
2229 if(
atod(trimmed, v))
2230 return static_cast<size_t>(trimmed.
end() - str.begin());
2245#define C4_IF_NOT_FIXED_LENGTH_I_(T, ty) typename std::enable_if<std:: is_signed<T>::value && !is_fixed_length<T>::value_i, ty>
2246#define C4_IF_NOT_FIXED_LENGTH_U_(T, ty) typename std::enable_if<std::is_unsigned<T>::value && !is_fixed_length<T>::value_u, ty>
2267C4_ALWAYS_INLINE
size_t xtoa(
substr s, uint8_t v, uint8_t radix)
noexcept {
return utoa(s, v, radix); }
2268C4_ALWAYS_INLINE
size_t xtoa(
substr s, uint16_t v, uint16_t radix)
noexcept {
return utoa(s, v, radix); }
2269C4_ALWAYS_INLINE
size_t xtoa(
substr s, uint32_t v, uint32_t radix)
noexcept {
return utoa(s, v, radix); }
2270C4_ALWAYS_INLINE
size_t xtoa(
substr s, uint64_t v, uint64_t radix)
noexcept {
return utoa(s, v, radix); }
2271C4_ALWAYS_INLINE
size_t xtoa(
substr s, int8_t v, int8_t radix)
noexcept {
return itoa(s, v, radix); }
2272C4_ALWAYS_INLINE
size_t xtoa(
substr s, int16_t v, int16_t radix)
noexcept {
return itoa(s, v, radix); }
2273C4_ALWAYS_INLINE
size_t xtoa(
substr s, int32_t v, int32_t radix)
noexcept {
return itoa(s, v, radix); }
2274C4_ALWAYS_INLINE
size_t xtoa(
substr s, int64_t v, int64_t radix)
noexcept {
return itoa(s, v, radix); }
2276C4_ALWAYS_INLINE
size_t xtoa(
substr s, uint8_t v, uint8_t radix,
size_t num_digits)
noexcept {
return utoa(s, v, radix, num_digits); }
2277C4_ALWAYS_INLINE
size_t xtoa(
substr s, uint16_t v, uint16_t radix,
size_t num_digits)
noexcept {
return utoa(s, v, radix, num_digits); }
2278C4_ALWAYS_INLINE
size_t xtoa(
substr s, uint32_t v, uint32_t radix,
size_t num_digits)
noexcept {
return utoa(s, v, radix, num_digits); }
2279C4_ALWAYS_INLINE
size_t xtoa(
substr s, uint64_t v, uint64_t radix,
size_t num_digits)
noexcept {
return utoa(s, v, radix, num_digits); }
2280C4_ALWAYS_INLINE
size_t xtoa(
substr s, int8_t v, int8_t radix,
size_t num_digits)
noexcept {
return itoa(s, v, radix, num_digits); }
2281C4_ALWAYS_INLINE
size_t xtoa(
substr s, int16_t v, int16_t radix,
size_t num_digits)
noexcept {
return itoa(s, v, radix, num_digits); }
2282C4_ALWAYS_INLINE
size_t xtoa(
substr s, int32_t v, int32_t radix,
size_t num_digits)
noexcept {
return itoa(s, v, radix, num_digits); }
2283C4_ALWAYS_INLINE
size_t xtoa(
substr s, int64_t v, int64_t radix,
size_t num_digits)
noexcept {
return itoa(s, v, radix, num_digits); }
2288template <
class T> C4_ALWAYS_INLINE
auto xtoa(
substr buf, T v)
noexcept -> C4_IF_NOT_FIXED_LENGTH_I_(T,
size_t)::type { return
itoa(buf, v); }
2289template <
class T> C4_ALWAYS_INLINE
auto xtoa(substr buf, T v)
noexcept -> C4_IF_NOT_FIXED_LENGTH_U_(T,
size_t)::type { return write_dec(buf, v); }
2291C4_ALWAYS_INLINE
size_t xtoa(
substr s, T *v)
noexcept {
return itoa(s, (intptr_t)v, (intptr_t)16); }
2302C4_ALWAYS_INLINE
bool atox(
csubstr s, uint8_t *C4_RESTRICT v)
noexcept {
return atou(s, v); }
2303C4_ALWAYS_INLINE
bool atox(
csubstr s, uint16_t *C4_RESTRICT v)
noexcept {
return atou(s, v); }
2304C4_ALWAYS_INLINE
bool atox(
csubstr s, uint32_t *C4_RESTRICT v)
noexcept {
return atou(s, v); }
2305C4_ALWAYS_INLINE
bool atox(
csubstr s, uint64_t *C4_RESTRICT v)
noexcept {
return atou(s, v); }
2306C4_ALWAYS_INLINE
bool atox(
csubstr s, int8_t *C4_RESTRICT v)
noexcept {
return atoi(s, v); }
2307C4_ALWAYS_INLINE
bool atox(
csubstr s, int16_t *C4_RESTRICT v)
noexcept {
return atoi(s, v); }
2308C4_ALWAYS_INLINE
bool atox(
csubstr s, int32_t *C4_RESTRICT v)
noexcept {
return atoi(s, v); }
2309C4_ALWAYS_INLINE
bool atox(
csubstr s, int64_t *C4_RESTRICT v)
noexcept {
return atoi(s, v); }
2310C4_ALWAYS_INLINE
bool atox(
csubstr s,
float *C4_RESTRICT v)
noexcept {
return atof(s, v); }
2311C4_ALWAYS_INLINE
bool atox(
csubstr s,
double *C4_RESTRICT v)
noexcept {
return atod(s, v); }
2313template <
class T> C4_ALWAYS_INLINE
auto atox(
csubstr buf, T *C4_RESTRICT v)
noexcept -> C4_IF_NOT_FIXED_LENGTH_I_(T,
bool)::type { return
atoi(buf, v); }
2314template <
class T> C4_ALWAYS_INLINE
auto atox(csubstr buf, T *C4_RESTRICT v)
noexcept -> C4_IF_NOT_FIXED_LENGTH_U_(T,
bool)::type { return atou(buf, v); }
2316C4_ALWAYS_INLINE
bool atox(
csubstr s, T **v)
noexcept { intptr_t tmp;
bool ret =
atox(s, &tmp);
if(ret) { *v = (T*)tmp; }
return ret; }
2353template <
class T> C4_ALWAYS_INLINE
auto to_chars(
substr buf, T v)
noexcept -> C4_IF_NOT_FIXED_LENGTH_I_(T,
size_t)::type { return
itoa(buf, v); }
2354template <
class T> C4_ALWAYS_INLINE
auto to_chars(substr buf, T v)
noexcept -> C4_IF_NOT_FIXED_LENGTH_U_(T,
size_t)::type { return write_dec(buf, v); }
2357 ->
typename std::enable_if<!std::is_same<T, char>::value &&
2358 !std::is_same<T, const char>::value,
2361 return itoa(s, (intptr_t)v, (intptr_t)16);
2394template <
class T> C4_ALWAYS_INLINE
auto from_chars(
csubstr buf, T *C4_RESTRICT v)
noexcept -> C4_IF_NOT_FIXED_LENGTH_I_(T,
bool)::type { return
atoi(buf, v); }
2395template <
class T> C4_ALWAYS_INLINE
auto from_chars(csubstr buf, T *C4_RESTRICT v)
noexcept -> C4_IF_NOT_FIXED_LENGTH_U_(T,
bool)::type { return atou(buf, v); }
2397C4_ALWAYS_INLINE
bool from_chars(
csubstr buf, T **v)
noexcept { intptr_t tmp;
bool ret =
from_chars(buf, &tmp);
if(ret) { *v = (T*)tmp; }
return ret; }
2423template <
class T> C4_ALWAYS_INLINE
auto from_chars_first(csubstr buf, T *C4_RESTRICT v)
noexcept -> C4_IF_NOT_FIXED_LENGTH_U_(T,
size_t)::type { return atou_first(buf, v); }
2431#undef C4_IF_NOT_FIXED_LENGTH_I_
2432#undef C4_IF_NOT_FIXED_LENGTH_U_
2450 return buf.left_of(sz <= buf.len ? sz : buf.len);
2470 if(buf.str[0] ==
'0')
2472 *v =
false;
return true;
2474 else if(buf.str[0] ==
'1')
2476 *v =
true;
return true;
2479 else if(buf.len == 4)
2481 if(((buf.str[0] ==
't') && (0 == memcmp(buf.str + 1,
"rue", 3)))
2483 ((buf.str[0] ==
'T') && (0 == memcmp(buf.str + 1,
"rue", 3) ||
2484 0 == memcmp(buf.str + 1,
"RUE", 3))))
2486 *v =
true;
return true;
2489 else if(buf.len == 5)
2491 if(((buf.str[0] ==
'f') && (0 == memcmp(buf.str + 1,
"alse", 4)))
2493 ((buf.str[0] ==
'F') && (0 == memcmp(buf.str + 1,
"alse", 4) ||
2494 0 == memcmp(buf.str + 1,
"ALSE", 4))))
2496 *v =
false;
return true;
2512 csubstr trimmed = buf.first_non_empty_span();
2527 C4_XASSERT(buf.str);
2541 C4_XASSERT(buf.str);
2562 C4_ASSERT(!buf.overlaps(v));
2563 size_t len = buf.len < v.len ? buf.len : v.len;
2569 C4_ASSERT(buf.str !=
nullptr);
2570 C4_ASSERT(v.str !=
nullptr);
2571 memcpy(buf.str, v.str, len);
2586 csubstr trimmed = buf.first_non_empty_span();
2587 if(trimmed.
len == 0)
2590 return static_cast<size_t>(trimmed.
end() - buf.begin());
2600 C4_ASSERT(!buf.overlaps(v));
2601 size_t len = buf.len < v.len ? buf.len : v.len;
2607 C4_ASSERT(buf.str !=
nullptr);
2608 C4_ASSERT(v.str !=
nullptr);
2609 memcpy(buf.str, v.str, len);
2617 C4_ASSERT(!buf.overlaps(*v));
2619 if(v->len >= buf.len)
2626 C4_ASSERT(buf.str !=
nullptr);
2627 C4_ASSERT(v->str !=
nullptr);
2628 memcpy(v->str, buf.str, buf.len);
2639 csubstr trimmed = buf.first_non_empty_span();
2641 if C4_UNLIKELY(trimmed.
len == 0)
2643 size_t len = trimmed.
len > v->len ? v->len : trimmed.
len;
2649 C4_ASSERT(buf.str !=
nullptr);
2650 C4_ASSERT(v->str !=
nullptr);
2651 memcpy(v->str, trimmed.
str, len);
2653 if C4_UNLIKELY(trimmed.
len > v->len)
2655 return static_cast<size_t>(trimmed.
end() - buf.begin());
2675template<
class CharPtr>
2677 ->
typename std::enable_if<std::is_same<CharPtr, char*>::value
2679 std::is_same<CharPtr, const char*>::value,
size_t>::type
2703#if defined(_MSC_VER) && !defined(__clang__)
2704# pragma warning(pop)
2705#elif defined(__clang__)
2706# pragma clang diagnostic pop
2707#elif defined(__GNUC__)
2708# pragma GCC diagnostic pop
#define C4_NO_UBSAN_IOVRFLW
bool atod(csubstr str, double *v) noexcept
Convert a string to a double precision real number.
size_t atod_first(csubstr str, double *v) noexcept
Convert a string to a double precision real number.
size_t atof_first(csubstr str, float *v) noexcept
Convert a string to a single precision real number.
bool atof(csubstr str, float *v) noexcept
Convert a string to a single precision real number.
bool atoi(csubstr str, T *v) noexcept
Convert a trimmed string to a signed integral value.
size_t atoi_first(csubstr str, T *v)
Select the next range of characters in the string that can be parsed as a signed integral value,...
bool atou(csubstr str, T *v) noexcept
Convert a trimmed string to an unsigned integral value.
size_t atou_first(csubstr str, T *v)
Select the next range of characters in the string that can be parsed as an unsigned integral value,...
bool atox(csubstr s, uint8_t *v) noexcept
@ FTOA_FLEX
print the real number in flexible format (like g)
@ FTOA_SCIENT
print the real number in scientific format (like e)
@ FTOA_FLOAT
print the real number in floating point format (like f)
@ FTOA_HEXA
print the real number in hexadecimal format (like a)
auto digits_dec(T v) noexcept -> typename std::enable_if< sizeof(T)==1u, unsigned >::type
decimal digits for 8 bit integers
unsigned digits_oct(T v_) noexcept
return the number of digits required to encode an octal number.
unsigned digits_hex(T v) noexcept
return the number of digits required to encode an hexadecimal number.
unsigned digits_bin(T v) noexcept
return the number of digits required to encode a binary number.
size_t dtoa(substr str, double v, int precision=-1, RealFormat_e formatting=FTOA_FLEX) noexcept
Convert a double-precision real number to string.
size_t from_chars_first(csubstr buf, uint8_t *v) noexcept
bool from_chars(csubstr buf, uint8_t *v) noexcept
size_t ftoa(substr str, float v, int precision=-1, RealFormat_e formatting=FTOA_FLEX) noexcept
Convert a single-precision real number to string.
size_t itoa(substr buf, T v) noexcept
convert an integral signed decimal to a string.
auto overflows(csubstr str) noexcept -> typename std::enable_if< std::is_unsigned< T >::value, bool >::type
Test if the following string would overflow when converted to associated integral types; this functio...
bool read_bin(csubstr s, I *v) noexcept
read a binary integer from a string.
bool read_oct(csubstr s, I *v) noexcept
read an octal integer from a string.
bool read_hex(csubstr s, I *v) noexcept
read an hexadecimal integer from a string.
bool read_dec(csubstr s, I *v) noexcept
read a decimal integer from a string.
size_t to_chars(ryml::substr buf, vec2< T > v)
bool from_chars(ryml::csubstr buf, vec2< T > *v)
basic_substring< char > substr
a mutable string view
basic_substring< const char > csubstr
an immutable string view
substr to_chars_sub(substr buf, T const &v) noexcept
call to_chars() and return a substr consisting of the written portion of the input buffer.
size_t utoa(substr buf, T v) noexcept
convert an integral unsigned decimal to a string.
void write_bin_unchecked(substr buf, T v, unsigned digits_v) noexcept
void write_dec_unchecked(substr buf, T v, unsigned digits_v) noexcept
void write_hex_unchecked(substr buf, T v, unsigned digits_v) noexcept
void write_oct_unchecked(substr buf, T v, unsigned digits_v) noexcept
size_t write_hex(substr buf, T v) noexcept
write an integer to a string in hexadecimal format.
size_t write_dec(substr buf, T v) noexcept
write an integer to a string in decimal format.
size_t write_bin(substr buf, T v) noexcept
write an integer to a string in binary format.
size_t write_oct(substr buf, T v) noexcept
write an integer to a string in octal format.
size_t xtoa(substr s, uint8_t v) noexcept
basic_substring first_uint_span() const
get the first span which can be interpreted as an unsigned integer
basic_substring first_int_span() const
get the first span which can be interpreted as a signed integer
size_t len
the length of the substring
iterator begin() noexcept
bool overlaps(ro_substr const that) const noexcept
true if there is overlap of at least one element between that and *this
basic_substring sub(size_t first) const noexcept
return [first,len[
C * str
a restricted pointer to the first character of the substring