Mercurial > lbo > hg > ylisp
view src/base/str.c @ 173:800a02381024
all: Clean up includes
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Mon, 09 Sep 2019 19:53:57 +0200 |
parents | 9fa6d6b4eb69 |
children |
line wrap: on
line source
#include "str.h" #include <assert.h> #include <stdarg.h> #include <stdbool.h> #include <stdint.h> #include <stdio.h> static inline bool ystr_is_inline(ystr_t *s) { return 0 == s->inner.big.size; } ystr_t ystr_new(const char* src) { ystr_t str; ystr_init(&str, src); return str; } void ystr_init(ystr_t *s, const char *src) { memset(s, 0, sizeof(ystr_t)); if (src == NULL) return; ystr_set(s, src); } void ystr_set_owned(ystr_t *s, char *src) { if (src == NULL) { ystr_destroy(s); return; } // Free previous memory. ystr_destroy(s); size_t len = strlen(src) + 1; s->inner.big.len = len; s->inner.big.cap = len; s->inner.big.size = 1; s->inner.big.base = src; } void ystr_set(ystr_t *s, const char *src) { if (src == NULL) { ystr_destroy(s); return; } ystr_set_n(s, src, strlen(src)); } void ystr_set_n(ystr_t *s, const char *src, size_t srclen) { if (src == NULL) { ystr_destroy(s); return; } if (srclen < YSTR_SMALL_THRESHOLD) { if (!ystr_is_inline(s)) yvec_destroy(&s->inner.big); memset(s, 0, sizeof(ystr_t)); // Marks as inline because inner.big.size == 0. memcpy(s->inner.small, src, srclen); } else { // +1 for terminating NULL byte. if (ystr_is_inline(s)) yvec_init(&s->inner.big, sizeof(char), srclen + 1); yvec_resize(&s->inner.big, srclen + 1); memcpy(s->inner.big.base, src, srclen + 1); } } void ystr_destroy(ystr_t *s) { if (!ystr_is_inline(s)) { free(s->inner.big.base); } memset(s, 0, sizeof(ystr_t)); } size_t ystr_len(ystr_t *s) { if (ystr_is_inline(s)) return strlen(s->inner.small); return s->inner.big.len - 1; } char* ystr_at(ystr_t *s, size_t index) { if (index >= ystr_len(s)) return NULL; if (ystr_is_inline(s)) { return &s->inner.small[index]; } return YVEC_AT(&s->inner.big, index, char); } const char *ystr_str(ystr_t *s) { if (ystr_is_inline(s)) { return s->inner.small; } return (const char *)s->inner.big.base; } int ystr_cmp(ystr_t *s1, ystr_t *s2) { return strcmp(ystr_str(s1), ystr_str(s2)); } int ystr_cmp_str(ystr_t *s1, const char *s2) { return strcmp(ystr_str(s1), s2); } void ystr_split(ystr_t *s, char limit, yvec_t *dst) { size_t parts = 0; size_t len = ystr_len(s); for (size_t i = 0; i < len; i++) { if (*ystr_at(s, i) == limit) parts++; } parts += 1; yvec_init(dst, sizeof(ystr_t), parts); size_t index = 0; while (index <= len) { ystr_t part; ystr_init(&part, NULL); size_t i = 0; for (i = index; i < len && *ystr_at(s, i) != limit; i++) ; ystr_set_n(&part, ystr_str(s) + index, i - index); YVEC_PUSH(dst, &part); index = i + 1; } } void ystr_resize(ystr_t *s, size_t new) { if (ystr_is_inline(s)) { size_t oldlen = strlen(s->inner.small); if (new < oldlen) { // Truncate small string. memset(s->inner.small + new, 0, YSTR_SMALL_THRESHOLD - new); } else if (new > YSTR_SMALL_THRESHOLD) { // Move to external representation. yvec_t ext; YVEC_INIT(&ext, new + 1, char); yvec_push_multi(&ext, s->inner.small, oldlen + 1); yvec_resize(&ext, new + 1); s->inner.big = ext; } else { // Size is between current size and threshold; do nothing. } return; } // +1 for NULL byte. yvec_resize(&s->inner.big, new + 1); } void ystr_append(ystr_t *s1, ystr_t *s2) { size_t oldlen = ystr_len(s1); ystr_resize(s1, ystr_len(s1) + ystr_len(s2)); // Still inline after resize? if (ystr_is_inline(s1)) { memcpy(s1->inner.small + strlen(s1->inner.small), ystr_str(s2), ystr_len(s2)); return; } // String has external vec with length of new string. Resize to length of // old string without NULL before appending to it (append starts at current // length, we want to skip the NULL byte) yvec_resize(&s1->inner.big, oldlen); yvec_push_multi(&s1->inner.big, ystr_str(s2), ystr_len(s2) + 1); } void ystr_copy(ystr_t* src, ystr_t* dst) { if (dst == NULL || src == NULL) return; ystr_destroy(dst); if (ystr_is_inline(src)) { memcpy(dst, src, sizeof(ystr_t)); return; } yvec_copy(&src->inner.big, &dst->inner.big); } ystr_t ystr_clone(ystr_t* src) { ystr_t new; ystr_init(&new, ystr_str(src)); return new; } #define YSTR_BUILD_BUF_SIZE 128 void ystr_build(ystr_t *s, const char *fmt, ...) { va_list args; char buf[YSTR_BUILD_BUF_SIZE]; memset(buf, 0, YSTR_BUILD_BUF_SIZE); va_start(args, fmt); int written = vsnprintf(buf, YSTR_BUILD_BUF_SIZE, fmt, args); va_end(args); // If truncated, make more space. if (written >= YSTR_BUILD_BUF_SIZE) { char *buf2 = calloc(written + 1, sizeof(char)); va_start(args, fmt); vsnprintf(buf2, written + 1, fmt, args); va_end(args); ystr_t fmtd; ystr_init(&fmtd, NULL); ystr_set_owned(&fmtd, buf2); ystr_append(s, &fmtd); ystr_destroy(&fmtd); return; } ystr_t fmtd; ystr_init(&fmtd, NULL); ystr_set_owned(&fmtd, buf); ystr_append(s, &fmtd); // No destroy, fmtd points to buffer on stack. }