21 #include <string_view>
24 #include <type_traits>
26 #ifndef STRFORMAT_NO_LOCALE
42 return ::malloc(size);
63 constexpr
static size_t alignment =
alignof(std::max_align_t);
79 return ::malloc(size);
142 if (size == 0) size = 1;
145 auto Alloc = [&]()->
void * {
146 if (h->
allocated + size <= h->capacity) {
165 size_t bufsize =
sizeof(
Header) + size;
170 }
else if (h->
next) {
205 static const double tbl[] = {
206 1e+00, 1e+01, 1e+02, 1e+03, 1e+04, 1e+05, 1e+06,
207 1e+07, 1e+08, 1e+09, 1e+10, 1e+11, 1e+12, 1e+13,
210 if (exp >= 0 && exp <
static_cast<int>(
sizeof tbl /
sizeof *tbl))
212 if (exp <= 0 && exp > -
static_cast<int>(
sizeof tbl /
sizeof *tbl))
213 return 1.0 / tbl[-exp];
215 return std::pow(10.0, exp);
233 static double my_strtod(
const char *nptr,
char **endptr)
235 const char *s = nptr;
237 bool saw_digit =
false;
240 bool exp_sign =
false;
244 while (std::isspace((
unsigned char)*s)) ++s;
247 if (*s ==
'+' || *s ==
'-') {
248 if (*s ==
'-') sign =
true;
253 while (std::isdigit((
unsigned char)*s)) {
255 value = value * 10.0 + (*s -
'0');
262 while (std::isdigit((
unsigned char)*s)) {
264 value = value * 10.0 + (*s -
'0');
272 if (endptr) *endptr =
const_cast<char *
>(nptr);
277 if (*s ==
'e' || *s ==
'E') {
279 const char *exp_start = s;
280 if (*s ==
'+' || *s ==
'-') {
281 if (*s ==
'-') exp_sign =
true;
284 if (std::isdigit((
unsigned char)*s)) {
285 while (std::isdigit((
unsigned char)*s)) {
286 exp_val = exp_val * 10 + (*s -
'0');
299 int total_exp = exp_val - frac_digits;
300 if (total_exp != 0) {
310 if (!std::isfinite(value)) {
312 value = sign ? -HUGE_VAL : HUGE_VAL;
313 }
else if (value == 0.0 && saw_digit && total_exp != 0) {
318 if (endptr) *endptr =
const_cast<char *
>(s);
330 while (isspace((
unsigned char)*
p)) {
335 }
else if (*
p ==
'-') {
340 if (
p[1] ==
'x' ||
p[1] ==
'X') {
346 int c = (
unsigned char)
p[i];
347 if (c < '0' || c >
'7')
break;
356 template <
typename T>
static inline T
parse_number(
char const *ptr, std::function<T(
char const *p,
int radix)> conv)
361 if constexpr (std::is_integral_v<T>) {
363 v =
static_cast<T
>(0 -
static_cast<std::make_unsigned_t<T>
>(v));
375 #ifdef STRFORMAT_NO_LOCALE
378 struct lconv *
lc =
nullptr;
382 template <
typename T>
static inline T
num(
char const *value,
Option_ const &opt);
386 return parse_number<char>(value, [](
char const *p,
int radix){
387 return (
char)strtol(p,
nullptr, radix);
393 return parse_number<uint32_t>(value, [](
char const *p,
int radix){
394 return strtoul(p,
nullptr, radix);
400 return parse_number<uint32_t>(value, [](
char const *p,
int radix){
401 return strtoul(p,
nullptr, radix);
407 return parse_number<uint64_t>(value, [](
char const *p,
int radix){
408 return strtoull(p,
nullptr, radix);
414 return parse_number<uint64_t>(value, [](
char const *p,
int radix){
415 return strtoull(p,
nullptr, radix);
418 #ifndef STRFORMAT_NO_FP
421 return parse_number<double>(value, [&opt](
char const *p,
int radix){
425 return strtod(p, nullptr);
428 return misc::my_strtod(p, nullptr);
431 return (
double)strtoll(p,
nullptr, radix);
436 template <
typename T>
static inline T
num(std::string
const &value,
Option_ const &opt)
438 return num<T>(value.data(), opt);
476 memcpy(
p->data, data, size);
515 Part *next =
p->next;
519 list->
head =
nullptr;
520 list->
last =
nullptr;
527 memset(
p->data,
c, n);
534 return "0123456789abcdef";
538 return "0123456789ABCDEF";
541 #ifndef STRFORMAT_NO_FP
544 if (std::isnan(val))
return alloc_part(
"#NAN");
545 if (std::isinf(val))
return alloc_part(
"#INF");
548 if (sign) val = -val;
550 int bufsize = precision + 400;
551 char *buf = (
char *)alloca(bufsize);
554 auto result = std::to_chars(ptr, buf + bufsize, val, std::chars_format::fixed, precision);
555 char *end = result.ptr;
558 char *dot = std::find(ptr, end,
'.');
560 while (end > dot + 1 && end[-1] ==
'0') end--;
561 if (end[-1] ==
'.') end--;
577 char *end = (
char *)alloca(n) + n - 1;
584 bool sign = (val < 0);
585 using U = std::make_unsigned_t<decltype(val)>;
591 int c =
u % 10 +
'0';
597 }
else if (force_sign) {
607 char *end = (
char *)alloca(n) + n - 1;
615 int c = val % 10 +
'0';
626 char *end = (
char *)alloca(n) + n - 1;
633 bool sign = (val < 0);
634 using U = std::make_unsigned_t<decltype(val)>;
641 int c =
u % 10 +
'0';
647 }
else if (force_sign) {
657 char *end = (
char *)alloca(n) + n - 1;
665 int c = val % 10 +
'0';
676 char *end = (
char *)alloca(n) + n - 1;
686 char c = digits[val & 7];
697 char *end = (
char *)alloca(n) + n - 1;
707 char c = digits[val & 7];
718 char *end = (
char *)alloca(n) + n - 1;
728 char c = digits[val & 15];
739 char *end = (
char *)alloca(n) + n - 1;
749 char c = digits[val & 15];
759 int n =
sizeof(uintptr_t) * 2 + 1;
760 char *end = (
char *)alloca(n) + n - 1;
766 uintptr_t v = (uintptr_t)val;
767 for (
int i = 0; i < (int)
sizeof(uintptr_t) * 2; i++) {
768 char c = digits[v & 15];
810 char const *end =
q.
text.data() +
q.
text.size();
811 while (
q.
next < end) {
812 if (*
q.
next ==
'%') {
813 if (
q.
next[1] ==
'%') {
818 }
else if (complete) {
831 #ifndef STRFORMAT_NO_FP
847 case 'c':
return format_c((
char)value);
848 case 'd':
return format((int32_t)value, 0);
849 case 'u':
return format(value, 0);
851 #ifndef STRFORMAT_NO_FP
852 case 'f':
return format((
double)value, 0);
862 case 'c':
return format_c((
char)value);
863 case 'd':
return format((int64_t)value, 0);
864 case 'u':
return format(value, 0);
866 #ifndef STRFORMAT_NO_FP
867 case 'f':
return format((
double)value, 0);
877 case 'c':
return format_c((
char)value);
878 case 'd':
return format((int32_t)value, 0);
879 case 'u':
return format(value, 0);
881 #ifndef STRFORMAT_NO_FP
882 case 'f':
return format((
double)value, 0);
892 case 'c':
return format_c((
char)value);
893 case 'd':
return format((int64_t)value, 0);
894 case 'u':
return format(value, 0);
896 #ifndef STRFORMAT_NO_FP
897 case 'f':
return format((
double)value, 0);
905 return format((int32_t)
c, hint);
907 #ifndef STRFORMAT_NO_FP
912 case 'c':
return format_c((
char)value);
913 case 'd':
return format((int64_t)value, 0);
914 case 'u':
return format((uint64_t)value, 0);
915 case 'o':
return format_o64((uint64_t)value, 0);
916 case 'x':
return format_x64((uint64_t)value, 0);
917 case 's':
return format_f(value,
true);
927 case 'c':
return format_c((
char)value);
928 case 'u':
return format((uint32_t)value, 0);
929 case 'o':
return format_o32((uint32_t)value, 0);
930 case 'x':
return format_x32((uint32_t)value, 0);
931 #ifndef STRFORMAT_NO_FP
932 case 'f':
return format((
double)value, 0);
942 case 'c':
return format_c((
char)value);
943 case 'd':
return format((int32_t)value, 0);
944 case 'o':
return format_o32((uint32_t)value, 0);
945 case 'x':
return format_x32((uint32_t)value, 0);
946 #ifndef STRFORMAT_NO_FP
947 case 'f':
return format((
double)value, 0);
957 case 'c':
return format_c((
char)value);
958 case 'u':
return format((uint64_t)value, 0);
959 case 'o':
return format_o64((uint64_t)value, 0);
960 case 'x':
return format_x64((uint64_t)value, 0);
961 #ifndef STRFORMAT_NO_FP
962 case 'f':
return format((
double)value, 0);
972 case 'c':
return format_c((
char)value);
973 case 'd':
return format((int64_t)value, 0);
976 #ifndef STRFORMAT_NO_FP
977 case 'f':
return format((
double)value, 0);
998 case 'u':
case 'o':
case 'x':
1004 #ifndef STRFORMAT_NO_FP
1010 return alloc_part(value, value + strlen(value));
1017 return format(value.data(), hint);
1021 std::string_view sv(value.data(), value.size());
1041 void format(std::function<
Part *(
int)>
const &callback,
int width,
int precision)
1044 if (*
q.
next ==
'%') {
1051 int c = (
unsigned char)*
q.
next;
1054 }
else if (
c ==
'+') {
1056 }
else if (
c ==
'-') {
1064 auto GetNumber = [&](
int alternate_value){
1066 if (*
q.
next ==
'*') {
1070 int c = (
unsigned char)*
q.
next;
1071 if (!isdigit(
c))
break;
1075 if (value <= (std::numeric_limits<int>::max() - (
c -
'0')) / 10) {
1076 value = value * 10 + (
c -
'0');
1078 value = std::numeric_limits<int>::max();
1084 value = alternate_value;
1089 q.
width = GetNumber(width);
1091 if (*
q.
next ==
'.') {
1097 while (*
q.
next ==
'l') {
1104 int c = (
unsigned char)*
q.
next;
1114 int padlen =
q.
width -
p->size;
1117 char c =
p->data[0];
1119 if (
c ==
'+' ||
c ==
'-') {
1147 #ifndef STRFORMAT_NO_LOCALE
1160 #ifndef STRFORMAT_NO_LOCALE
1186 #ifndef STRFORMAT_NO_LOCALE
1188 return *
q.
opt.
lc->decimal_point;
1198 q.
text = text.empty() ? std::string_view(
"") : text;
1203 #ifndef STRFORMAT_NO_LOCALE
1212 format([&](
int hint){
return format(value, hint); }, width, precision);
1215 #ifndef STRFORMAT_NO_FP
1218 return arg(value, width, precision);
1223 return arg(value, width, precision);
1227 return arg(value, width, precision);
1231 return arg(value, width, precision);
1235 return arg(value, width, precision);
1239 return arg(value, width, precision);
1243 format([&](
int hint){
return format_o32(value, hint); }, width, precision);
1248 format([&](
int hint){
return format_o64(value, hint); }, width, precision);
1253 format([&](
int hint){
return format_x32(value, hint); }, width, precision);
1258 format([&](
int hint){
return format_x64(value, hint); }, width, precision);
1263 return arg(value, width, precision);
1267 return arg(value, width, precision);
1271 format([&](
int hint){ (void)hint;
return format_p(value); }, width, precision);
1277 return arg(value, width, precision);
1279 void render(std::function<
void (
char const *ptr,
int len)>
const &to)
1283 to(
p->data,
p->size);
1288 render([&](
char const *ptr,
int len){
1289 fwrite(ptr, 1, len, fp);
1294 render([&](
char const *ptr,
int len){
1295 ::write(fd, ptr, len);
1309 render([&](
char const *ptr,
int len){
1310 vec->insert(
vec->end(), ptr, ptr + len);
1316 render([&](
char const *ptr,
int len){
1317 str->append(ptr, len);
1322 std::vector<char> ret;
1329 result.reserve(
length());
1330 render([&](
char const *ptr,
int len){
1331 result.append(ptr, len);
1335 operator std::string ()