#include "strvec.h" #include "dvec.h" #include "allocator.h" #include #include int strvec_init(struct strvec *strvec, size_t cap, const struct allocator *allocator) { int rc; LIBSTRVEC_ABORT_ON_ARGS(!strvec || !allocator); rc = dvec_init(&strvec->vec, sizeof(char *), cap, allocator); LIBSTRVEC_ABORT_ON_ALLOC(rc < 0); return rc; } int strvec_deinit(struct strvec *strvec) { int rc; LIBSTRVEC_ABORT_ON_ALLOC(!strvec); rc = dvec_deinit(&strvec->vec); LIBSTRVEC_ABORT_ON_ALLOC(rc < 0); return rc; } struct strvec * strvec_alloc(size_t cap, const struct allocator *allocator, int *_rc) { struct strvec *strvec; int *rc, stub; LIBSTRVEC_ABORT_ON_ARGS(!allocator); rc = _rc ? _rc : &stub; strvec = allocator->alloc(allocator, sizeof(struct strvec), rc); if (!strvec && _rc) *rc = -*rc; if (!strvec) return NULL; *rc = strvec_init(strvec, cap, allocator); if (*rc) { allocator->free(allocator, strvec); return NULL; } return strvec; } int strvec_free(struct strvec *strvec) { const struct allocator *allocator; int rc; LIBSTRVEC_ABORT_ON_ARGS(!allocator); allocator = strvec->vec.allocator; rc = dvec_deinit(&strvec->vec); LIBSTRVEC_ABORT_ON_ALLOC(rc < 0); if (rc) return rc; rc = allocator->free(allocator, strvec); LIBSTRVEC_ABORT_ON_ALLOC(rc); if (rc) return -rc; return 0; } int strvec_copy(struct strvec *dst, struct strvec *src, const struct allocator *allocator) { char **str, *nstr; size_t len; int rc; LIBSTRVEC_ABORT_ON_ARGS(!dst || !src); dvec_copy(&dst->vec, &src->vec); for (DVEC_ITER(&dst->vec, str)) { if (!*str) continue; len = strlen(*str); nstr = allocator->alloc(allocator, len + 1, &rc); LIBSTRVEC_ABORT_ON_ALLOC(!nstr); if (!nstr) return rc; strncpy(nstr, *str, len + 1); *str = nstr; } return 0; } void strvec_move(struct strvec *dst, struct strvec *src) { LIBSTRVEC_ABORT_ON_ARGS(!dst || !src); memcpy(dst, src, sizeof(struct strvec)); } void strvec_swap(struct strvec *dst, struct strvec *src) { struct strvec tmp; LIBSTRVEC_ABORT_ON_ARGS(!dst || !src); memcpy(&tmp, dst, sizeof(struct dvec)); memcpy(dst, src, sizeof(struct dvec)); memcpy(src, &tmp, sizeof(struct dvec)); } int strvec_reserve(struct strvec *strvec, size_t cap) { int rc; LIBSTRVEC_ABORT_ON_ARGS(!strvec); rc = dvec_reserve(&strvec->vec, cap); LIBSTRVEC_ABORT_ON_ALLOC(rc < 0); return rc; } void strvec_clear(struct strvec *strvec) { LIBSTRVEC_ABORT_ON_ARGS(!strvec); dvec_clear(&strvec->vec); } int strvec_shrink(struct strvec *strvec) { int rc; LIBSTRVEC_ABORT_ON_ARGS(!strvec); rc = dvec_shrink(&strvec->vec); LIBSTRVEC_ABORT_ON_ALLOC(rc < 0); return rc; } int strvec_pushn(struct strvec *strvec, const char **str, size_t count) { const char **dst; int rc; LIBSTRVEC_ABORT_ON_ARGS(!strvec || !str || !count); rc = dvec_add_back(&strvec->vec, count); LIBSTRVEC_ABORT_ON_ALLOC(rc < 0); if (rc) return rc; dst = dvec_at_back(&strvec->vec, count - 1); memcpy(dst, str, count * sizeof(char *)); return 0; } const char ** strvec_popn(struct strvec *strvec, size_t count) { const char **pos; LIBSTRVEC_ABORT_ON_ARGS(!strvec || !count); pos = dvec_at_back(&strvec->vec, count); dvec_rm_back(&strvec->vec, count); return pos; } void strvec_replace(struct strvec *strvec, size_t index, const char *str) { const char **pos; LIBSTRVEC_ABORT_ON_ARGS(!strvec || index >= dvec_len(&strvec->vec)) pos = dvec_at(&strvec->vec, index); *pos = str; } void strvec_remove(struct strvec *strvec, size_t index, size_t count) { LIBSTRVEC_ABORT_ON_ARGS(!strvec); dvec_rm(&strvec->vec, index, count); } int strvec_remove_str(struct strvec *strvec, const char *str, const struct allocator *allocator) { const char **ent; size_t i; int rc; LIBSTRVEC_ABORT_ON_ARGS(!strvec); for (i = 0; i < strvec->vec.len; ) { ent = strvec_at(strvec, i); if (!str && !*ent || !strcmp(str, *ent)) { if (allocator) { rc = allocator->free(allocator, (char *) *ent); if (rc) return -rc; } strvec_remove(strvec, i, 1); } else { i++; } } return 0; } ssize_t strvec_find(struct strvec *strvec, size_t start, const char *str) { const char **ent; size_t i; LIBSTRVEC_ABORT_ON_ARGS(!strvec); for (i = start; i < strvec->vec.len; i++) { ent = strvec_at(strvec, i); if (!str && !*ent) return (ssize_t) i; if (!strcmp(str, *ent)) return (ssize_t) i; } return -1; } char * strvec_join(struct strvec *strvec, const char *sep, const struct allocator *allocator, int *_rc) { const char **ent; size_t len, seplen; char *str; seplen = strlen(sep); len = 0; for (STRVEC_ITER(strvec, ent)) { if (!*ent) continue; if (len) len += seplen; len += strlen(*ent); } str = allocator->alloc(allocator, len + 1, _rc); if (!str && _rc) *_rc = -*_rc; if (!str) return NULL; len = 0; for (STRVEC_ITER(strvec, ent)) { if (!*ent) continue; if (len) { strcpy(str + len, sep); len += seplen; } strcpy(str + len, *ent); len += strlen(*ent); } return str; } const char ** strvec_iter_fwd(const struct strvec *strvec, const char **p) { LIBSTRVEC_ABORT_ON_ARGS(!strvec); return dvec_iter_fwd(&strvec->vec, p); } const char ** strvec_iter_bwd(const struct strvec *strvec, const char **p) { LIBSTRVEC_ABORT_ON_ARGS(!strvec); return dvec_iter_bwd(&strvec->vec, p); }