summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authortylov <[email protected]>2023-07-26 21:23:15 +0200
committertylov <[email protected]>2023-07-26 21:23:15 +0200
commitd7fba27af452de2d709767e615fa2e90d6b3a391 (patch)
tree33f83221b34b8a123d25ddc886512d81bbdee706
parent5b54b0ca26540dd116880f316c6fa0291a7c96c7 (diff)
downloadSTC-modified-d7fba27af452de2d709767e615fa2e90d6b3a391.tar.gz
STC-modified-d7fba27af452de2d709767e615fa2e90d6b3a391.zip
Added cmap_emplace_key() / csmap_emplace_key()
More docs.
-rw-r--r--README.md29
-rw-r--r--docs/algorithm_api.md4
-rw-r--r--docs/cmap_api.md8
-rw-r--r--docs/csmap_api.md1
-rw-r--r--include/stc/algo/filter.h2
-rw-r--r--include/stc/cmap.h87
-rw-r--r--include/stc/csmap.h30
-rw-r--r--include/stc/forward.h1
-rw-r--r--misc/examples/smartpointers/arc_containers.c1
-rw-r--r--misc/tests/cspan_test.c4
10 files changed, 95 insertions, 72 deletions
diff --git a/README.md b/README.md
index 9b6698e5..d66a7f1c 100644
--- a/README.md
+++ b/README.md
@@ -619,23 +619,24 @@ STC is generally very memory efficient. Memory usage for the different container
# Version History
## Version 4.3
-- Some breaking changes.
-- **coroutines**: much improved with some new API and added features.
-- **cspan**: Rewritten to add support for **column-major** order (fortran) multidim spans and transposed views.
-- Removed default comparison for **clist**, **cvec** and **cdeq** (like cstack and cqueue).
- - Define `i_cmp_native` to enable built-in i_key types comparisons (<, ==).
- - Use of `i_keyclass` still expects comparison functions defined.
- - Use of `i_keyboxed` compares hosted pointers instead of pointed to values if comparisons not defined.
-- **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including.
+- Some breaking changes:
+ - **cstr** and **csview** now uses *shared linking* by default. Implement by either defining `i_implement` or `i_static` before including.
+ - Changes in `coroutine.h`: much improved with some new API and added features.
+ - Renamed stc/calgo.h => `<stc/algorithms.h>`
+ - Removed deprecated stc/crandom.h. Use `<stc/crand.h>` with the new API.
+ - Removed default comparison for **clist**, **cvec** and **cdeq**:
+ - Define `i_cmp_native` to enable comparison for built-in i_key types (<, ==).
+ - Use of `i_keyclass` still expects comparison functions to be defined.
+ - Use of `i_keyboxed` compares hosted pointers instead of pointed to values if comparisons not defined.
+ - Renamed input enum flags for ***cregex***-functions.
+- **cspan**: Changed representation of strides to add **column-major** order (fortran) multidimensional spans and transposed views.
- All new faster and smaller **cqueue** and **cdeq** implementations, using a circular buffer.
-- Renamed i_extern => `i_import`.
- - Define `i_import` before `#include <stc/cstr.h>` will also define utf8 case conversions.
+- Renamed i_extern => `i_import` (i_extern deprecated).
+ - Define `i_import` before `#include <stc/cstr.h>` will also define full utf8 case conversions.
- Define `i_import` before `#include <stc/cregex.h>` will also define cstr + utf8 tables.
-- Renamed c_make() => ***c_init()*** macro for initializing containers with element lists.
-- Renamed input enum flags for ***cregex***-functions.
-- Removed deprecated <stc/crandom.h>. Use `<stc/crand.h>` with the new API.
+- Renamed c_make() => ***c_init()*** macro for initializing containers with element lists. c_make deprecated.
- Removed deprecated uppercase flow-control macro names.
-- Improved default string hash function.
+- Other smaller additions, bug fixes and improved documentation.
## Version 4.2
- New home! And online single headers for https://godbolt.org
diff --git a/docs/algorithm_api.md b/docs/algorithm_api.md
index 490771b5..40ff32d6 100644
--- a/docs/algorithm_api.md
+++ b/docs/algorithm_api.md
@@ -130,7 +130,7 @@ Iterate a container or a crange with chained `&&` filtering.
[ [Run this example](https://godbolt.org/z/n9aYrYPv8) ]
```c
-#include <stc/calgo.h>
+#include <stc/algorithm.h>
#include <stdio.h>
bool isPrime(long long i) {
@@ -309,8 +309,6 @@ The **checkauto** utility described below, ensures that the `c_auto*` macros are
| `continue` | Exit a defer-block without resource leak |
```c
-#include <stc/algo/raii.h> // or <stc/calgo.h>
-...
// `c_defer` executes the expression(s) when leaving scope.
// Note: does not require inclusion of "raii.h".
cstr s1 = cstr_lit("Hello"), s2 = cstr_lit("world");
diff --git a/docs/cmap_api.md b/docs/cmap_api.md
index 17f27662..4e6da57d 100644
--- a/docs/cmap_api.md
+++ b/docs/cmap_api.md
@@ -71,7 +71,8 @@ cmap_X_result cmap_X_insert_or_assign(cmap_X* self, i_key key, i_val map
cmap_X_result cmap_X_push(cmap_X* self, cmap_X_value entry); // similar to insert
cmap_X_result cmap_X_emplace(cmap_X* self, i_keyraw rkey, i_valraw rmapped); // no change if rkey in map
-cmap_X_result cmap_X_emplace_or_assign(cmap_X* self, i_keyraw rkey, i_valraw rmapped); // always update
+cmap_X_result cmap_X_emplace_or_assign(cmap_X* self, i_keyraw rkey, i_valraw rmapped); // always update mapped
+cmap_X_result cmap_X_emplace_key(cmap_X* self, i_keyraw rkey); // see example 1.
int cmap_X_erase(cmap_X* self, i_keyraw rkey); // return 0 or 1
cmap_X_iter cmap_X_erase_at(cmap_X* self, cmap_X_iter it); // return iter after it
@@ -138,6 +139,11 @@ int main(void)
cmap_str_emplace(&umap, "BLACK", "#000000");
cmap_str_emplace(&umap, "WHITE", "#FFFFFF");
+ // Insert only if "CYAN" is not in the map: create mapped value when needed only.
+ cmap_str_result res = cmap_str_emplace_key(&umap, "CYAN");
+ if (res.inserted)
+ res.ref->second = cstr_from("#00FFFF"); // must assign second if key was inserted.
+
// Output values by key
printf("The HEX of color RED is:[%s]\n", cstr_str(cmap_str_at(&umap, "RED")));
printf("The HEX of color BLACK is:[%s]\n", cstr_str(cmap_str_at(&umap, "BLACK")));
diff --git a/docs/csmap_api.md b/docs/csmap_api.md
index 164b0f8a..d739283b 100644
--- a/docs/csmap_api.md
+++ b/docs/csmap_api.md
@@ -72,6 +72,7 @@ csmap_X_result csmap_X_push(csmap_X* self, csmap_X_value entry);
csmap_X_result csmap_X_emplace(csmap_X* self, i_keyraw rkey, i_valraw rmapped); // no change if rkey in map
csmap_X_result csmap_X_emplace_or_assign(csmap_X* self, i_keyraw rkey, i_valraw rmapped); // always update rmapped
+csmap_X_result csmap_X_emplace_key(csmap_X* self, i_keyraw rkey); // if key not in map, mapped is left unassigned
int csmap_X_erase(csmap_X* self, i_keyraw rkey);
csmap_X_iter csmap_X_erase_at(csmap_X* self, csmap_X_iter it); // returns iter after it
diff --git a/include/stc/algo/filter.h b/include/stc/algo/filter.h
index 1a62c3e1..320cd50d 100644
--- a/include/stc/algo/filter.h
+++ b/include/stc/algo/filter.h
@@ -24,7 +24,7 @@
#include <stdio.h>
#define i_val int
#include <stc/cstack.h>
-#include <stc/calgo.h>
+#include <stc/algorithm.h>
int main(void)
{
diff --git a/include/stc/cmap.h b/include/stc/cmap.h
index 513a8b93..2dd8cbe6 100644
--- a/include/stc/cmap.h
+++ b/include/stc/cmap.h
@@ -55,7 +55,6 @@ int main(void) {
#include <stdlib.h>
#include <string.h>
struct chash_slot { uint8_t hashx; };
-typedef struct { intptr_t idx; uint8_t hashx, found; } chash_bucket;
#endif // CMAP_H_INCLUDED
#ifndef _i_prefix
@@ -94,7 +93,7 @@ STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self map);
STC_API void _cx_MEMB(_drop)(_cx_Self* self);
STC_API void _cx_MEMB(_clear)(_cx_Self* self);
STC_API bool _cx_MEMB(_reserve)(_cx_Self* self, intptr_t capacity);
-STC_API chash_bucket _cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr);
+STC_API _cx_result _cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr);
STC_API _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey);
STC_API void _cx_MEMB(_erase_entry)(_cx_Self* self, _cx_value* val);
STC_API float _cx_MEMB(_max_load_factor)(const _cx_Self* self);
@@ -106,9 +105,9 @@ STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* map) { return !map->siz
STC_INLINE intptr_t _cx_MEMB(_size)(const _cx_Self* map) { return (intptr_t)map->size; }
STC_INLINE intptr_t _cx_MEMB(_bucket_count)(_cx_Self* map) { return map->bucket_count; }
STC_INLINE bool _cx_MEMB(_contains)(const _cx_Self* self, _cx_keyraw rkey)
- { return self->size && _cx_MEMB(_bucket_)(self, &rkey).found; }
+ { return self->size && !_cx_MEMB(_bucket_)(self, &rkey).inserted; }
-#ifndef _i_isset
+#ifdef _i_ismap
STC_API _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key key, i_val mapped);
#if !defined i_no_emplace
STC_API _cx_result _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped);
@@ -116,14 +115,15 @@ STC_INLINE bool _cx_MEMB(_contains)(const _cx_Self* self, _cx_keyraw rke
STC_INLINE const _cx_mapped*
_cx_MEMB(_at)(const _cx_Self* self, _cx_keyraw rkey) {
- chash_bucket b = _cx_MEMB(_bucket_)(self, &rkey);
- c_assert(b.found);
- return &self->data[b.idx].second;
+ _cx_result b = _cx_MEMB(_bucket_)(self, &rkey);
+ c_assert(!b.inserted);
+ return &b.ref->second;
}
+
STC_INLINE _cx_mapped*
_cx_MEMB(_at_mut)(_cx_Self* self, _cx_keyraw rkey)
{ return (_cx_mapped*)_cx_MEMB(_at)(self, rkey); }
-#endif // !_i_isset
+#endif // _i_ismap
#if !defined i_no_clone
STC_INLINE void _cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) {
@@ -151,6 +151,16 @@ _cx_MEMB(_emplace)(_cx_Self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmappe
}
return _res;
}
+
+#ifdef _i_ismap
+ STC_INLINE _cx_result
+ _cx_MEMB(_emplace_key)(_cx_Self* self, _cx_keyraw rkey) {
+ _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey);
+ if (_res.inserted)
+ _res.ref->first = i_keyfrom(rkey);
+ return _res;
+ }
+#endif // _i_ismap
#endif // !i_no_emplace
STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* val) {
@@ -215,19 +225,19 @@ STC_INLINE _cx_iter _cx_MEMB(_advance)(_cx_iter it, size_t n) {
STC_INLINE _cx_iter
_cx_MEMB(_find)(const _cx_Self* self, _cx_keyraw rkey) {
- chash_bucket b;
- if (self->size && (b = _cx_MEMB(_bucket_)(self, &rkey)).found)
- return c_LITERAL(_cx_iter){self->data + b.idx,
+ _cx_result b;
+ if (self->size && !(b = _cx_MEMB(_bucket_)(self, &rkey)).inserted)
+ return c_LITERAL(_cx_iter){b.ref,
self->data + self->bucket_count,
- self->slot + b.idx};
+ self->slot + (b.ref - self->data)};
return _cx_MEMB(_end)(self);
}
STC_INLINE const _cx_value*
_cx_MEMB(_get)(const _cx_Self* self, _cx_keyraw rkey) {
- chash_bucket b;
- if (self->size && (b = _cx_MEMB(_bucket_)(self, &rkey)).found)
- return self->data + b.idx;
+ _cx_result b;
+ if (self->size && !(b = _cx_MEMB(_bucket_)(self, &rkey)).inserted)
+ return b.ref;
return NULL;
}
@@ -237,10 +247,10 @@ _cx_MEMB(_get_mut)(_cx_Self* self, _cx_keyraw rkey)
STC_INLINE int
_cx_MEMB(_erase)(_cx_Self* self, _cx_keyraw rkey) {
- chash_bucket b = {0};
- if (self->size && (b = _cx_MEMB(_bucket_)(self, &rkey)).found)
- _cx_MEMB(_erase_entry)(self, self->data + b.idx);
- return b.found;
+ _cx_result b;
+ if (self->size && !(b = _cx_MEMB(_bucket_)(self, &rkey)).inserted)
+ { _cx_MEMB(_erase_entry)(self, b.ref); return 1; }
+ return 0;
}
STC_INLINE _cx_iter
@@ -313,7 +323,7 @@ STC_DEF void _cx_MEMB(_clear)(_cx_Self* self) {
c_memset(self->slot, 0, c_sizeof(chash_slot)*self->bucket_count);
}
-#ifndef _i_isset
+#ifdef _i_ismap
STC_DEF _cx_result
_cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key _key, i_val _mapped) {
_cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key)));
@@ -340,42 +350,41 @@ STC_DEF void _cx_MEMB(_clear)(_cx_Self* self) {
return _res;
}
#endif // !i_no_emplace
-#endif // !_i_isset
+#endif // _i_ismap
-STC_DEF chash_bucket
+STC_DEF _cx_result
_cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr) {
const uint64_t _hash = i_hash(rkeyptr);
intptr_t _cap = self->bucket_count;
- chash_bucket b = {fastrange_2(_hash, _cap), (uint8_t)(_hash | 0x80)};
+ intptr_t _idx = fastrange_2(_hash, _cap);
+ _cx_result b = {NULL, true, (uint8_t)(_hash | 0x80)};
const chash_slot* s = self->slot;
- while (s[b.idx].hashx) {
- if (s[b.idx].hashx == b.hashx) {
- const _cx_keyraw _raw = i_keyto(_i_keyref(self->data + b.idx));
+ while (s[_idx].hashx) {
+ if (s[_idx].hashx == b.hashx) {
+ const _cx_keyraw _raw = i_keyto(_i_keyref(self->data + _idx));
if (i_eq((&_raw), rkeyptr)) {
- b.found = true;
+ b.inserted = false;
break;
}
}
- if (++b.idx == _cap) b.idx = 0;
+ if (++_idx == _cap) _idx = 0;
}
+ b.ref = self->data + _idx;
return b;
}
STC_DEF _cx_result
_cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) {
- _cx_result res = {NULL};
if (self->size >= (intptr_t)((float)self->bucket_count * (i_max_load_factor)))
if (!_cx_MEMB(_reserve)(self, (intptr_t)(self->size*3/2 + 2)))
- return res;
+ return c_LITERAL(_cx_result){NULL};
- chash_bucket b = _cx_MEMB(_bucket_)(self, &rkey);
- res.ref = &self->data[b.idx];
- if (!b.found) {
- self->slot[b.idx].hashx = b.hashx;
- res.inserted = true;
+ _cx_result b = _cx_MEMB(_bucket_)(self, &rkey);
+ if (b.inserted) {
+ self->slot[b.ref - self->data].hashx = b.hashx;
++self->size;
}
- return res;
+ return b;
}
#if !defined i_no_clone
@@ -417,9 +426,9 @@ _cx_MEMB(_reserve)(_cx_Self* self, const intptr_t _newcap) {
const chash_slot* s = self->slot;
for (intptr_t i = 0; i < _oldbucks; ++i, ++d) if ((s++)->hashx) {
_cx_keyraw r = i_keyto(_i_keyref(d));
- chash_bucket b = _cx_MEMB(_bucket_)(&m, &r);
- m.slot[b.idx].hashx = b.hashx;
- m.data[b.idx] = *d; // move
+ _cx_result b = _cx_MEMB(_bucket_)(&m, &r);
+ m.slot[b.ref - m.data].hashx = b.hashx;
+ *b.ref = *d; // move
}
c_swap(_cx_Self, self, &m);
}
diff --git a/include/stc/csmap.h b/include/stc/csmap.h
index f4d33a4d..d2e1d1fc 100644
--- a/include/stc/csmap.h
+++ b/include/stc/csmap.h
@@ -170,19 +170,29 @@ _cx_MEMB(_shrink_to_fit)(_cx_Self *self) {
}
#endif // !i_no_clone
-#ifndef _i_isset
+STC_API _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey);
+
+#ifdef _i_ismap
STC_API _cx_result _cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key key, i_val mapped);
#if !defined i_no_emplace
STC_API _cx_result _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped);
- #endif
+ STC_INLINE _cx_result
+ _cx_MEMB(_emplace_key)(_cx_Self* self, _cx_keyraw rkey) {
+ _cx_result res = _cx_MEMB(_insert_entry_)(self, rkey);
+ if (res.inserted)
+ res.ref->first = i_keyfrom(rkey);
+ return res;
+ }
+ #endif
STC_INLINE const _cx_mapped*
_cx_MEMB(_at)(const _cx_Self* self, _cx_keyraw rkey)
{ _cx_iter it; return &_cx_MEMB(_find_it)(self, rkey, &it)->second; }
+
STC_INLINE _cx_mapped*
_cx_MEMB(_at_mut)(_cx_Self* self, _cx_keyraw rkey)
{ _cx_iter it; return &_cx_MEMB(_find_it)(self, rkey, &it)->second; }
-#endif // !_i_isset
+#endif // _i_ismap
STC_INLINE _cx_iter
_cx_MEMB(_end)(const _cx_Self* self) {
@@ -209,8 +219,6 @@ _cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) {
return true;
}
-static _cx_result _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey);
-
STC_INLINE _cx_result
_cx_MEMB(_insert)(_cx_Self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) {
_cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key)));
@@ -326,7 +334,7 @@ _cx_MEMB(_new_node_)(_cx_Self* self, int level) {
return tn;
}
-#ifndef _i_isset
+#ifdef _i_ismap
STC_DEF _cx_result
_cx_MEMB(_insert_or_assign)(_cx_Self* self, i_key _key, i_val _mapped) {
_cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto((&_key)));
@@ -353,7 +361,7 @@ _cx_MEMB(_new_node_)(_cx_Self* self, int level) {
return _res;
}
#endif // !i_no_emplace
-#endif // !_i_isset
+#endif // !_i_ismap
STC_DEF _cx_value*
_cx_MEMB(_find_it)(const _cx_Self* self, _cx_keyraw rkey, _cx_iter* out) {
@@ -407,7 +415,7 @@ _cx_MEMB(_split_)(_cx_node *d, int32_t tn) {
return tn;
}
-static int32_t
+STC_DEF int32_t
_cx_MEMB(_insert_entry_i_)(_cx_Self* self, int32_t tn, const _cx_keyraw* rkey, _cx_result* _res) {
int32_t up[64], tx = tn;
_cx_node* d = self->nodes;
@@ -439,7 +447,7 @@ _cx_MEMB(_insert_entry_i_)(_cx_Self* self, int32_t tn, const _cx_keyraw* rkey, _
return up[0];
}
-static _cx_result
+STC_DEF _cx_result
_cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) {
_cx_result res = {NULL};
int32_t tn = _cx_MEMB(_insert_entry_i_)(self, self->root, &rkey, &res);
@@ -448,7 +456,7 @@ _cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) {
return res;
}
-static int32_t
+STC_DEF int32_t
_cx_MEMB(_erase_r_)(_cx_Self *self, int32_t tn, const _cx_keyraw* rkey, int *erased) {
_cx_node *d = self->nodes;
if (tn == 0)
@@ -533,7 +541,7 @@ _cx_MEMB(_erase_range)(_cx_Self* self, _cx_iter it1, _cx_iter it2) {
}
#if !defined i_no_clone
-static int32_t
+STC_DEF int32_t
_cx_MEMB(_clone_r_)(_cx_Self* self, _cx_node* src, int32_t sn) {
if (sn == 0)
return 0;
diff --git a/include/stc/forward.h b/include/stc/forward.h
index 484a8b63..085205cf 100644
--- a/include/stc/forward.h
+++ b/include/stc/forward.h
@@ -120,6 +120,7 @@ typedef struct chash_slot chash_slot;
typedef struct { \
SELF##_value *ref; \
bool inserted; \
+ uint8_t hashx; \
} SELF##_result; \
\
typedef struct { \
diff --git a/misc/examples/smartpointers/arc_containers.c b/misc/examples/smartpointers/arc_containers.c
index 2fb04c56..6209005d 100644
--- a/misc/examples/smartpointers/arc_containers.c
+++ b/misc/examples/smartpointers/arc_containers.c
@@ -2,7 +2,6 @@
// and demonstrate sharing and cloning of maps.
#define i_implement
#include <stc/cstr.h>
-#include <stc/algo/raii.h>
#define i_type Map
#define i_key_str // strings
#define i_val int
diff --git a/misc/tests/cspan_test.c b/misc/tests/cspan_test.c
index d7ca9b64..ce267b14 100644
--- a/misc/tests/cspan_test.c
+++ b/misc/tests/cspan_test.c
@@ -1,6 +1,5 @@
#include <stdio.h>
#include <stc/cspan.h>
-#include <stc/algo/raii.h>
#include "ctest.h"
using_cspan3(intspan, int);
@@ -48,7 +47,8 @@ CTEST(cspan, slice) {
#include <stc/cstack.h>
CTEST(cspan, slice2) {
- c_auto (cstack_int, stack)
+ cstack_int stack = {0};
+ c_defer (cstack_int_drop(&stack))
{
c_forrange (i, 10*20*30)
cstack_int_push(&stack, i);