12static bool str_grow_(
Str *s,
size_t needed) {
13 if (needed <= s->capacity && s->
data != NULL)
return true;
16 while (cap < needed) {
17 if (ckd_mul(&cap, cap, 2)) {
24 if (ckd_add(&bytes, cap, 1))
return false;
28 if (p == NULL)
return false;
29 if (s->
data == NULL) p[0] =
'\0';
38 return str_grow_(s, capacity);
58 if (ckd_add(&needed, s->
len, additional))
return false;
59 return str_grow_(s, needed);
65 if (p == NULL)
return false;
73 if (s->
data != NULL) s->
data[0] =
'\0';
80 if (data != NULL && len < s->capacity) {
90 if (v.
len == 0)
return true;
97 memmove(data + len, v.
data, v.
len);
98 data[len + v.
len] =
'\0';
105 const bool aliased = s->
data != NULL &&
108 const size_t off = aliased ? (size_t)(v.
data - s->
data) : 0;
112 const char *src = aliased ? s->
data + off : v.
data;
137 char *end = room != 0 ? s->
data + s->
len : NULL;
138 int n = vsnprintf(end, room, fmt, ap);
139 bool ok = n >= 0 && (size_t)n < room;
144 if (end != NULL) *end =
'\0';
146 vsnprintf(s->
data + s->
len, (
size_t)n + 1, fmt, ap2);
166 size_t n = fread(tmp.
data + tmp.
len, 1, room, f);
174 if (ok && s->
data == NULL) {
188 bool got =
false, ok =
true;
190 for (
int c; (c = getc_unlocked(f)) != EOF;) {
192 if (c ==
'\n')
break;
200 if (!ok || !got || ferror(f)) {
202 if (s->
data != NULL) s->
data[old] =
'\0';
205 if (s->
data == NULL)
return true;
217 return s->
data != NULL ? s->
data :
"";
225 if (cstr == NULL)
return (
StrView){ .data =
"", .len = 0 };
226 return (
StrView){ .data = cstr, .len = strlen(cstr) };
233 const char *p = memchr(v.
data, c, v.
len);
238 if (needle.
len == 0)
return 0;
242 size_t last = v.
len - needle.
len;
243 for (
size_t i = 0; i <= last; i++) {
244 const char *p = memchr(v.
data + i, needle.
data[0], last - i + 1);
246 i = (size_t)(p - v.
data);
247 if (memcmp(p + 1, needle.
data + 1, needle.
len - 1) == 0)
return i;
254 int c = n != 0 ? memcmp(a.
data, b.
data, n) : 0;
255 if (c != 0)
return c;
264 return suffix.
len <= v.
len &&
269 assert(from <= to && to <= v.
len);
275static bool sv_space_(
char c) {
276 return c ==
' ' || (c >=
'\t' && c <=
'\r');
280 size_t from = 0, to = v.
len;
281 while (from < to && sv_space_(v.
data[from])) from++;
282 while (to > from && sv_space_(v.
data[to - 1])) to--;
287 assert(sep.
len != 0);
288 if (rest->
len == 0)
return false;
290 size_t at =
sv_find(*rest, sep);
301static bool sv_in_set_(
const uint64_t set[4],
char c) {
302 unsigned char u = (
unsigned char)c;
303 return (set[u >> 6] >> (u & 63)) & 1;
308 uint64_t set[4] = { 0 };
309 for (
size_t i = 0; i < delims.
len; i++) {
310 unsigned char c = (
unsigned char)delims.
data[i];
311 set[c >> 6] |= UINT64_C(1) << (c & 63);
314 size_t from = 0, n = rest->
len;
315 while (from < n && sv_in_set_(set, rest->
data[from])) from++;
317 while (to < n && !sv_in_set_(set, rest->
data[to])) to++;
333 if (v.
len > 0 && (v.
data[0] ==
'-' || v.
data[0] ==
'+')) {
334 neg = v.
data[0] ==
'-';
337 if (i == v.
len)
return false;
340 for (; i < v.
len; i++) {
341 unsigned d = (unsigned)(
unsigned char)v.
data[i] -
'0';
342 if (d > 9 || ckd_mul(&mag, mag, 10) || ckd_add(&mag, mag, d))
345 if (mag > (uint64_t)INT64_MAX + neg)
return false;
347 *out = neg ? -(int64_t)(mag - 1) - 1 : (int64_t)mag;
353 if (v.
len == 0 || v.
len >=
sizeof buf || sv_space_(v.
data[0]))
return false;
359 double d = strtod(buf, &end);
360 if (end != buf + v.
len || (errno == ERANGE && isinf(d)))
return false;
void * mem_realloc(const Allocator *a, void *old, size_t old_size, size_t new_size)
Resize old from old_size to new_size bytes through a.
size_t len
Number of bytes in the view.
size_t capacity
Content bytes that fit before the next realloc.
const char * data
First byte.
const Allocator * alloc
Source of data.
size_t len
Bytes of content, excluding the terminator.
char * data
Buffer, or null when nothing is allocated.
const char * str_cstr(const Str *s)
NUL-terminated contents of s, for C APIs such as fopen and puts.
size_t sv_find(StrView v, StrView needle)
Index of the first needle in v.
bool str_shrink_to_fit(Str *s)
Shrink the allocation to exactly len + 1 bytes.
StrView sv_from_cstr(const char *cstr)
View of cstr, measured with strlen.
bool sv_parse_f64(StrView v, double *out)
Parse all of v as a double, in any form strtod accepts in the C locale.
void str_clear(Str *s)
Set the length to zero.
StrView str_view(const Str *s)
Borrow the whole of s.
bool sv_token_next(StrView *rest, StrView delims, StrView *token)
strtok without the mutation: skip delims, then cut the next run of other bytes.
bool str_from(Str *s, StrView v)
Initialise s as a copy of v.
#define SV_NPOS
Returned by the find functions when there is no match.
void str_free(Str *s)
Free the buffer and reset s to the zero state.
bool str_append_file(Str *s, FILE *f)
Append everything left to read from f.
bool str_appendf(Str *s, const char *fmt,...)
Append the printf-style expansion of fmt.
bool str_push(Str *s, char c)
Append the single byte c.
StrView sv_trim(StrView v)
v without leading and trailing ASCII whitespace: space, \t, \n, \v, \f and \r.
bool sv_ends_with(StrView v, StrView suffix)
True when v ends with suffix.
bool str_read_line(Str *s, FILE *f)
Replace the contents of s with the next line of f, without its \n.
bool str_reserve(Str *s, size_t additional)
Ensure additional more bytes fit without another allocation.
bool str_append(Str *s, StrView v)
Append v.
bool sv_starts_with(StrView v, StrView prefix)
True when v begins with prefix.
bool str_eq(StrView a, StrView b)
True when a and b hold the same bytes.
bool sv_split_next(StrView *rest, StrView sep, StrView *piece)
Cut the piece before sep off rest.
bool sv_parse_i64(StrView v, int64_t *out)
Parse all of v as a base-10 integer with an optional sign.
bool str_from_cstr(Str *s, const char *cstr)
Initialise s as a copy of cstr.
bool str_with_capacity(Str *s, size_t capacity)
Initialise s as empty with room for capacity bytes of content.
StrView sv_slice(StrView v, size_t from, size_t to)
Bytes from up to but not including to.
int sv_cmp(StrView a, StrView b)
Byte order like memcmp.
size_t sv_find_byte(StrView v, char c)
Index of the first c in v.
bool str_vappendf(Str *s, const char *fmt, va_list ap)
str_appendf() for a va_list, like vprintf.
bool str_append_cstr(Str *s, const char *cstr)
Append cstr.
Owned, growable byte string.
Non-owning view of bytes; handy for passing slices and literals around.