21#ifndef PROTOCORE_STRBUF_H
22#define PROTOCORE_STRBUF_H
55 memcpy(b->
p + b->
len, s, sl);
92 if (!b->
ok || !s || b->
len + 1 >= b->
cap)
96 size_t room = b->
cap - b->
len - 1;
97 size_t sl = strnlen(s, room);
98 memcpy(b->
p + b->
len, s, sl);
125 size_t width = (digits < columns) ? columns : digits;
126 if (b->
len + width >= b->
cap)
130 for (
size_t i = width - digits; i-- > 0;)
132 b->
p[b->
len + i] =
' ';
134 for (
size_t i = width; i-- > width - digits;)
136 b->
p[b->
len + i] = (char)(
'0' + (
unsigned)(v % 10));
151 const char *rep =
nullptr;
217 const unsigned bits_per_digit = (base == 16) ? 4u : (base == 8) ? 3u : 0u;
218 const bool power_of_two = bits_per_digit != 0;
219 const uint64_t digit_mask = power_of_two ? ((1ull << bits_per_digit) - 1u) : 0u;
225 const bool narrow = !power_of_two && v <= 0xFFFFFFFFu;
231 while ((probe >>= bits_per_digit) != 0)
238 uint32_t p32 = (uint32_t)v;
253 if (digits < min_digits)
257 if (b->
len + digits >= b->
cap)
264 for (
unsigned i = digits; i-- > 0;)
266 b->
p[b->
len + i] =
"0123456789abcdef"[v & digit_mask];
267 v >>= bits_per_digit;
272 uint32_t v32 = (uint32_t)v;
273 for (
unsigned i = digits; i-- > 0;)
275 b->
p[b->
len + i] = (char)(
'0' + (
unsigned)(v32 % 10u));
281 for (
unsigned i = digits; i-- > 0;)
283 b->
p[b->
len + i] = (char)(
'0' + (
unsigned)(v % 10));
319 uint64_t mag = (v < 0) ? (uint64_t)(-(v + 1)) + 1u : (uint64_t)v;
329static const double PC_POW10_BIN[9] = {1e1, 1e2, 1e4, 1e8, 1e16, 1e32, 1e64, 1e128, 1e256};
335 memcpy(&bits, &v,
sizeof(bits));
336 return (bits >> 63) != 0;
343 memcpy(&bits, &v,
sizeof(bits));
344 return ((bits >> 52) & 0x7FFu) == 0x7FFu && (bits & 0xFFFFFFFFFFFFFull) == 0;
351 for (
int k = 0; p != 0 && k < 9; k++, p >>= 1)
355 r *= PC_POW10_BIN[k];
373 memcpy(&bits, &v,
sizeof(bits));
374 int be = (int)((bits >> 52) & 0x7FFu);
378 double s = v * 1e300;
379 memcpy(&bits, &s,
sizeof(bits));
380 be = (int)((bits >> 52) & 0x7FFu);
381 e = (int)(((int64_t)(be - 1023) * 78913) >> 18) - 300;
385 e = (int)(((int64_t)(be - 1023) * 78913) >> 18);
393 else if (v / 10.0 >= p)
409 for (
unsigned i = 1; i < digits; i++)
413 for (
unsigned i = 0; i < digits; i++)
415 if (i == point_after && i != 0)
419 pc_sb_ch(b, (
char)(
'0' + (
unsigned)((mant / div) % 10)));
475 for (
unsigned i = 0; i < sig; i++)
483 int p = (int)sig - 1 - e;
485 if (p > 300 || p < -300)
495 scaled = (p >= 0) ? v0 * pw : v0 / pw;
499 uint64_t mant = (uint64_t)scaled;
500 double frac = scaled - (double)mant;
501 if (frac > 0.5 || (frac == 0.5 && (mant & 1u)))
514 if (sig > 1 && mant < limit / 10)
516 mant = mant * 10 + 9;
520 unsigned digits = sig;
521 while (digits > 1 && mant % 10 == 0)
527 if (e < -4 || e >= (
int)sig)
532 unsigned mag = (unsigned)(e < 0 ? -e : e);
536 if (e >= (
int)digits - 1)
539 for (
int i = 0; i < e - (int)digits + 1; i++)
551 for (
int i = 0; i < -e - 1; i++)
592 if (v >= 18446744073709551616.0)
598 for (
unsigned i = 0; i < decimals; i++)
603 double ip = (double)(uint64_t)v;
604 uint64_t frac = (uint64_t)((v - ip) * scale + 0.5);
605 if (frac >= (uint64_t)scale)
623 for (
const char *p = s ? s :
""; *p; p++)
625 if (*p ==
'"' || *p ==
'\\')
632 b->
p[b->
len++] =
'\\';
635 else if (b->
len + 1 < b->
cap)
653 if (!b->
ok || b->
cap == 0)
int pc_dec_exp(double v)
Decimal exponent of v (the X such that 10^X <= |v| < 10^(X+1)), for v > 0.
void pc_sb_g(pc_sb *b, double v, unsigned sig)
Append v with sig significant digits, choosing fixed or scientific form - the printf "%....
void pc_sb_fixed(pc_sb *b, double v, unsigned decimals)
Append v with exactly decimals digits after the point (printf "%.<decimals>f").
size_t pc_sb_finish(pc_sb *b)
NUL-terminate and return the built length, or 0 if the build overflowed.
void pc_sb_uint(pc_sb *b, uint64_t v, unsigned base, unsigned min_digits)
Append v in base (10 or 16), left-padded with '0' to at least min_digits.
void pc_sb_u64_clip(pc_sb *b, uint64_t v, uint8_t columns)
Append v as decimal, right-aligned in at least columns with leading spaces, if the whole field fits -...
void pc_sb_xml(pc_sb *b, const char *s)
Append s XML-escaped (& < > "); a NULL s appends nothing.
void pc_sb_digits(pc_sb *b, uint64_t mant, unsigned digits, unsigned point_after)
Emit digits decimal digits of mant, with a '.' after the first point_after.
void pc_sb_hex(pc_sb *b, uint64_t v, unsigned min_digits)
Append v as lowercase hex, zero-padded to at least min_digits (printf "%0Nx").
void pc_sb_put_n(pc_sb *b, const char *s, size_t sl)
Append sl bytes of s - the primitive the others build on.
bool pc_signbit(double v)
True if v carries the IEEE-754 sign bit, including for -0.0 (a mask, not a divide).
bool pc_isinf(double v)
True if v is an infinity: all exponent bits set, zero significand.
void pc_sb_ch(pc_sb *b, char c)
Append a single character.
void pc_sb_u64(pc_sb *b, uint64_t v)
Append v as decimal (64-bit).
void pc_sb_lit(pc_sb *b, const char(&s)[N])
Append a string literal. The array parameter deduces N, so the length is a constant.
void pc_sb_u32w(pc_sb *b, uint32_t v, unsigned min_digits)
Append v as decimal, zero-padded to at least min_digits (printf "%0Nu").
void pc_sb_i64(pc_sb *b, int64_t v)
Append v as signed decimal (64-bit), with a leading '-' when negative.
void pc_sb_put_clip(pc_sb *b, const char *s)
Append as much of s as fits and stop, WITHOUT latching ok.
void pc_sb_json(pc_sb *b, const char *s)
Append s as a JSON string literal: double-quoted, with "</tt> and <tt>\</tt> backslash-escaped....
void pc_sb_put(pc_sb *b, const char *s)
Append NUL-terminated s; leaves the buffer untouched and clears ok if it would not fit.
void pc_sb_u32(pc_sb *b, uint32_t v)
Append v as decimal (no leading zeros; "0" for zero).
double pc_pow10i(int p)
10^p for p >= 0, by binary composition.
Bump-append target; ok latches false once an append would overflow cap.