From 508d4759db4cc45fe49441dd19e40f38a497fe0f Mon Sep 17 00:00:00 2001 From: Tyge Løvset Date: Sat, 13 Mar 2021 13:03:29 +0100 Subject: Fixed some doc errors in csmap and cmap. Added some inline funcs to cstr. Added read.c example. --- benchmarks/others/csmap_v1.h | 478 +++++++++++++++++++++++++++++++++++++++++++ docs/cmap_api.md | 2 +- docs/csmap_api.md | 2 +- docs/cstr_api.md | 19 +- examples/csmap_v1.h | 478 ------------------------------------------- examples/mapmap.c | 22 +- examples/read.c | 27 +++ stc/cstr.h | 19 ++ 8 files changed, 551 insertions(+), 496 deletions(-) create mode 100644 benchmarks/others/csmap_v1.h delete mode 100644 examples/csmap_v1.h create mode 100644 examples/read.c diff --git a/benchmarks/others/csmap_v1.h b/benchmarks/others/csmap_v1.h new file mode 100644 index 00000000..b81d7554 --- /dev/null +++ b/benchmarks/others/csmap_v1.h @@ -0,0 +1,478 @@ +/* MIT License + * + * Copyright (c) 2021 Tyge Løvset, NORCE, www.norceresearch.no + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#ifndef CSMAP_H_INCLUDED +#define CSMAP_H_INCLUDED + +// Sorted/Ordered set and map - implemented as an AA-tree. +/* +#include +#include +using_csset(i, int); // Set of int +using_csmap(ic, int, char); // Map of int -> char + +int main(void) { + csset_sx s = csset_sx_init(); + csset_sx_insert(&s, 5); + csset_sx_insert(&s, 8); + c_foreach (i, csset_sx, s) + printf("set %d\n", i.ref->second); + csset_sx_del(&s); +} +*/ +#include +#include +#include + +#define using_csmap(...) \ + c_MACRO_OVERLOAD(using_csmap, __VA_ARGS__) + +#define using_csmap_3(X, Key, Mapped) \ + using_csmap_4(X, Key, Mapped, c_default_compare) + +#define using_csmap_4(X, Key, Mapped, keyCompare) \ + using_csmap_6(X, Key, Mapped, keyCompare, c_trivial_del, c_trivial_fromraw) + +#define using_csmap_6(X, Key, Mapped, keyCompare, mappedDel, mappedClone) \ + using_csmap_8(X, Key, Mapped, keyCompare, mappedDel, mappedClone, c_trivial_del, c_trivial_fromraw) + +#define using_csmap_8(X, Key, Mapped, keyCompare, mappedDel, mappedClone, keyDel, keyClone) \ + using_csmap_10(X, Key, Mapped, keyCompare, mappedDel, mappedClone, \ + keyDel, keyClone, c_trivial_toraw, Key) + +#define using_csmap_10(X, Key, Mapped, keyCompareRaw, mappedDel, mappedClone, \ + keyDel, keyFromRaw, keyToRaw, RawKey) \ + _using_AATREE(X, csmap_, Key, Mapped, keyCompareRaw, mappedDel, keyDel, \ + keyFromRaw, keyToRaw, RawKey, mappedClone, c_trivial_toraw, Mapped) + +/* csset: */ +#define using_csset(...) \ + c_MACRO_OVERLOAD(using_csset, __VA_ARGS__) + +#define using_csset_2(X, Key) \ + using_csset_3(X, Key, c_default_compare) + +#define using_csset_3(X, Key, keyCompare) \ + using_csset_5(X, Key, keyCompare, c_trivial_del, c_trivial_fromraw) + +#define using_csset_5(X, Key, keyCompare, keyDel, keyClone) \ + using_csset_7(X, Key, keyCompare, keyDel, keyClone, c_trivial_toraw, Key) + +#define using_csset_7(X, Key, keyCompareRaw, keyDel, keyFromRaw, keyToRaw, RawKey) \ + _using_AATREE(X, csset_, Key, Key, keyCompareRaw, @@, keyDel, \ + keyFromRaw, keyToRaw, RawKey, @@, @@, void) + +/* csset_str, csmap_str, csmap_strkey, csmap_strval: */ +#define using_csset_str() \ + _using_AATREE_strkey(str, csset_, cstr_t, @@, @@) +#define using_csmap_str() \ + _using_AATREE(str, csmap_, cstr_t, cstr_t, cstr_compare_raw, cstr_del, cstr_del, \ + cstr_from, cstr_c_str, const char*, cstr_from, cstr_c_str, const char*) + +#define using_csmap_strkey(...) \ + c_MACRO_OVERLOAD(using_csmap_strkey, __VA_ARGS__) + +#define using_csmap_strkey_2(X, Mapped) \ + _using_AATREE_strkey(X, csmap_, Mapped, c_trivial_del, c_trivial_fromraw) + +#define using_csmap_strkey_4(X, Mapped, mappedDel, mappedClone) \ + _using_AATREE_strkey(X, csmap_, Mapped, mappedDel, mappedClone) + +#define _using_AATREE_strkey(X, C, Mapped, mappedDel, mappedClone) \ + _using_AATREE(X, C, cstr_t, Mapped, cstr_compare_raw, mappedDel, cstr_del, \ + cstr_from, cstr_c_str, const char*, mappedClone, c_trivial_toraw, Mapped) + +#define using_csmap_strval(...) \ + c_MACRO_OVERLOAD(using_csmap_strval, __VA_ARGS__) + +#define using_csmap_strval_2(X, Key) \ + using_csmap_strval_3(X, Key, c_default_compare) + +#define using_csmap_strval_3(X, Key, keyCompare) \ + using_csmap_strval_5(X, Key, keyCompare, c_trivial_del, c_trivial_fromraw) + +#define using_csmap_strval_5(X, Key, keyCompare, keyDel, keyClone) \ + using_csmap_strval_7(X, Key, keyCompare, keyDel, keyClone, c_trivial_toraw, Key) + +#define using_csmap_strval_7(X, Key, keyCompare, keyDel, keyFromRaw, keyToRaw, RawKey) \ + _using_AATREE(X, csmap_, Key, cstr_t, keyCompare, cstr_del, keyDel, \ + keyFromRaw, keyToRaw, RawKey, cstr_from, cstr_c_str, const char*) + +#define SET_ONLY_csset_(...) __VA_ARGS__ +#define SET_ONLY_csmap_(...) +#define MAP_ONLY_csset_(...) +#define MAP_ONLY_csmap_(...) __VA_ARGS__ +#define KEY_REF_csset_(vp) (vp) +#define KEY_REF_csmap_(vp) (&(vp)->first) + +#define _using_AATREE_types(X, C, Key, Mapped) \ + typedef Key C##X##_key_t; \ + typedef Mapped C##X##_mapped_t; \ +\ + typedef SET_ONLY_##C( C##X##_key_t ) \ + MAP_ONLY_##C( struct {C##X##_key_t first; \ + C##X##_mapped_t second;} ) \ + C##X##_value_t; \ +\ + typedef struct C##X##_node { \ + struct C##X##_node *link[2]; \ + uint8_t level; \ + C##X##_value_t value; \ + } C##X##_node_t; \ +\ + typedef struct { \ + C##X##_value_t *ref; \ + int _top; \ + C##X##_node_t *_tn, *_st[48]; \ + } C##X##_iter_t + + +#define _using_AATREE(X, C, Key, Mapped, keyCompareRaw, mappedDel, keyDel, \ + keyFromRaw, keyToRaw, RawKey, mappedFromRaw, mappedToRaw, RawMapped) \ + _using_AATREE_types(X, C, Key, Mapped); \ +\ + typedef struct { \ + C##X##_node_t* root; \ + size_t size; \ + } C##X; \ +\ + typedef RawKey C##X##_rawkey_t; \ + typedef RawMapped C##X##_rawmapped_t; \ + typedef SET_ONLY_##C( C##X##_rawkey_t ) \ + MAP_ONLY_##C( struct {C##X##_rawkey_t first; \ + C##X##_rawmapped_t second;} ) \ + C##X##_rawvalue_t; \ +\ + typedef struct { \ + C##X##_value_t *ref; \ + bool inserted; \ + } C##X##_result_t; \ +\ + STC_API C##X \ + C##X##_init(void); \ + STC_INLINE bool \ + C##X##_empty(C##X m) {return m.size == 0;} \ + STC_INLINE size_t \ + C##X##_size(C##X m) {return m.size;} \ +\ + STC_API void \ + C##X##_del_r_(C##X##_node_t* tn); \ +\ + STC_INLINE void \ + C##X##_del(C##X* self) {C##X##_del_r_(self->root);} \ + STC_INLINE void \ + C##X##_clear(C##X* self) {C##X##_del(self); *self = C##X##_init();} \ + STC_INLINE void \ + C##X##_swap(C##X* a, C##X* b) {c_swap(C##X, *a, *b);} \ +\ + STC_INLINE void \ + C##X##_value_del(C##X##_value_t* val) { \ + keyDel(KEY_REF_##C(val)); \ + MAP_ONLY_##C( mappedDel(&val->second); ) \ + } \ + STC_INLINE C##X##_value_t \ + C##X##_value_clone(C##X##_value_t val) { \ + *KEY_REF_##C(&val) = keyFromRaw(keyToRaw(KEY_REF_##C(&val))); \ + MAP_ONLY_##C( val.second = mappedFromRaw(mappedToRaw(&val.second)); ) \ + return val; \ + } \ +\ + STC_API C##X##_node_t* C##X##_clone_r_(C##X##_node_t *tn); \ + STC_INLINE C##X \ + C##X##_clone(C##X bst) { \ + C##X clone = {C##X##_clone_r_(bst.root), bst.size}; \ + return clone; \ + } \ +\ + STC_API C##X##_value_t* \ + C##X##_find_it(const C##X* self, RawKey rkey, C##X##_iter_t* out); \ +\ + STC_INLINE C##X##_iter_t \ + C##X##_find(const C##X* self, RawKey rkey) { \ + C##X##_iter_t it; \ + C##X##_find_it(self, rkey, &it); \ + return it; \ + } \ + STC_INLINE bool \ + C##X##_contains(const C##X* self, RawKey rkey) { \ + C##X##_iter_t it; \ + return C##X##_find_it(self, rkey, &it) != NULL; \ + } \ +\ + STC_API C##X##_result_t \ + C##X##_insert_entry_(C##X* self, RawKey rkey); \ +\ + STC_INLINE C##X##_result_t \ + C##X##_emplace(C##X* self, RawKey rkey MAP_ONLY_##C(, RawMapped rmapped)) { \ + C##X##_result_t res = C##X##_insert_entry_(self, rkey); \ + if (res.inserted) { \ + *KEY_REF_##C(res.ref) = keyFromRaw(rkey); \ + MAP_ONLY_##C(res.ref->second = mappedFromRaw(rmapped);) \ + } \ + return res; \ + } \ + STC_INLINE void \ + C##X##_emplace_n(C##X* self, const C##X##_rawvalue_t arr[], size_t n) { \ + for (size_t i=0; isecond = mapped; )} \ + else {keyDel(&key); MAP_ONLY_##C( mappedDel(&mapped); )} \ + return res; \ + } \ +\ + MAP_ONLY_##C( \ + STC_INLINE C##X##_result_t \ + C##X##_insert_or_assign(C##X* self, Key key, Mapped mapped) { \ + C##X##_result_t res = C##X##_insert_entry_(self, keyToRaw(&key)); \ + if (res.inserted) res.ref->first = key; \ + else {keyDel(&key); mappedDel(&res.ref->second);} \ + res.ref->second = mapped; return res; \ + } \ + STC_INLINE C##X##_result_t \ + C##X##_put(C##X* self, Key k, Mapped m) { \ + return C##X##_insert_or_assign(self, k, m); \ + } \ + STC_INLINE C##X##_result_t \ + C##X##_emplace_or_assign(C##X* self, RawKey rkey, RawMapped rmapped) { \ + C##X##_result_t res = C##X##_insert_entry_(self, rkey); \ + if (res.inserted) res.ref->first = keyFromRaw(rkey); \ + else mappedDel(&res.ref->second); \ + res.ref->second = mappedFromRaw(rmapped); return res; \ + } \ + STC_INLINE C##X##_mapped_t* \ + C##X##_at(const C##X* self, RawKey rkey) { \ + C##X##_iter_t it; \ + return &C##X##_find_it(self, rkey, &it)->second; \ + }) \ +\ + STC_INLINE C##X##_value_t* \ + C##X##_front(const C##X* self) { \ + C##X##_node_t *tn = self->root; \ + while (tn->link[0]->level) tn = tn->link[0]; \ + return &tn->value; \ + } \ + STC_INLINE C##X##_value_t* \ + C##X##_back(const C##X* self) { \ + C##X##_node_t *tn = self->root; \ + while (tn->link[1]->level) tn = tn->link[1]; \ + return &tn->value; \ + } \ +\ + STC_API void \ + C##X##_next(C##X##_iter_t* it); \ +\ + STC_INLINE C##X##_iter_t \ + C##X##_begin(const C##X* self) { \ + C##X##_iter_t it = {NULL, 0, self->root}; \ + C##X##_next(&it); return it; \ + } \ + STC_INLINE C##X##_iter_t \ + C##X##_end(const C##X* self) {\ + C##X##_iter_t it = {NULL}; return it; \ + } \ + STC_INLINE C##X##_mapped_t* \ + C##X##_itval(C##X##_iter_t it) {return SET_ONLY_##C( it.ref ) \ + MAP_ONLY_##C( &it.ref->second );} \ +\ + STC_API C##X##_node_t* \ + C##X##_erase_r_(C##X##_node_t *tn, const C##X##_rawkey_t* rkey, int *erased); \ +\ + STC_INLINE size_t \ + C##X##_erase(C##X* self, RawKey rkey) { \ + int erased = 0; \ + self->root = C##X##_erase_r_(self->root, &rkey, &erased); \ + self->size -= erased; return erased; \ + } \ + STC_INLINE size_t \ + C##X##_erase_at(C##X* self, C##X##_iter_t pos) { \ + return C##X##_erase(self, keyToRaw(KEY_REF_##C(pos.ref))); \ + } \ +\ + _implement_AATREE(X, C, Key, Mapped, keyCompareRaw, mappedDel, keyDel, \ + keyFromRaw, keyToRaw, RawKey, mappedFromRaw, mappedToRaw, RawMapped) \ + typedef C##X C##X##_t + +/* -------------------------- IMPLEMENTATION ------------------------- */ + +#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION) +#define _implement_AATREE(X, C, Key, Mapped, keyCompareRaw, mappedDel, keyDel, \ + keyFromRaw, keyToRaw, RawKey, mappedFromRaw, mappedToRaw, RawMapped) \ + STC_DEF C##X \ + C##X##_init(void) { \ + C##X m = {(C##X##_node_t *) &aatree_nil, 0}; \ + return m; \ + } \ +\ + STC_DEF C##X##_value_t* \ + C##X##_find_it(const C##X* self, C##X##_rawkey_t rkey, C##X##_iter_t* out) { \ + C##X##_node_t *tn = self->root; \ + out->_top = 0; \ + while (tn->level) { \ + int c; C##X##_rawkey_t rx = keyToRaw(KEY_REF_##C(&tn->value)); \ + if ((c = keyCompareRaw(&rx, &rkey)) < 0) tn = tn->link[1]; \ + else if (c > 0) {out->_st[out->_top++] = tn; tn = tn->link[0];} \ + else {out->_tn = tn->link[1]; return (out->ref = &tn->value);} \ + } \ + return (out->ref = NULL); \ + } \ +\ + STC_DEF void \ + C##X##_next(C##X##_iter_t *it) { \ + C##X##_node_t *tn = it->_tn; \ + if (it->_top || tn->level) { \ + while (tn->level) { \ + it->_st[it->_top++] = tn; \ + tn = tn->link[0]; \ + } \ + tn = it->_st[--it->_top]; \ + it->_tn = tn->link[1]; \ + it->ref = &tn->value; \ + } else \ + it->ref = NULL; \ + } \ +\ + static C##X##_node_t * \ + C##X##_skew_(C##X##_node_t *tn) { \ + if (tn && tn->link[0]->level == tn->level && tn->level) { \ + C##X##_node_t *tmp = tn->link[0]; \ + tn->link[0] = tmp->link[1]; \ + tmp->link[1] = tn; \ + tn = tmp; \ + } \ + return tn; \ + } \ +\ + static C##X##_node_t * \ + C##X##_split_(C##X##_node_t *tn) { \ + if (tn->link[1]->link[1]->level == tn->level && tn->level) { \ + C##X##_node_t *tmp = tn->link[1]; \ + tn->link[1] = tmp->link[0]; \ + tmp->link[0] = tn; \ + tn = tmp; \ + ++tn->level; \ + } \ + return tn; \ + } \ +\ + static inline C##X##_node_t* \ + C##X##_insert_entry_i_(C##X##_node_t* tn, const C##X##_rawkey_t* rkey, C##X##_result_t* res) { \ + C##X##_node_t *up[64], *it = tn; \ + int c, top = 0, dir = 0; \ + while (it->level) { \ + up[top++] = it; \ + C##X##_rawkey_t r = keyToRaw(KEY_REF_##C(&it->value)); \ + if ((c = keyCompareRaw(&r, rkey)) == 0) {res->ref = &it->value; return tn;} \ + it = it->link[(dir = (c == -1))]; \ + } \ + tn = c_new_1(C##X##_node_t); \ + res->ref = &tn->value, res->inserted = true; \ + tn->link[0] = tn->link[1] = (C##X##_node_t*) &aatree_nil, tn->level = 1; \ + if (top == 0) return tn; \ + up[top - 1]->link[dir] = tn; \ + while (top--) { \ + if (top) dir = (up[top - 1]->link[1] == up[top]); \ + up[top] = C##X##_skew_(up[top]); \ + up[top] = C##X##_split_(up[top]); \ + if (top) up[top - 1]->link[dir] = up[top]; \ + } \ + return up[0]; \ + } \ +\ + STC_DEF C##X##_result_t \ + C##X##_insert_entry_(C##X* self, RawKey rkey) { \ + C##X##_result_t res = {NULL, false}; \ + self->root = C##X##_insert_entry_i_(self->root, &rkey, &res); \ + self->size += res.inserted; \ + return res; \ + } \ +\ + STC_DEF C##X##_node_t* \ + C##X##_erase_r_(C##X##_node_t *tn, const C##X##_rawkey_t* rkey, int *erased) { \ + if (tn->level == 0) \ + return tn; \ + C##X##_rawkey_t raw = keyToRaw(KEY_REF_##C(&tn->value)); \ + C##X##_node_t *tx; int c = keyCompareRaw(&raw, rkey); \ + if (c != 0) \ + tn->link[c == -1] = C##X##_erase_r_(tn->link[c == -1], rkey, erased); \ + else { \ + if (!*erased) {C##X##_value_del(&tn->value); *erased = 1;} \ + if (tn->link[0]->level && tn->link[1]->level) { \ + tx = tn->link[0]; \ + while (tx->link[1]->level) \ + tx = tx->link[1]; \ + tn->value = tx->value; \ + raw = keyToRaw(KEY_REF_##C(&tn->value)); \ + tn->link[0] = C##X##_erase_r_(tn->link[0], &raw, erased); \ + } else { \ + tx = tn; \ + tn = tn->link[tn->link[0]->level == 0]; \ + c_free(tx); \ + } \ + } \ + if (tn->link[0]->level < tn->level - 1 || tn->link[1]->level < tn->level - 1) { \ + if (tn->link[1]->level > --tn->level) \ + tn->link[1]->level = tn->level; \ + tn = C##X##_skew_(tn); \ + tx = tn->link[0] = C##X##_skew_(tn->link[0]); \ + tx->link[0] = C##X##_skew_(tx->link[0]); \ + tn = C##X##_split_(tn); \ + tn->link[0] = C##X##_split_(tn->link[0]); \ + } \ + return tn; \ + } \ +\ + STC_DEF C##X##_node_t* \ + C##X##_clone_r_(C##X##_node_t *tn) { \ + if (! tn->level) return tn; \ + C##X##_node_t *cn = c_new_1(C##X##_node_t); \ + cn->link[0] = C##X##_clone_r_(tn->link[0]); \ + cn->link[1] = C##X##_clone_r_(tn->link[1]); \ + cn->level = tn->level; \ + cn->value = C##X##_value_clone(tn->value); \ + return cn; \ + } \ +\ + STC_DEF void \ + C##X##_del_r_(C##X##_node_t* tn) { \ + if (tn->level != 0) { \ + C##X##_del_r_(tn->link[0]); \ + C##X##_del_r_(tn->link[1]); \ + C##X##_value_del(&tn->value); \ + c_free(tn); \ + } \ + } + + +_using_AATREE_types(VOID, csmap_, int, int); +static csmap_VOID_node_t aatree_nil = {&aatree_nil, &aatree_nil, 0}; + +#else +#define _implement_AATREE(X, C, Key, Mapped, keyCompareRaw, mappedDel, keyDel, \ + keyFromRaw, keyToRaw, RawKey, mappedFromRaw, mappedToRaw, RawMapped) +#endif + +#endif diff --git a/docs/cmap_api.md b/docs/cmap_api.md index 0bbc76c7..9ae72e44 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -64,7 +64,7 @@ bool cmap_X_contains(const cmap_X* self, RawKey rkey); cmap_X_result_t cmap_X_insert(cmap_X* self, Key key, Mapped mapped); // no change if key in map cmap_X_result_t cmap_X_insert_or_assign(cmap_X* self, Key key, Mapped mapped); // always update mapped -cmap_X_result_t cmap_X_put(cmap_X* self, RawKey rkey, RawMapped rmapped); // alias for insert_or_assign +cmap_X_result_t cmap_X_put(cmap_X* self, Key key, Mapped mapped); // alias for insert_or_assign cmap_X_result_t cmap_X_emplace(cmap_X* self, RawKey rkey, RawMapped rmapped); // no change if rkey in map cmap_X_result_t cmap_X_emplace_or_assign(cmap_X* self, RawKey rkey, RawMapped rmapped); // always update rmapped void cmap_X_emplace_n(cmap_X* self, const cmap_X_rawvalue_t arr[], size_t size); diff --git a/docs/csmap_api.md b/docs/csmap_api.md index 72688c26..d314958e 100644 --- a/docs/csmap_api.md +++ b/docs/csmap_api.md @@ -60,7 +60,7 @@ bool csmap_X_contains(const csmap_X* self, RawKey rkey); csmap_X_result_t csmap_X_insert(csmap_X* self, Key key, Mapped mapped); // no change if key in map csmap_X_result_t csmap_X_insert_or_assign(csmap_X* self, Key key, Mapped mapped); // always update mapped -csmap_X_result_t csmap_X_put(csmap_X* self, RawKey rkey, RawMapped rmapped); // alias for insert_or_assign +csmap_X_result_t csmap_X_put(csmap_X* self, Key key, Mapped mapped); // alias for insert_or_assign csmap_X_result_t csmap_X_emplace(csmap_X* self, RawKey rkey, RawMapped rmapped); // no change if rkey in map csmap_X_result_t csmap_X_emplace_or_assign(csmap_X* self, RawKey rkey, RawMapped rmapped); // always update rmapped void csmap_X_emplace_n(csmap_X* self, const csmap_X_rawvalue_t arr[], size_t size); diff --git a/docs/cstr_api.md b/docs/cstr_api.md index 9f26187b..7a483370 100644 --- a/docs/cstr_api.md +++ b/docs/cstr_api.md @@ -23,6 +23,8 @@ cstr cstr_from_n(const char* str, size_t n); cstr cstr_from_fmt(const char* fmt, ...); // printf() formatting cstr cstr_clone(cstr s); +cstr* cstr_take(cstr* self, cstr s); // take the constructed or moved string +cstr cstr_move(cstr* self); // move string to caller, leave empty string void cstr_del(cstr *self); // destructor size_t cstr_size(cstr s); @@ -33,21 +35,24 @@ bool cstr_empty(cstr s); size_t cstr_reserve(cstr* self, size_t capacity); void cstr_resize(cstr* self, size_t len, char fill); void cstr_clear(cstr* self); + cstr* cstr_assign(cstr* self, const char* str); +cstr* cstr_assign_s(cstr* self, cstr s); cstr* cstr_assign_n(cstr* self, const char* str, size_t n); -cstr* cstr_take(cstr* self, cstr s); // take the constructed or moved string -cstr cstr_move(cstr* self); // move string to caller, leave empty string cstr* cstr_append(cstr* self, const char* str); +cstr* cstr_append_s(cstr* self, cstr s); cstr* cstr_append_n(cstr* self, const char* str, size_t n); // appends len characters -void cstr_push_back(cstr* self, char ch); -void cstr_pop_back(cstr* self); + void cstr_insert(cstr* self, size_t pos, const char* str); +void cstr_insert_s(cstr* self, size_t pos, cstr s); void cstr_insert_n(cstr* self, size_t pos, const char* str, size_t n); -void cstr_erase(cstr* self, size_t pos); -void cstr_erase_n(cstr* self, size_t pos, size_t n); + void cstr_replace(cstr* self, size_t pos, size_t len, const char* str); +void cstr_replace_s(cstr* self, size_t pos, size_t len, cstr s); void cstr_replace_n(cstr* self, size_t pos, size_t len, const char* str, size_t n); +void cstr_erase(cstr* self, size_t pos); +void cstr_erase_n(cstr* self, size_t pos, size_t n); int cstr_compare(const cstr *s1, const cstr *s2); bool cstr_equals(cstr s, const char* str); @@ -63,6 +68,8 @@ bool cstr_ibegins_with(cstr s, const char* substr); bool cstr_ends_with(cstr s, const char* substr); bool cstr_iends_with(cstr s, const char* substr); +void cstr_push_back(cstr* self, char ch); +void cstr_pop_back(cstr* self); char* cstr_front(cstr* self); char* cstr_back(cstr* self); diff --git a/examples/csmap_v1.h b/examples/csmap_v1.h deleted file mode 100644 index ec63c021..00000000 --- a/examples/csmap_v1.h +++ /dev/null @@ -1,478 +0,0 @@ -/* MIT License - * - * Copyright (c) 2021 Tyge Løvset, NORCE, www.norceresearch.no - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -#ifndef CSMAP_H_INCLUDED -#define CSMAP_H_INCLUDED - -// Sorted/Ordered set and map - implemented as an AA-tree. -/* -#include -#include -using_csset(i, int); // Set of int -using_csmap(ic, int, char); // Map of int -> char - -int main(void) { - csset_sx s = csset_sx_init(); - csset_sx_insert(&s, 5); - csset_sx_insert(&s, 8); - c_foreach (i, csset_sx, s) - printf("set %d\n", i.ref->second); - csset_sx_del(&s); -} -*/ -#include -#include -#include - -#define using_csmap(...) \ - c_MACRO_OVERLOAD(using_csmap, __VA_ARGS__) - -#define using_csmap_3(X, Key, Mapped) \ - using_csmap_4(X, Key, Mapped, c_default_compare) - -#define using_csmap_4(X, Key, Mapped, keyCompare) \ - using_csmap_6(X, Key, Mapped, keyCompare, c_trivial_del, c_trivial_fromraw) - -#define using_csmap_6(X, Key, Mapped, keyCompare, mappedDel, mappedClone) \ - using_csmap_8(X, Key, Mapped, keyCompare, mappedDel, mappedClone, c_trivial_del, c_trivial_fromraw) - -#define using_csmap_8(X, Key, Mapped, keyCompare, mappedDel, mappedClone, keyDel, keyClone) \ - using_csmap_10(X, Key, Mapped, keyCompare, mappedDel, mappedClone, \ - keyDel, keyClone, c_trivial_toraw, Key) - -#define using_csmap_10(X, Key, Mapped, keyCompareRaw, mappedDel, mappedClone, \ - keyDel, keyFromRaw, keyToRaw, RawKey) \ - _using_AATREE(X, csmap_, Key, Mapped, keyCompareRaw, mappedDel, keyDel, \ - keyFromRaw, keyToRaw, RawKey, mappedClone, c_trivial_toraw, Mapped) - -/* csset: */ -#define using_csset(...) \ - c_MACRO_OVERLOAD(using_csset, __VA_ARGS__) - -#define using_csset_2(X, Key) \ - using_csset_3(X, Key, c_default_compare) - -#define using_csset_3(X, Key, keyCompare) \ - using_csset_5(X, Key, keyCompare, c_trivial_del, c_trivial_fromraw) - -#define using_csset_5(X, Key, keyCompare, keyDel, keyClone) \ - using_csset_7(X, Key, keyCompare, keyDel, keyClone, c_trivial_toraw, Key) - -#define using_csset_7(X, Key, keyCompareRaw, keyDel, keyFromRaw, keyToRaw, RawKey) \ - _using_AATREE(X, csset_, Key, Key, keyCompareRaw, @@, keyDel, \ - keyFromRaw, keyToRaw, RawKey, @@, @@, void) - -/* csset_str, csmap_str, csmap_strkey, csmap_strval: */ -#define using_csset_str() \ - _using_AATREE_strkey(str, csset_, cstr_t, @@, @@) -#define using_csmap_str() \ - _using_AATREE(str, csmap_, cstr_t, cstr_t, cstr_compare_raw, cstr_del, cstr_del, \ - cstr_from, cstr_c_str, const char*, cstr_from, cstr_c_str, const char*) - -#define using_csmap_strkey(...) \ - c_MACRO_OVERLOAD(using_csmap_strkey, __VA_ARGS__) - -#define using_csmap_strkey_2(X, Mapped) \ - _using_AATREE_strkey(X, csmap_, Mapped, c_trivial_del, c_trivial_fromraw) - -#define using_csmap_strkey_4(X, Mapped, mappedDel, mappedClone) \ - _using_AATREE_strkey(X, csmap_, Mapped, mappedDel, mappedClone) - -#define _using_AATREE_strkey(X, C, Mapped, mappedDel, mappedClone) \ - _using_AATREE(X, C, cstr_t, Mapped, cstr_compare_raw, mappedDel, cstr_del, \ - cstr_from, cstr_c_str, const char*, mappedClone, c_trivial_toraw, Mapped) - -#define using_csmap_strval(...) \ - c_MACRO_OVERLOAD(using_csmap_strval, __VA_ARGS__) - -#define using_csmap_strval_2(X, Key) \ - using_csmap_strval_3(X, Key, c_default_compare) - -#define using_csmap_strval_3(X, Key, keyCompare) \ - using_csmap_strval_5(X, Key, keyCompare, c_trivial_del, c_trivial_fromraw) - -#define using_csmap_strval_5(X, Key, keyCompare, keyDel, keyClone) \ - using_csmap_strval_7(X, Key, keyCompare, keyDel, keyClone, c_trivial_toraw, Key) - -#define using_csmap_strval_7(X, Key, keyCompare, keyDel, keyFromRaw, keyToRaw, RawKey) \ - _using_AATREE(X, csmap_, Key, cstr_t, keyCompare, cstr_del, keyDel, \ - keyFromRaw, keyToRaw, RawKey, cstr_from, cstr_c_str, const char*) - -#define SET_ONLY_csset_(...) __VA_ARGS__ -#define SET_ONLY_csmap_(...) -#define MAP_ONLY_csset_(...) -#define MAP_ONLY_csmap_(...) __VA_ARGS__ -#define KEY_REF_csset_(vp) (vp) -#define KEY_REF_csmap_(vp) (&(vp)->first) - -#define _using_AATREE_types(X, C, Key, Mapped) \ - typedef Key C##X##_key_t; \ - typedef Mapped C##X##_mapped_t; \ -\ - typedef SET_ONLY_##C( C##X##_key_t ) \ - MAP_ONLY_##C( struct {C##X##_key_t first; \ - C##X##_mapped_t second;} ) \ - C##X##_value_t; \ -\ - typedef struct C##X##_node { \ - struct C##X##_node *link[2]; \ - uint8_t level; \ - C##X##_value_t value; \ - } C##X##_node_t; \ -\ - typedef struct { \ - C##X##_value_t *ref; \ - int _top; \ - C##X##_node_t *_tn, *_st[48]; \ - } C##X##_iter_t - - -#define _using_AATREE(X, C, Key, Mapped, keyCompareRaw, mappedDel, keyDel, \ - keyFromRaw, keyToRaw, RawKey, mappedFromRaw, mappedToRaw, RawMapped) \ - _using_AATREE_types(X, C, Key, Mapped); \ -\ - typedef struct { \ - C##X##_node_t* root; \ - size_t size; \ - } C##X; \ -\ - typedef RawKey C##X##_rawkey_t; \ - typedef RawMapped C##X##_rawmapped_t; \ - typedef SET_ONLY_##C( C##X##_rawkey_t ) \ - MAP_ONLY_##C( struct {C##X##_rawkey_t first; \ - C##X##_rawmapped_t second;} ) \ - C##X##_rawvalue_t; \ -\ - typedef struct { \ - C##X##_value_t *ref; \ - bool inserted; \ - } C##X##_result_t; \ -\ - STC_API C##X \ - C##X##_init(void); \ - STC_INLINE bool \ - C##X##_empty(C##X m) {return m.size == 0;} \ - STC_INLINE size_t \ - C##X##_size(C##X m) {return m.size;} \ -\ - STC_API void \ - C##X##_del_r_(C##X##_node_t* tn); \ -\ - STC_INLINE void \ - C##X##_del(C##X* self) {C##X##_del_r_(self->root);} \ - STC_INLINE void \ - C##X##_clear(C##X* self) {C##X##_del(self); *self = C##X##_init();} \ - STC_INLINE void \ - C##X##_swap(C##X* a, C##X* b) {c_swap(C##X, *a, *b);} \ -\ - STC_INLINE void \ - C##X##_value_del(C##X##_value_t* val) { \ - keyDel(KEY_REF_##C(val)); \ - MAP_ONLY_##C( mappedDel(&val->second); ) \ - } \ - STC_INLINE C##X##_value_t \ - C##X##_value_clone(C##X##_value_t val) { \ - *KEY_REF_##C(&val) = keyFromRaw(keyToRaw(KEY_REF_##C(&val))); \ - MAP_ONLY_##C( val.second = mappedFromRaw(mappedToRaw(&val.second)); ) \ - return val; \ - } \ -\ - STC_API C##X##_node_t* C##X##_clone_r_(C##X##_node_t *tn); \ - STC_INLINE C##X \ - C##X##_clone(C##X bst) { \ - C##X clone = {C##X##_clone_r_(bst.root), bst.size}; \ - return clone; \ - } \ -\ - STC_API C##X##_value_t* \ - C##X##_find_it(const C##X* self, RawKey rkey, C##X##_iter_t* out); \ -\ - STC_INLINE C##X##_iter_t \ - C##X##_find(const C##X* self, RawKey rkey) { \ - C##X##_iter_t it; \ - C##X##_find_it(self, rkey, &it); \ - return it; \ - } \ - STC_INLINE bool \ - C##X##_contains(const C##X* self, RawKey rkey) { \ - C##X##_iter_t it; \ - return C##X##_find_it(self, rkey, &it) != NULL; \ - } \ -\ - STC_API C##X##_result_t \ - C##X##_insert_entry_(C##X* self, RawKey rkey); \ -\ - STC_INLINE C##X##_result_t \ - C##X##_emplace(C##X* self, RawKey rkey MAP_ONLY_##C(, RawMapped rmapped)) { \ - C##X##_result_t res = C##X##_insert_entry_(self, rkey); \ - if (res.inserted) { \ - *KEY_REF_##C(res.ref) = keyFromRaw(rkey); \ - MAP_ONLY_##C(res.ref->second = mappedFromRaw(rmapped);) \ - } \ - return res; \ - } \ - STC_INLINE void \ - C##X##_emplace_n(C##X* self, const C##X##_rawvalue_t arr[], size_t n) { \ - for (size_t i=0; isecond = mapped; )} \ - else {keyDel(&key); MAP_ONLY_##C( mappedDel(&mapped); )} \ - return res; \ - } \ -\ - MAP_ONLY_##C( \ - STC_INLINE C##X##_result_t \ - C##X##_insert_or_assign(C##X* self, Key key, Mapped mapped) { \ - C##X##_result_t res = C##X##_insert_entry_(self, keyToRaw(&key)); \ - if (res.inserted) res.ref->first = key; \ - else {keyDel(&key); mappedDel(&res.ref->second);} \ - res.ref->second = mapped; return res; \ - } \ - STC_INLINE C##X##_result_t \ - C##X##_put(C##X* self, Key k, Mapped m) { \ - return C##X##_insert_or_assign(self, k, m); \ - } \ - STC_INLINE C##X##_result_t \ - C##X##_emplace_or_assign(C##X* self, RawKey rkey, RawMapped rmapped) { \ - C##X##_result_t res = C##X##_insert_entry_(self, rkey); \ - if (res.inserted) res.ref->first = keyFromRaw(rkey); \ - else mappedDel(&res.ref->second); \ - res.ref->second = mappedFromRaw(rmapped); return res; \ - } \ - STC_INLINE C##X##_mapped_t* \ - C##X##_at(const C##X* self, RawKey rkey) { \ - C##X##_iter_t it; \ - return &C##X##_find_it(self, rkey, &it)->second; \ - }) \ -\ - STC_INLINE C##X##_value_t* \ - C##X##_front(const C##X* self) { \ - C##X##_node_t *tn = self->root; \ - while (tn->link[0]->level) tn = tn->link[0]; \ - return &tn->value; \ - } \ - STC_INLINE C##X##_value_t* \ - C##X##_back(const C##X* self) { \ - C##X##_node_t *tn = self->root; \ - while (tn->link[1]->level) tn = tn->link[1]; \ - return &tn->value; \ - } \ -\ - STC_API void \ - C##X##_next(C##X##_iter_t* it); \ -\ - STC_INLINE C##X##_iter_t \ - C##X##_begin(const C##X* self) { \ - C##X##_iter_t it = {NULL, 0, self->root}; \ - C##X##_next(&it); return it; \ - } \ - STC_INLINE C##X##_iter_t \ - C##X##_end(const C##X* self) {\ - C##X##_iter_t it = {NULL}; return it; \ - } \ - STC_INLINE C##X##_mapped_t* \ - C##X##_itval(C##X##_iter_t it) {return SET_ONLY_##C( it.ref ) \ - MAP_ONLY_##C( &it.ref->second );} \ -\ - STC_API C##X##_node_t* \ - C##X##_erase_r_(C##X##_node_t *tn, const C##X##_rawkey_t* rkey, int *erased); \ -\ - STC_INLINE size_t \ - C##X##_erase(C##X* self, RawKey rkey) { \ - int erased = 0; \ - self->root = C##X##_erase_r_(self->root, &rkey, &erased); \ - self->size -= erased; return erased; \ - } \ - STC_INLINE size_t \ - C##X##_erase_at(C##X* self, C##X##_iter_t pos) { \ - return C##X##_erase(self, keyToRaw(KEY_REF_##C(pos.ref))); \ - } \ -\ - _implement_AATREE(X, C, Key, Mapped, keyCompareRaw, mappedDel, keyDel, \ - keyFromRaw, keyToRaw, RawKey, mappedFromRaw, mappedToRaw, RawMapped) \ - typedef C##X C##X##_t - -/* -------------------------- IMPLEMENTATION ------------------------- */ - -#if !defined(STC_HEADER) || defined(STC_IMPLEMENTATION) -#define _implement_AATREE(X, C, Key, Mapped, keyCompareRaw, mappedDel, keyDel, \ - keyFromRaw, keyToRaw, RawKey, mappedFromRaw, mappedToRaw, RawMapped) \ - STC_DEF C##X \ - C##X##_init(void) { \ - C##X m = {(C##X##_node_t *) &aatree_nil, 0}; \ - return m; \ - } \ -\ - STC_DEF C##X##_value_t* \ - C##X##_find_it(const C##X* self, C##X##_rawkey_t rkey, C##X##_iter_t* out) { \ - C##X##_node_t *tn = self->root; \ - out->_top = 0; \ - while (tn->level) { \ - int c; C##X##_rawkey_t rx = keyToRaw(KEY_REF_##C(&tn->value)); \ - if ((c = keyCompareRaw(&rx, &rkey)) < 0) tn = tn->link[1]; \ - else if (c > 0) {out->_st[out->_top++] = tn; tn = tn->link[0];} \ - else {out->_tn = tn->link[1]; return (out->ref = &tn->value);} \ - } \ - return (out->ref = NULL); \ - } \ -\ - STC_DEF void \ - C##X##_next(C##X##_iter_t *it) { \ - C##X##_node_t *tn = it->_tn; \ - if (it->_top || tn->level) { \ - while (tn->level) { \ - it->_st[it->_top++] = tn; \ - tn = tn->link[0]; \ - } \ - tn = it->_st[--it->_top]; \ - it->_tn = tn->link[1]; \ - it->ref = &tn->value; \ - } else \ - it->ref = NULL; \ - } \ -\ - static C##X##_node_t * \ - C##X##_skew_(C##X##_node_t *tn) { \ - if (tn && tn->link[0]->level == tn->level && tn->level) { \ - C##X##_node_t *tmp = tn->link[0]; \ - tn->link[0] = tmp->link[1]; \ - tmp->link[1] = tn; \ - tn = tmp; \ - } \ - return tn; \ - } \ -\ - static C##X##_node_t * \ - C##X##_split_(C##X##_node_t *tn) { \ - if (tn->link[1]->link[1]->level == tn->level && tn->level) { \ - C##X##_node_t *tmp = tn->link[1]; \ - tn->link[1] = tmp->link[0]; \ - tmp->link[0] = tn; \ - tn = tmp; \ - ++tn->level; \ - } \ - return tn; \ - } \ -\ - static inline C##X##_node_t* \ - C##X##_insert_entry_i_(C##X##_node_t* tn, const C##X##_rawkey_t* rkey, C##X##_result_t* res) { \ - C##X##_node_t *up[64], *it = tn; \ - int c, top = 0, dir = 0; \ - while (it->level) { \ - up[top++] = it; \ - C##X##_rawkey_t r = keyToRaw(KEY_REF_##C(&it->value)); \ - if ((c = keyCompareRaw(&r, rkey)) == 0) {res->first = &it->value; return tn;} \ - it = it->link[(dir = (c == -1))]; \ - } \ - tn = c_new_1(C##X##_node_t); \ - res->first = &tn->value, res->second = true; \ - tn->link[0] = tn->link[1] = (C##X##_node_t*) &aatree_nil, tn->level = 1; \ - if (top == 0) return tn; \ - up[top - 1]->link[dir] = tn; \ - while (top--) { \ - if (top) dir = (up[top - 1]->link[1] == up[top]); \ - up[top] = C##X##_skew_(up[top]); \ - up[top] = C##X##_split_(up[top]); \ - if (top) up[top - 1]->link[dir] = up[top]; \ - } \ - return up[0]; \ - } \ -\ - STC_DEF C##X##_result_t \ - C##X##_insert_entry_(C##X* self, RawKey rkey) { \ - C##X##_result_t res = {NULL, false}; \ - self->root = C##X##_insert_entry_i_(self->root, &rkey, &res); \ - self->size += res.inserted; \ - return res; \ - } \ -\ - STC_DEF C##X##_node_t* \ - C##X##_erase_r_(C##X##_node_t *tn, const C##X##_rawkey_t* rkey, int *erased) { \ - if (tn->level == 0) \ - return tn; \ - C##X##_rawkey_t raw = keyToRaw(KEY_REF_##C(&tn->value)); \ - C##X##_node_t *tx; int c = keyCompareRaw(&raw, rkey); \ - if (c != 0) \ - tn->link[c == -1] = C##X##_erase_r_(tn->link[c == -1], rkey, erased); \ - else { \ - if (!*erased) {C##X##_value_del(&tn->value); *erased = 1;} \ - if (tn->link[0]->level && tn->link[1]->level) { \ - tx = tn->link[0]; \ - while (tx->link[1]->level) \ - tx = tx->link[1]; \ - tn->value = tx->value; \ - raw = keyToRaw(KEY_REF_##C(&tn->value)); \ - tn->link[0] = C##X##_erase_r_(tn->link[0], &raw, erased); \ - } else { \ - tx = tn; \ - tn = tn->link[tn->link[0]->level == 0]; \ - c_free(tx); \ - } \ - } \ - if (tn->link[0]->level < tn->level - 1 || tn->link[1]->level < tn->level - 1) { \ - if (tn->link[1]->level > --tn->level) \ - tn->link[1]->level = tn->level; \ - tn = C##X##_skew_(tn); \ - tx = tn->link[0] = C##X##_skew_(tn->link[0]); \ - tx->link[0] = C##X##_skew_(tx->link[0]); \ - tn = C##X##_split_(tn); \ - tn->link[0] = C##X##_split_(tn->link[0]); \ - } \ - return tn; \ - } \ -\ - STC_DEF C##X##_node_t* \ - C##X##_clone_r_(C##X##_node_t *tn) { \ - if (! tn->level) return tn; \ - C##X##_node_t *cn = c_new_1(C##X##_node_t); \ - cn->link[0] = C##X##_clone_r_(tn->link[0]); \ - cn->link[1] = C##X##_clone_r_(tn->link[1]); \ - cn->level = tn->level; \ - cn->value = C##X##_value_clone(tn->value); \ - return cn; \ - } \ -\ - STC_DEF void \ - C##X##_del_r_(C##X##_node_t* tn) { \ - if (tn->level != 0) { \ - C##X##_del_r_(tn->link[0]); \ - C##X##_del_r_(tn->link[1]); \ - C##X##_value_del(&tn->value); \ - c_free(tn); \ - } \ - } - - -_using_AATREE_types(VOID, csmap_, int, int); -static csmap_VOID_node_t aatree_nil = {&aatree_nil, &aatree_nil, 0}; - -#else -#define _implement_AATREE(X, C, Key, Mapped, keyCompareRaw, mappedDel, keyDel, \ - keyFromRaw, keyToRaw, RawKey, mappedFromRaw, mappedToRaw, RawMapped) -#endif - -#endif diff --git a/examples/mapmap.c b/examples/mapmap.c index e22ac80c..fc6c8a79 100644 --- a/examples/mapmap.c +++ b/examples/mapmap.c @@ -3,24 +3,26 @@ #include #include +// unordered_map>: + using_cmap_str(); using_cmap_strkey(cfg, cmap_str, cmap_str_del, c_no_clone); int main(void) { - cmap_cfg config = cmap_cfg_init(); + cmap_cfg cfg = cmap_cfg_init(); cmap_str init = cmap_str_init(); - cmap_str_emplace(&cmap_cfg_insert(&config, cstr_from("user"), init).ref->second, "name", "Joe"); - cmap_str_emplace(&cmap_cfg_insert(&config, cstr_from("user"), init).ref->second, "groups", "proj1,proj3"); - cmap_str_emplace(&cmap_cfg_insert(&config, cstr_from("group"), init).ref->second, "proj1", "Energy"); - cmap_str_emplace(&cmap_cfg_insert(&config, cstr_from("group"), init).ref->second, "proj2", "Windy"); - cmap_str_emplace(&cmap_cfg_insert(&config, cstr_from("group"), init).ref->second, "proj3", "Oil"); - cmap_str_emplace(&cmap_cfg_insert(&config, cstr_from("admin"), init).ref->second, "employees", "2302"); + cmap_str_emplace(&cmap_cfg_insert(&cfg, cstr_from("user"), init).ref->second, "name", "Joe"); + cmap_str_emplace(&cmap_cfg_insert(&cfg, cstr_from("user"), init).ref->second, "groups", "proj1,proj3"); + cmap_str_emplace(&cmap_cfg_insert(&cfg, cstr_from("group"), init).ref->second, "proj1", "Energy"); + cmap_str_emplace(&cmap_cfg_insert(&cfg, cstr_from("group"), init).ref->second, "proj2", "Windy"); + cmap_str_emplace(&cmap_cfg_insert(&cfg, cstr_from("group"), init).ref->second, "proj3", "Oil"); + cmap_str_emplace(&cmap_cfg_insert(&cfg, cstr_from("admin"), init).ref->second, "employees", "2302"); - cmap_str_emplace_or_assign(&cmap_cfg_insert(&config, cstr_from("group"), init).ref->second, "proj2", "Wind"); // Update + cmap_str_emplace_or_assign(&cmap_cfg_insert(&cfg, cstr_from("group"), init).ref->second, "proj2", "Wind"); // Update - c_foreach (i, cmap_cfg, config) + c_foreach (i, cmap_cfg, cfg) c_foreach (j, cmap_str, i.ref->second) printf("%s: %s - %s (%u)\n", i.ref->first.str, j.ref->first.str, j.ref->second.str, i.ref->second.bucket_count); - cmap_cfg_del(&config); + cmap_cfg_del(&cfg); } \ No newline at end of file diff --git a/examples/read.c b/examples/read.c new file mode 100644 index 00000000..b3ddcc00 --- /dev/null +++ b/examples/read.c @@ -0,0 +1,27 @@ +#include +#include +#include + +using_cvec_str(); + +cvec_str read_file(const char* name) { + cvec_str vec = cvec_str_init(); + c_withfile (f, fopen(name, "r")) { + cstr line = cstr_init(); + while (cstr_getline(&line, f)) + cvec_str_emplace_back(&vec, line.str); + cstr_del(&line); + } + return vec; +} + +int main() { + cvec_str vec = read_file("read.c"); + if (errno) printf("errno: %d\n", errno); + + int n = 0; + c_foreach (i, cvec_str, vec) + printf("%5d: %s\n", ++n, i.ref->str); + + cvec_str_del(&vec); +} \ No newline at end of file diff --git a/stc/cstr.h b/stc/cstr.h index b0267ae2..88fc71a4 100644 --- a/stc/cstr.h +++ b/stc/cstr.h @@ -116,6 +116,10 @@ STC_INLINE cstr_t* cstr_assign(cstr_t* self, const char* str) { return cstr_assign_n(self, str, strlen(str)); } +STC_INLINE cstr_t* +cstr_assign_s(cstr_t* self, cstr s) { + return cstr_assign_n(self, s.str, _cstr_rep(&s)->size); +} STC_INLINE cstr_t* cstr_take(cstr_t* self, cstr_t s) { @@ -135,6 +139,11 @@ STC_INLINE cstr_t* cstr_append(cstr_t* self, const char* str) { return cstr_append_n(self, str, strlen(str)); } +STC_INLINE cstr_t* +cstr_append_s(cstr_t* self, cstr s) { + return cstr_append_n(self, s.str, _cstr_rep(&s)->size); +} + STC_INLINE void cstr_push_back(cstr_t* self, char value) { cstr_append_n(self, &value, 1); @@ -152,10 +161,20 @@ STC_INLINE void cstr_insert(cstr_t* self, size_t pos, const char* str) { cstr_replace_n(self, pos, 0, str, strlen(str)); } +STC_INLINE void +cstr_insert_s(cstr_t* self, size_t pos, cstr s) { + cstr_replace_n(self, pos, 0, s.str, _cstr_rep(&s)->size); +} + STC_INLINE void cstr_replace(cstr_t* self, size_t pos, size_t len, const char* str) { cstr_replace_n(self, pos, len, str, strlen(str)); } +STC_INLINE void +cstr_replace_s(cstr_t* self, size_t pos, size_t len, cstr s) { + cstr_replace_n(self, pos, len, s.str, _cstr_rep(&s)->size); +} + STC_INLINE void cstr_erase(cstr_t* self, size_t pos) {cstr_erase_n(self, pos, 1);} -- cgit v1.2.3