ss_INLINE ss ss_box_flonum(ss_flonum_t v) { ss_s_flonum *self = ss_alloc(ss_t_flonum, sizeof(*self)); self->value = v; return self; }
ss_INLINE ss ss_alloc_copy(ss type, size_t size, void *ptr) { void *self = ss_alloc(type, size); memcpy(self, ptr, size); return self; }
static ss_t *aux_replace(ss_t **s, const sbool_t cat, const ss_t *src, const size_t off, const ss_t *s1, const ss_t *s2) { ASSERT_RETURN_IF(!s, ss_void); if (!s1) s1 = ss_void; if (!s2) s2 = ss_void; if (!src) src = ss_void; const size_t at = (cat && *s) ? sd_get_size(*s) : 0; const char *p0 = get_str_r(src), *p2 = get_str_r(s2); const size_t l1 = sd_get_size(s1), l2 = sd_get_size(s2); size_t i = off, l = sd_get_size(src); ss_t *out = NULL; ssize_t size_delta = l2 > l1 ? (ssize_t)(l2 - l1) : -(ssize_t)(l1 - l2); sbool_t aliasing = S_FALSE; size_t out_size = at + l; char *o, *o0; if (l2 >= l1) { /* resize required */ size_t nfound = 0; /* scan required size */ for (;; i+= l1, nfound++) if ((i = ss_find(src, i, s1)) == S_NPOS) break; if (nfound == 0) /* 0 occurrences: return */ return ss_check(s); if (size_delta >= 0) out_size += (size_t)size_delta * nfound; else out_size -= (size_t)(-size_delta) * nfound; /* allocate output string */ out = ss_alloc(out_size); if (!out) { S_ERROR("not enough memory"); sd_set_alloc_errors(*s); return ss_check(s); } o0 = o = get_str(out); /* copy prefix data (cat) */ if (at > 0) memcpy(o, get_str_r(*s), at); } else { if (s && *s && *s == src) { aliasing = S_TRUE; } else { if (ss_reserve(s, out_size) < out_size) /* BEHAVIOR */ return ss_check(s); } o0 = o = get_str(*s); } typedef void (*memcpy_t)(void *, const void *, size_t); memcpy_t f_cpy; if (aliasing) { f_cpy = (memcpy_t)memmove; } else { f_cpy = (memcpy_t)memcpy; o += at; if (off > 0) /* copy not affected data */ memcpy(o, p0, off); } o += off; size_t i_next = s1 == s2? S_NPOS : /* no replace */ ss_find(src, i + off, s1); for (i = off;;) { /* before match copy: */ if (i_next == S_NPOS) { f_cpy(o, p0 + i, l - i); o += (l - i); break; } f_cpy(o, p0 + i, i_next - i); o += (i_next - i); /* replace: */ f_cpy(o, p2, l2); o += l2; i = i_next + l1; /* prepare next search: */ i_next = ss_find(src, i, s1); } if (out) { ss_t *s_bck = *s; *s = out; ss_free(&s_bck); } set_size(*s, (size_t)(o - o0)); return *s; }
static ss_t *aux_toXcase(ss_t **s, const sbool_t cat, const ss_t *src, sint32_t (*towX)(sint32_t)) { ASSERT_RETURN_IF(!s, ss_void); if (!src) src = ss_void; const size_t ss = sd_get_size(src), sso_max = *s ? ss_get_max_size(*s) : 0; const char *ps = get_str_r(src); ss_t *out = NULL; const sbool_t aliasing = *s == src; unsigned char is_cached_usize = 0; ssize_t extra = sc_utf8_calc_case_extra_size(ps, 0, ss, towX); size_t cached_usize = 0, at; /* If possible, keep Unicode size cached: */ if (*s) { if (is_unicode_size_cached(*s) && is_unicode_size_cached(src)) { is_cached_usize = 1; cached_usize = get_unicode_size(src) + get_unicode_size(*s); } at = cat ? sd_get_size(*s) : 0; } else { /* copy */ if (is_unicode_size_cached(src)) { is_cached_usize = 1; cached_usize = get_unicode_size(src); } at = 0; } /* Check if it is necessary to allocate more memory: */ size_t sso_req = extra < 0 ? (at + ss - (size_t)(-extra)) : (at + ss + (size_t)extra); char *po0; if (!*s || sso_req > sso_max || (aliasing && extra > 0)) { if (*s && (*s)->ext_buffer) { /* BEHAVIOR */ S_ERROR("not enough memory: strings stored in the " "stored in fixed-length buffer can not be " "resized."); sd_set_alloc_errors(*s); return ss_check(s); } out = ss_alloc(sso_req); if (!out) { /* BEHAVIOR */ S_ERROR("not enough memory: can not " "change character case"); if (*s) sd_set_alloc_errors(*s); return ss_check(s); } char *pout = get_str(out); if (at > 0) /* cat */ memcpy(pout, get_str(*s), at); po0 = pout + at; } else { po0 = get_str(*s) + at; } /* Case conversion loop: */ size_t i = 0; int c = 0; char *po = po0, u8[SSU8_MAX_SIZE]; for (; i < ss;) { #ifdef S_ENABLE_UTF8_7BIT_PARALLEL_CASE_OPTIMIZATIONS unsigned *pou = (unsigned *)po; const size_t i2 = sc_parallel_toX(ps, i, ss, pou, towX); if (i != i2) { po += (i2 - i); i = i2; if (i >= ss) break; } #endif const size_t csize = ss_utf8_to_wc(ps, i, ss, &c, *s); const int c2 = towX(c); size_t csize2; if (c2 == c) { csize2 = csize; if (!aliasing) memcpy(po, ps + i, csize2); } else { csize2 = sc_wc_to_utf8(c2, u8, 0, SSU8_MAX_SIZE); memcpy(po, u8, csize2); } i += csize; po += csize2; } if (out) { /* Case of using a secondary string was required */ ss_t *s_bck = *s; *s = out; ss_free(&s_bck); } if (*s) { set_size(*s, sso_req); set_unicode_size_cached(*s, is_cached_usize); set_unicode_size(*s, cached_usize); } return ss_check(s); }