3#if defined(__cplusplus)
37static inline StrSlice ss_from(
const char* data,
size_t len) {
return (StrSlice){.data = data, .len = len}; }
40static inline StrSlice ss_from_cstr(
const char*
cstr) {
41 if (!
cstr)
return (StrSlice){0};
42 return (StrSlice){.data =
cstr, .len = strlen(
cstr)};
47#define SS_LIT(literal) ((StrSlice){.data = (literal), .len = sizeof(literal) - 1})
50static inline StrSlice ss_empty(
void) {
return (StrSlice){0}; }
53static inline void ss_print(StrSlice s) {
54 if (s.data) printf(
"%.*s", (
int)s.len, s.data);
57static inline void ss_println(StrSlice s) {
65static inline bool ss_is_valid(StrSlice s) {
68 return s.len == 0 || s.data != NULL;
72static inline bool ss_is_empty(StrSlice s) {
return s.len == 0; }
76static inline char* ss_to_owned_cstr(StrSlice s) {
77 if (!ss_is_valid(s))
return NULL;
78 return strndup(s.data, s.len);
85static inline StrSlice ss_slice(StrSlice s,
size_t start,
size_t len, StrSliceErr* err) {
86 if (!ss_is_valid(s)) {
87 if (err) *err = SS_NULL;
90 if (start + len > s.len) {
91 if (err) *err = SS_BOUNDS;
94 if (err) *err = SS_OK;
95 return (StrSlice){.data = s.data + start, .len = len};
99static inline StrSlice ss_skip(StrSlice s,
size_t n) {
100 if (n >= s.len)
return ss_empty();
101 return (StrSlice){.data = s.data + n, .len = s.len - n};
105static inline StrSlice ss_take(StrSlice s,
size_t n) {
106 if (n > s.len) n = s.len;
107 return (StrSlice){.data = s.data, .len = n};
112static inline bool ss_equal(StrSlice a, StrSlice b) {
113 return a.len == b.len && (a.data == b.data || memcmp(a.data, b.data, a.len) == 0);
117static inline bool ss_equal_nocase(StrSlice a, StrSlice b) {
118 if (a.len != b.len)
return false;
119 for (
size_t i = 0; i < a.len; ++i) {
120 unsigned char ca = (
unsigned char)a.data[i];
121 unsigned char cb = (
unsigned char)b.data[i];
122 if ((ca | 32u) != (cb | 32u))
return false;
127static inline bool ss_starts_with(StrSlice s, StrSlice prefix) {
128 return s.len >= prefix.len && memcmp(s.data, prefix.data, prefix.len) == 0;
131static inline bool ss_ends_with(StrSlice s, StrSlice suffix) {
132 return s.len >= suffix.len && memcmp(s.data + s.len - suffix.len, suffix.data, suffix.len) == 0;
138static inline size_t ss_find(StrSlice haystack, StrSlice needle) {
139 if (needle.len == 0)
return 0;
140 if (needle.len > haystack.len)
return (
size_t)-1;
141 size_t limit = haystack.len - needle.len;
142 for (
size_t i = 0; i <= limit; ++i) {
143 if (memcmp(haystack.data + i, needle.data, needle.len) == 0)
return i;
148static inline bool ss_contains(StrSlice s, StrSlice needle) {
return ss_find(s, needle) != (size_t)-1; }
153static inline StrSliceErr ss_split_on(StrSlice s, StrSlice sep, StrSlice* head, StrSlice* tail) {
154 size_t pos = ss_find(s, sep);
155 if (pos == (
size_t)-1)
return SS_NOT_FOUND;
156 *head = ss_take(s, pos);
157 *tail = ss_skip(s, pos + sep.len);
163static inline bool _ss_is_space(
char c) {
return c ==
' ' || c ==
'\t' || c ==
'\n' || c ==
'\r'; }
165static inline StrSlice ss_trim(StrSlice s) {
166 size_t lo = 0, hi = s.len;
167 while (lo < hi && _ss_is_space(s.data[lo])) ++lo;
168 while (hi > lo && _ss_is_space(s.data[hi - 1])) --hi;
169 return (StrSlice){.data = s.data + lo, .len = hi - lo};
175static inline bool ss_get(StrSlice s,
size_t i,
char* out) {
176 if (i >= s.len)
return false;
193static inline StrSliceErr ss_to_int(StrSlice s,
int* out) {
194 if (!out)
return SS_NULL;
199 if (i < s.len && s.data[i] ==
'-') {
202 }
else if (i < s.len && s.data[i] ==
'+') {
206 if (i >= s.len || s.data[i] <
'0' || s.data[i] >
'9')
return SS_NOT_FOUND;
210 unsigned int acc = 0;
211 for (; i < s.len; ++i) {
213 if (c <
'0' || c >
'9')
break;
214 unsigned int d = (
unsigned int)(c -
'0');
216 if (acc > (UINT_MAX - d) / 10u)
return SS_OVERFLOW;
222 if (acc > (
unsigned int)INT_MAX + 1u)
return SS_OVERFLOW;
223 *out = (acc == (
unsigned int)INT_MAX + 1u) ? INT_MIN : -(int)acc;
225 if (acc > (
unsigned int)INT_MAX)
return SS_OVERFLOW;
247static inline StrSliceErr ss_to_double(StrSlice s,
double* out) {
248 if (!out)
return SS_NULL;
253 if (i < s.len && s.data[i] ==
'-') {
256 }
else if (i < s.len && s.data[i] ==
'+') {
260 uint64_t mantissa = 0;
262 bool seen_dot =
false;
263 bool has_digits =
false;
264 bool saturated =
false;
266 for (; i < s.len; ++i) {
268 if (c >=
'0' && c <=
'9') {
271 uint64_t d = (uint64_t)(c -
'0');
272 if (mantissa > (UINT64_MAX - d) / 10ull) {
276 if (!seen_dot) ++dec_shift;
278 mantissa = mantissa * 10ull + d;
279 if (seen_dot) --dec_shift;
281 }
else if (!seen_dot) {
284 }
else if (c ==
'.' && !seen_dot) {
291 if (!has_digits)
return SS_NOT_FOUND;
295 if (i < s.len && (s.data[i] ==
'e' || s.data[i] ==
'E')) {
297 bool exp_neg =
false;
298 if (i < s.len && s.data[i] ==
'-') {
301 }
else if (i < s.len && s.data[i] ==
'+') {
306 if (i >= s.len || s.data[i] <
'0' || s.data[i] >
'9')
return SS_INVALID;
308 for (; i < s.len && s.data[i] >=
'0' && s.data[i] <=
'9'; ++i) {
309 if (exp_shift < 100000)
310 exp_shift = exp_shift * 10 + (s.data[i] -
'0');
312 if (exp_neg) exp_shift = -exp_shift;
315 int total_exp = dec_shift + exp_shift;
320 static const double _p10[23] = {
321 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11,
322 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22,
324 double result = (double)mantissa;
325 if (total_exp != 0) {
326 int abs_exp = total_exp < 0 ? -total_exp : total_exp;
327 if (abs_exp > 308) abs_exp = 308;
328 double scale = (abs_exp <= 22) ? _p10[abs_exp] : ({
330 for (
int j = 0; j < abs_exp; ++j) str *= 10.0;
333 result = (total_exp < 0) ? result / scale : result * scale;
336 *out = neg ? -result : result;
349static inline StrSliceErr ss_to_bool(StrSlice s,
bool* out) {
350 if (!out)
return SS_NULL;
352 if (ss_equal_nocase(s, SS_LIT(
"true")) || ss_equal_nocase(s, SS_LIT(
"yes")) || ss_equal_nocase(s, SS_LIT(
"on")) ||
353 ss_equal(s, SS_LIT(
"1"))) {
358 if (ss_equal_nocase(s, SS_LIT(
"false")) || ss_equal_nocase(s, SS_LIT(
"no")) || ss_equal_nocase(s, SS_LIT(
"off")) ||
359 ss_equal(s, SS_LIT(
"0"))) {
366#if defined(__cplusplus)
A dynamically resizable C string with SSO.