diff options
| -rw-r--r-- | README.md | 6 | ||||
| -rw-r--r-- | docs/cmap_api.md | 14 | ||||
| -rw-r--r-- | docs/cset_api.md | 10 | ||||
| -rw-r--r-- | docs/csmap_api.md | 12 | ||||
| -rw-r--r-- | docs/csset_api.md | 8 | ||||
| -rw-r--r-- | include/stc/cmap.h | 22 | ||||
| -rw-r--r-- | include/stc/csmap.h | 64 | ||||
| -rw-r--r-- | include/stc/forward.h | 10 | ||||
| -rw-r--r-- | include/stc/priv/template.h | 6 | ||||
| -rw-r--r-- | misc/benchmarks/external/ankerl/robin_hood.h | 2 | ||||
| -rw-r--r-- | misc/benchmarks/external/ankerl/unordered_dense.h | 87 | ||||
| -rw-r--r-- | misc/benchmarks/external/emhash/hash_table7.hpp | 27 | ||||
| -rw-r--r-- | misc/benchmarks/shootout_hashmaps.cpp | 1 |
13 files changed, 172 insertions, 97 deletions
@@ -320,8 +320,10 @@ You may also cherry-pick shared linking mode on individual containers by `#defin `#define i_implement`, or force static symbols by `#define i_static` before container includes. As a special case, there may be non-templated functions in templated containers that should be implemented only -once if needed. Currently, for **clist**, define `i_extern` before including `clist.h` for sorting functionality -(global `STC_EXTERN` may alternatively be defined). +once and if needed. Currently, define `i_extern` before including **clist** for its sorting function, and before +**cregex** or **utf8** to implement them (global `STC_EXTERN` can alternatively be defined). + +It is possible to generate single headers by executing the python script in src/singleheader.py <header>. Conveniently, `src\libstc.c` implements non-templated functions as shared symbols for **cstr**, **csview**, **cbits** and **crandom**. When building in shared mode (-DSTC_HEADER), you may include this file in your project, diff --git a/docs/cmap_api.md b/docs/cmap_api.md index 2c6274ae..76fbda92 100644 --- a/docs/cmap_api.md +++ b/docs/cmap_api.md @@ -38,7 +38,7 @@ See the c++ class [std::unordered_map](https://en.cppreference.com/w/cpp/contain #define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val #define i_hash_functor // advanced, see examples/functor.c for similar usage. #define i_eq_functor // advanced, see examples/functor.c for similar usage. -#define i_size // define cmap_X_sizet. default int32_t. If defined, table expand 2x (else 1.5x) +#define i_ssize // default int32_t. If defined, table expand 2x (else 1.5x) #include <stc/cmap.h> ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. @@ -47,20 +47,20 @@ See the c++ class [std::unordered_map](https://en.cppreference.com/w/cpp/contain ```c cmap_X cmap_X_init(void); -cmap_X cmap_X_with_capacity(cmap_X_sizet cap); +cmap_X cmap_X_with_capacity(i_ssize cap); cmap_X cmap_X_clone(cmap_x map); void cmap_X_clear(cmap_X* self); void cmap_X_copy(cmap_X* self, const cmap_X* other); float cmap_X_max_load_factor(const cmap_X* self); // default: 0.85f -bool cmap_X_reserve(cmap_X* self, cmap_X_sizet size); +bool cmap_X_reserve(cmap_X* self, i_ssize size); void cmap_X_shrink_to_fit(cmap_X* self); void cmap_X_drop(cmap_X* self); // destructor bool cmap_X_empty(const cmap_X* self ); -cmap_X_sizet cmap_X_size(const cmap_X* self); -cmap_X_sizet cmap_X_capacity(const cmap_X* self); // buckets * max_load_factor -cmap_X_sizet cmap_X_bucket_count(const cmap_X* self); // num. of allocated buckets +i_ssize cmap_X_size(const cmap_X* self); +i_ssize cmap_X_capacity(const cmap_X* self); // buckets * max_load_factor +i_ssize cmap_X_bucket_count(const cmap_X* self); // num. of allocated buckets const cmap_X_mapped* cmap_X_at(const cmap_X* self, i_keyraw rkey); // rkey must be in map cmap_X_mapped* cmap_X_at_mut(cmap_X* self, i_keyraw rkey); // mutable at @@ -83,7 +83,7 @@ void cmap_X_erase_entry(cmap_X* self, cmap_X_value* entry); cmap_X_iter cmap_X_begin(const cmap_X* self); cmap_X_iter cmap_X_end(const cmap_X* self); void cmap_X_next(cmap_X_iter* it); -cmap_X_iter cmap_X_advance(cmap_X_iter it, cmap_X_sizet n); +cmap_X_iter cmap_X_advance(cmap_X_iter it, cmap_X_ssize n); cmap_X_value cmap_X_value_clone(cmap_X_value val); cmap_X_raw cmap_X_value_toraw(cmap_X_value* pval); diff --git a/docs/cset_api.md b/docs/cset_api.md index 27e633b4..34b6f3eb 100644 --- a/docs/cset_api.md +++ b/docs/cset_api.md @@ -21,7 +21,7 @@ A **cset** is an associative container that contains a set of unique objects of #define i_tag // alternative typename: cmap_{i_tag}. i_tag defaults to i_val #define i_hash_functor // advanced, see examples/functor.c for similar usage. #define i_eq_functor // advanced, see examples/functor.c for similar usage. -#define i_size // defines cset_X_sizet. default int32_t. If defined, table expand 2x (else 1.5x) +#define i_ssize // default int32_t. If defined, table expand 2x (else 1.5x) #include <stc/cset.h> ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. @@ -36,14 +36,14 @@ cset_X cset_X_clone(cset_x set); void cset_X_clear(cset_X* self); void cset_X_copy(cset_X* self, const cset_X* other); float cset_X_max_load_factor(const cset_X* self); // default: 0.85 -bool cset_X_reserve(cset_X* self, cset_X_sizet size); +bool cset_X_reserve(cset_X* self, i_ssize size); void cset_X_shrink_to_fit(cset_X* self); void cset_X_drop(cset_X* self); // destructor -cset_X_sizet cset_X_size(const cset_X* self); // num. of allocated buckets -cset_X_sizet cset_X_capacity(const cset_X* self); // buckets * max_load_factor +i_ssize cset_X_size(const cset_X* self); // num. of allocated buckets +i_ssize cset_X_capacity(const cset_X* self); // buckets * max_load_factor bool cset_X_empty(const cset_X* self); -cset_X_sizet cset_X_bucket_count(const cset_X* self); +i_ssize cset_X_bucket_count(const cset_X* self); bool cset_X_contains(const cset_X* self, i_keyraw rkey); const cset_X_value* cset_X_get(const cset_X* self, i_keyraw rkey); // return NULL if not found diff --git a/docs/csmap_api.md b/docs/csmap_api.md index 59185081..19a654d6 100644 --- a/docs/csmap_api.md +++ b/docs/csmap_api.md @@ -34,7 +34,7 @@ See the c++ class [std::map](https://en.cppreference.com/w/cpp/container/map) fo #define i_tag // alternative typename: csmap_{i_tag}. i_tag defaults to i_val #define i_cmp_functor // advanced, see examples/functor.c for similar usage. -#define i_size // defines csmap_X_sizet type; defaults to int32_t +#define i_ssize // defaults to int32_t #include <stc/csmap.h> ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. @@ -43,8 +43,8 @@ See the c++ class [std::map](https://en.cppreference.com/w/cpp/container/map) fo ```c csmap_X csmap_X_init(void); -csset_X csmap_X_with_capacity(csmap_X_sizet cap); -bool csmap_X_reserve(csmap_X* self, csmap_X_sizet cap); +csset_X csmap_X_with_capacity(i_ssize cap); +bool csmap_X_reserve(csmap_X* self, i_ssize cap); void csmap_X_shrink_to_fit(csmap_X* self); csmap_X csmap_X_clone(csmap_x map); @@ -53,8 +53,8 @@ void csmap_X_copy(csmap_X* self, const csmap_X* other); void csmap_X_drop(csmap_X* self); // destructor bool csmap_X_empty(const csmap_X* self); -csmap_X_sizet csmap_X_size(const csmap_X* self); -csmap_X_sizet csmap_X_capacity(const csmap_X* self); +i_ssize csmap_X_size(const csmap_X* self); +i_ssize csmap_X_capacity(const csmap_X* self); const csmap_X_mapped* csmap_X_at(const csmap_X* self, i_keyraw rkey); // rkey must be in map csmap_X_mapped* csmap_X_at_mut(csmap_X* self, i_keyraw rkey); // mutable at @@ -82,7 +82,7 @@ csmap_X_iter csmap_X_erase_range(csmap_X* self, csmap_X_iter it1, csmap csmap_X_iter csmap_X_begin(const csmap_X* self); csmap_X_iter csmap_X_end(const csmap_X* self); void csmap_X_next(csmap_X_iter* iter); -csmap_X_iter csmap_X_advance(csmap_X_iter it, csmap_X_sizet n); +csmap_X_iter csmap_X_advance(csmap_X_iter it, i_ssize n); csmap_X_value csmap_X_value_clone(csmap_X_value val); csmap_X_raw csmap_X_value_toraw(csmap_X_value* pval); diff --git a/docs/csset_api.md b/docs/csset_api.md index 4618bd18..c696eab5 100644 --- a/docs/csset_api.md +++ b/docs/csset_api.md @@ -20,7 +20,7 @@ See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) fo #define i_cmp_functor // advanced, see examples/functor.c for similar usage. #define i_tag // alternative typename: csset_{i_tag}. i_tag defaults to i_val -#define i_size // defines csset_X_sizet type; defaults to int32_t +#define i_ssize // defaults to int32_t #include <stc/csset.h> ``` `X` should be replaced by the value of `i_tag` in all of the following documentation. @@ -29,8 +29,8 @@ See the c++ class [std::set](https://en.cppreference.com/w/cpp/container/set) fo ```c csset_X csset_X_init(void); -csset_X csset_X_with_capacity(csset_X_sizet cap); -bool csset_X_reserve(csset_X* self, csset_X_sizet cap); +csset_X csset_X_with_capacity(i_ssize cap); +bool csset_X_reserve(csset_X* self, i_ssize cap); void csset_X_shrink_to_fit(csset_X* self); csset_X csset_X_clone(csset_x set); @@ -38,7 +38,7 @@ void csset_X_clear(csset_X* self); void csset_X_copy(csset_X* self, const csset_X* other); void csset_X_drop(csset_X* self); // destructor -csset_X_sizet csset_X_size(const csset_X* self); +i_ssize csset_X_size(const csset_X* self); bool csset_X_empty(const csset_X* self); const csset_X_value* csset_X_get(const csset_X* self, i_keyraw rkey); // const get diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 0553823b..799df1ec 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -73,8 +73,8 @@ typedef struct { int64_t idx; uint8_t hx; } chash_bucket_t; #ifndef i_max_load_factor #define i_max_load_factor 0.85f #endif -#ifndef i_size - #define i_size int32_t +#ifndef i_ssize + #define i_ssize int32_t #define _i_expandby 1 #else #define _i_expandby 2 @@ -87,7 +87,7 @@ typedef struct { int64_t idx; uint8_t hx; } chash_bucket_t; #define i_eq_functor(self, x, y) i_eq(x, y) #endif #if !c_option(c_is_forward) - _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, i_size, _i_MAP_ONLY, _i_SET_ONLY); + _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY); #endif _i_MAP_ONLY( struct _cx_value { @@ -378,7 +378,7 @@ _cx_memb(_bucket_)(const _cx_self* self, const _cx_rawkey* rkeyptr) { STC_DEF _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey) { _cx_result res = {NULL}; - if (self->size + 2 > (i_size)((float)self->bucket_count * (i_max_load_factor))) + if (self->size + 2 > (i_ssize)((float)self->bucket_count * (i_max_load_factor))) if (!_cx_memb(_reserve)(self, self->size*3/2)) return res; @@ -412,12 +412,12 @@ _cx_memb(_clone)(_cx_self m) { STC_DEF bool _cx_memb(_reserve)(_cx_self* self, const int64_t newcap) { - const i_size _oldbuckets = self->bucket_count, _newcap = (i_size)newcap; + const i_ssize _oldbuckets = self->bucket_count, _newcap = (i_ssize)newcap; if (_newcap != self->size && _newcap <= _oldbuckets) return true; - i_size _nbuckets = (i_size)((float)_newcap / (i_max_load_factor)) + 4; + i_ssize _nbuckets = (i_ssize)((float)_newcap / (i_max_load_factor)) + 4; #if _i_expandby == 2 - _nbuckets = (i_size)next_power_of_2(_nbuckets); + _nbuckets = (i_ssize)next_power_of_2(_nbuckets); #else _nbuckets |= 1; #endif @@ -431,7 +431,7 @@ _cx_memb(_reserve)(_cx_self* self, const int64_t newcap) { m._hashx[_nbuckets] = 0xff; const _cx_value* e = self->table; const uint8_t* h = self->_hashx; - for (i_size i = 0; i < _oldbuckets; ++i, ++e) if (*h++) { + for (i_ssize i = 0; i < _oldbuckets; ++i, ++e) if (*h++) { _cx_rawkey r = i_keyto(_i_keyref(e)); chash_bucket_t b = _cx_memb(_bucket_)(&m, &r); m.table[b.idx] = *e; @@ -446,8 +446,8 @@ _cx_memb(_reserve)(_cx_self* self, const int64_t newcap) { STC_DEF void _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { - i_size i = (i_size)(_val - self->table), j = i, k; - const i_size _cap = self->bucket_count; + i_ssize i = (i_ssize)(_val - self->table), j = i, k; + const i_ssize _cap = self->bucket_count; _cx_value* _slot = self->table; uint8_t* _hashx = self->_hashx; _cx_memb(_value_drop)(_val); @@ -457,7 +457,7 @@ _cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { if (! _hashx[j]) break; const _cx_rawkey _raw = i_keyto(_i_keyref(_slot + j)); - k = (i_size)c_PASTE(fastrange_,_i_expandby)(i_hash_functor(self, (&_raw)), (uint64_t)_cap); + k = (i_ssize)c_PASTE(fastrange_,_i_expandby)(i_hash_functor(self, (&_raw)), (uint64_t)_cap); if ((j < i) ^ (k <= i) ^ (k > j)) /* is k outside (i, j]? */ _slot[i] = _slot[j], _hashx[i] = _hashx[j], i = j; } diff --git a/include/stc/csmap.h b/include/stc/csmap.h index 6a359fbb..4344ceb9 100644 --- a/include/stc/csmap.h +++ b/include/stc/csmap.h @@ -73,15 +73,15 @@ int main(void) { #define _i_SET_ONLY c_false #define _i_keyref(vp) (&(vp)->first) #endif -#ifndef i_size - #define i_size int32_t +#ifndef i_ssize + #define i_ssize int32_t #endif #include "priv/template.h" #ifndef i_cmp_functor #define i_cmp_functor(self, x, y) i_cmp(x, y) #endif #if !c_option(c_is_forward) - _cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_size, _i_MAP_ONLY, _i_SET_ONLY); + _cx_deftypes(_c_aatree_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY); #endif _i_MAP_ONLY( struct _cx_value { @@ -89,7 +89,7 @@ _i_MAP_ONLY( struct _cx_value { _cx_mapped second; }; ) struct _cx_node { - i_size link[2]; + i_ssize link[2]; int8_t level; _cx_value value; }; @@ -229,21 +229,21 @@ _cx_memb(_init)(void) { STC_DEF bool _cx_memb(_reserve)(_cx_self* self, const int64_t cap) { - if ((i_size)cap <= self->cap) + if ((i_ssize)cap <= self->cap) return false; _cx_node* nodes = (_cx_node*)i_realloc(self->nodes, (cap + 1)*c_sizeof(_cx_node)); if (!nodes) return false; nodes[0] = c_LITERAL(_cx_node){{0, 0}, 0}; self->nodes = nodes; - self->cap = (i_size)cap; + self->cap = (i_ssize)cap; return true; } STC_DEF _cx_value* _cx_memb(_front)(const _cx_self* self) { _cx_node *d = self->nodes; - i_size tn = self->root; + i_ssize tn = self->root; while (d[tn].link[0]) tn = d[tn].link[0]; return &d[tn].value; @@ -252,15 +252,15 @@ _cx_memb(_front)(const _cx_self* self) { STC_DEF _cx_value* _cx_memb(_back)(const _cx_self* self) { _cx_node *d = self->nodes; - i_size tn = self->root; + i_ssize tn = self->root; while (d[tn].link[1]) tn = d[tn].link[1]; return &d[tn].value; } -static i_size +static i_ssize _cx_memb(_new_node_)(_cx_self* self, int level) { - i_size tn; + i_ssize tn; if (self->disp) { tn = self->disp; self->disp = self->nodes[tn].link[1]; @@ -344,7 +344,7 @@ STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, int64_t n) STC_DEF _cx_value* _cx_memb(_find_it)(const _cx_self* self, _cx_rawkey rkey, _cx_iter* out) { - i_size tn = self->root; + i_ssize tn = self->root; _cx_node *d = out->_d = self->nodes; out->_top = 0; while (tn) { @@ -364,7 +364,7 @@ _cx_memb(_lower_bound)(const _cx_self* self, _cx_rawkey rkey) { _cx_iter it; _cx_memb(_find_it)(self, rkey, &it); if (!it.ref && it._top) { - i_size tn = it._st[--it._top]; + i_ssize tn = it._st[--it._top]; it._tn = it._d[tn].link[1]; it.ref = &it._d[tn].value; } @@ -373,7 +373,7 @@ _cx_memb(_lower_bound)(const _cx_self* self, _cx_rawkey rkey) { STC_DEF void _cx_memb(_next)(_cx_iter *it) { - i_size tn = it->_tn; + i_ssize tn = it->_tn; if (it->_top || tn) { while (tn) { it->_st[it->_top++] = tn; @@ -386,10 +386,10 @@ _cx_memb(_next)(_cx_iter *it) { it->ref = NULL; } -STC_DEF i_size -_cx_memb(_skew_)(_cx_node *d, i_size tn) { +STC_DEF i_ssize +_cx_memb(_skew_)(_cx_node *d, i_ssize tn) { if (tn && d[d[tn].link[0]].level == d[tn].level) { - i_size tmp = d[tn].link[0]; + i_ssize tmp = d[tn].link[0]; d[tn].link[0] = d[tmp].link[1]; d[tmp].link[1] = tn; tn = tmp; @@ -397,10 +397,10 @@ _cx_memb(_skew_)(_cx_node *d, i_size tn) { return tn; } -STC_DEF i_size -_cx_memb(_split_)(_cx_node *d, i_size tn) { +STC_DEF i_ssize +_cx_memb(_split_)(_cx_node *d, i_ssize tn) { if (d[d[d[tn].link[1]].link[1]].level == d[tn].level) { - i_size tmp = d[tn].link[1]; + i_ssize tmp = d[tn].link[1]; d[tn].link[1] = d[tmp].link[0]; d[tmp].link[0] = tn; tn = tmp; @@ -409,9 +409,9 @@ _cx_memb(_split_)(_cx_node *d, i_size tn) { return tn; } -static i_size -_cx_memb(_insert_entry_i_)(_cx_self* self, i_size tn, const _cx_rawkey* rkey, _cx_result* _res) { - i_size up[64], tx = tn; +static i_ssize +_cx_memb(_insert_entry_i_)(_cx_self* self, i_ssize tn, const _cx_rawkey* rkey, _cx_result* _res) { + i_ssize up[64], tx = tn; _cx_node* d = self->nodes; int c, top = 0, dir = 0; while (tx) { @@ -444,19 +444,19 @@ _cx_memb(_insert_entry_i_)(_cx_self* self, i_size tn, const _cx_rawkey* rkey, _c static _cx_result _cx_memb(_insert_entry_)(_cx_self* self, _cx_rawkey rkey) { _cx_result res = {NULL}; - i_size tn = _cx_memb(_insert_entry_i_)(self, self->root, &rkey, &res); + i_ssize tn = _cx_memb(_insert_entry_i_)(self, self->root, &rkey, &res); self->root = tn; self->size += res.inserted; return res; } -static i_size -_cx_memb(_erase_r_)(_cx_self *self, i_size tn, const _cx_rawkey* rkey, int *erased) { +static i_ssize +_cx_memb(_erase_r_)(_cx_self *self, i_ssize tn, const _cx_rawkey* rkey, int *erased) { _cx_node *d = self->nodes; if (tn == 0) return 0; _cx_rawkey raw = i_keyto(_i_keyref(&d[tn].value)); - i_size tx; int c = i_cmp_functor(self, (&raw), rkey); + i_ssize tx; int c = i_cmp_functor(self, (&raw), rkey); if (c != 0) d[tn].link[c < 0] = _cx_memb(_erase_r_)(self, d[tn].link[c < 0], rkey, erased); else { @@ -493,7 +493,7 @@ _cx_memb(_erase_r_)(_cx_self *self, i_size tn, const _cx_rawkey* rkey, int *eras STC_DEF int _cx_memb(_erase)(_cx_self* self, _cx_rawkey rkey) { int erased = 0; - i_size root = _cx_memb(_erase_r_)(self, self->root, &rkey, &erased); + i_ssize root = _cx_memb(_erase_r_)(self, self->root, &rkey, &erased); if (!erased) return 0; self->root = root; @@ -535,11 +535,11 @@ _cx_memb(_erase_range)(_cx_self* self, _cx_iter it1, _cx_iter it2) { } #if !defined i_no_clone -static i_size -_cx_memb(_clone_r_)(_cx_self* self, _cx_node* src, i_size sn) { +static i_ssize +_cx_memb(_clone_r_)(_cx_self* self, _cx_node* src, i_ssize sn) { if (sn == 0) return 0; - i_size tx, tn = _cx_memb(_new_node_)(self, src[sn].level); + i_ssize tx, tn = _cx_memb(_new_node_)(self, src[sn].level); self->nodes[tn].value = _cx_memb(_value_clone)(src[sn].value); tx = _cx_memb(_clone_r_)(self, src, src[sn].link[0]); self->nodes[tn].link[0] = tx; tx = _cx_memb(_clone_r_)(self, src, src[sn].link[1]); self->nodes[tn].link[1] = tx; @@ -549,7 +549,7 @@ _cx_memb(_clone_r_)(_cx_self* self, _cx_node* src, i_size sn) { STC_DEF _cx_self _cx_memb(_clone)(_cx_self tree) { _cx_self clone = _cx_memb(_with_capacity)(tree.size); - i_size root = _cx_memb(_clone_r_)(&clone, tree.nodes, tree.root); + i_ssize root = _cx_memb(_clone_r_)(&clone, tree.nodes, tree.root); clone.root = root; clone.size = tree.size; return clone; @@ -569,7 +569,7 @@ _cx_memb(_emplace)(_cx_self* self, _cx_rawkey rkey _i_MAP_ONLY(, i_valraw rmappe #endif // i_no_emplace static void -_cx_memb(_drop_r_)(_cx_node* d, i_size tn) { +_cx_memb(_drop_r_)(_cx_node* d, i_ssize tn) { if (tn) { _cx_memb(_drop_r_)(d, d[tn].link[0]); _cx_memb(_drop_r_)(d, d[tn].link[1]); diff --git a/include/stc/forward.h b/include/stc/forward.h index 64d4370a..00c531fe 100644 --- a/include/stc/forward.h +++ b/include/stc/forward.h @@ -106,7 +106,7 @@ typedef union { #define _c_chash_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \ typedef KEY SELF##_key; \ typedef VAL SELF##_mapped; \ - typedef SZ SELF##_sizet; \ + typedef SZ SELF##_ssize; \ \ typedef SET_ONLY( SELF##_key ) \ MAP_ONLY( struct SELF##_value ) \ @@ -125,13 +125,13 @@ typedef union { typedef struct SELF { \ SELF##_value* table; \ uint8_t* _hashx; \ - SELF##_sizet size, bucket_count; \ + SELF##_ssize size, bucket_count; \ } SELF #define _c_aatree_types(SELF, KEY, VAL, SZ, MAP_ONLY, SET_ONLY) \ typedef KEY SELF##_key; \ typedef VAL SELF##_mapped; \ - typedef SZ SELF##_sizet; \ + typedef SZ SELF##_ssize; \ typedef struct SELF##_node SELF##_node; \ \ typedef SET_ONLY( SELF##_key ) \ @@ -147,12 +147,12 @@ typedef union { SELF##_value *ref; \ SELF##_node *_d; \ int _top; \ - SELF##_sizet _tn, _st[36]; \ + SELF##_ssize _tn, _st[36]; \ } SELF##_iter; \ \ typedef struct SELF { \ SELF##_node *nodes; \ - SELF##_sizet root, disp, head, size, cap; \ + SELF##_ssize root, disp, head, size, cap; \ } SELF #define _c_cstack_fixed(SELF, VAL, CAP) \ diff --git a/include/stc/priv/template.h b/include/stc/priv/template.h index dd770839..3bef2c9a 100644 --- a/include/stc/priv/template.h +++ b/include/stc/priv/template.h @@ -44,8 +44,8 @@ #define _i_prefix #endif -#ifndef i_size - #define i_size intptr_t +#ifndef i_ssize + #define i_ssize intptr_t #endif #ifndef i_allocator @@ -298,7 +298,7 @@ #undef i_hash #undef i_rawclass #undef i_capacity -#undef i_size +#undef i_ssize #undef i_val #undef i_val_str diff --git a/misc/benchmarks/external/ankerl/robin_hood.h b/misc/benchmarks/external/ankerl/robin_hood.h index 0af031f5..b4e0fbc5 100644 --- a/misc/benchmarks/external/ankerl/robin_hood.h +++ b/misc/benchmarks/external/ankerl/robin_hood.h @@ -206,7 +206,7 @@ static Counts& counts() { // workaround missing "is_trivially_copyable" in g++ < 5.0 // See https://stackoverflow.com/a/31798726/48181 -#if defined(__GNUC__) && __GNUC__ < 5 +#if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__) # define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) __has_trivial_copy(__VA_ARGS__) #else # define ROBIN_HOOD_IS_TRIVIALLY_COPYABLE(...) std::is_trivially_copyable<__VA_ARGS__>::value diff --git a/misc/benchmarks/external/ankerl/unordered_dense.h b/misc/benchmarks/external/ankerl/unordered_dense.h index 05c7e928..faad051d 100644 --- a/misc/benchmarks/external/ankerl/unordered_dense.h +++ b/misc/benchmarks/external/ankerl/unordered_dense.h @@ -1,12 +1,12 @@ ///////////////////////// ankerl::unordered_dense::{map, set} ///////////////////////// // A fast & densely stored hashmap and hashset based on robin-hood backward shift deletion. -// Version 3.0.0 +// Version 3.1.0 // https://github.com/martinus/unordered_dense // // Licensed under the MIT License <http://opensource.org/licenses/MIT>. // SPDX-License-Identifier: MIT -// Copyright (c) 2022 Martin Leitner-Ankerl <[email protected]> +// Copyright (c) 2022-2023 Martin Leitner-Ankerl <[email protected]> // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -31,7 +31,7 @@ // see https://semver.org/spec/v2.0.0.html #define ANKERL_UNORDERED_DENSE_VERSION_MAJOR 3 // NOLINT(cppcoreguidelines-macro-usage) incompatible API changes -#define ANKERL_UNORDERED_DENSE_VERSION_MINOR 0 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible functionality +#define ANKERL_UNORDERED_DENSE_VERSION_MINOR 1 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible functionality #define ANKERL_UNORDERED_DENSE_VERSION_PATCH 0 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible bug fixes // API versioning with inline namespace, see https://www.foonathan.net/2018/11/inline-namespaces/ @@ -55,6 +55,18 @@ # define ANKERL_UNORDERED_DENSE_PACK(decl) __pragma(pack(push, 1)) decl __pragma(pack(pop)) #endif +// exceptions +#if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND) +# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 1 +#else +# define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 0 +#endif +#ifdef _MSC_VER +# define ANKERL_UNORDERED_DENSE_NOINLINE __declspec(noinline) +#else +# define ANKERL_UNORDERED_DENSE_NOINLINE __attribute__((noinline)) +#endif + #if ANKERL_UNORDERED_DENSE_CPP_VERSION < 201703L # error ankerl::unordered_dense requires C++17 or higher #else @@ -73,13 +85,24 @@ # include <type_traits> // for enable_if_t, declval, conditional_t, ena... # include <utility> // for forward, exchange, pair, as_const, piece... # include <vector> // for vector +# if ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() == 0 +# include <cstdlib> // for abort +# endif # define ANKERL_UNORDERED_DENSE_PMR 0 // NOLINT(cppcoreguidelines-macro-usage) # if defined(__has_include) # if __has_include(<memory_resource>) # undef ANKERL_UNORDERED_DENSE_PMR # define ANKERL_UNORDERED_DENSE_PMR 1 // NOLINT(cppcoreguidelines-macro-usage) -# include <memory_resource> // for polymorphic_allocator +# define ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR \ + std::pmr::polymorphic_allocator // NOLINT(cppcoreguidelines-macro-usage) +# include <memory_resource> // for polymorphic_allocator +# elif __has_include(<experimental/memory_resource>) +# undef ANKERL_UNORDERED_DENSE_PMR +# define ANKERL_UNORDERED_DENSE_PMR 1 // NOLINT(cppcoreguidelines-macro-usage) +# define ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR \ + std::experimental::pmr::polymorphic_allocator // NOLINT(cppcoreguidelines-macro-usage) +# include <experimental/memory_resource> // for polymorphic_allocator # endif # endif @@ -99,6 +122,38 @@ namespace ankerl::unordered_dense { inline namespace ANKERL_UNORDERED_DENSE_NAMESPACE { +namespace detail { + +# if ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() + +// make sure this is not inlined as it is slow and dramatically enlarges code, thus making other +// inlinings more difficult. Throws are also generally the slow path. +[[noreturn]] inline ANKERL_UNORDERED_DENSE_NOINLINE void on_error_key_not_found() { + throw std::out_of_range("ankerl::unordered_dense::map::at(): key not found"); +} +[[noreturn]] inline ANKERL_UNORDERED_DENSE_NOINLINE void on_error_bucket_overflow() { + throw std::overflow_error("ankerl::unordered_dense: reached max bucket size, cannot increase size"); +} +[[noreturn]] inline ANKERL_UNORDERED_DENSE_NOINLINE void on_error_too_many_elements() { + throw std::out_of_range("ankerl::unordered_dense::map::replace(): too many elements"); +} + +# else + +[[noreturn]] inline void on_error_key_not_found() { + abort(); +} +[[noreturn]] inline void on_error_bucket_overflow() { + abort(); +} +[[noreturn]] inline void on_error_too_many_elements() { + abort(); +} + +# endif + +} // namespace detail + // hash /////////////////////////////////////////////////////////////////////// // This is a stripped-down implementation of wyhash: https://github.com/wangyi-fudan/wyhash @@ -371,8 +426,10 @@ using detect_reserve = decltype(std::declval<T&>().reserve(size_t{})); template <typename Mapped> constexpr bool is_map_v = !std::is_void_v<Mapped>; +// clang-format off template <typename Hash, typename KeyEqual> constexpr bool is_transparent_v = is_detected_v<detect_is_transparent, Hash>&& is_detected_v<detect_is_transparent, KeyEqual>; +// clang-format on template <typename From, typename To1, typename To2> constexpr bool is_neither_convertible_v = !std::is_convertible_v<From, To1> && !std::is_convertible_v<From, To2>; @@ -590,7 +647,7 @@ private: void increase_size() { if (ANKERL_UNORDERED_DENSE_UNLIKELY(m_max_bucket_capacity == max_bucket_count())) { - throw std::overflow_error("ankerl::unordered_dense: reached max bucket size, cannot increase size"); + on_error_bucket_overflow(); } --m_shifts; deallocate_buckets(); @@ -745,10 +802,10 @@ private: template <typename K, typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true> auto do_at(K const& key) -> Q& { - if (auto it = find(key); end() != it) { + if (auto it = find(key); ANKERL_UNORDERED_DENSE_LIKELY(end() != it)) { return it->second; } - throw std::out_of_range("ankerl::unordered_dense::map::at(): key not found"); + on_error_key_not_found(); } template <typename K, typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true> @@ -842,8 +899,10 @@ public: : table(init, bucket_count, hash, KeyEqual(), alloc) {} ~table() { - auto ba = bucket_alloc(m_values.get_allocator()); - bucket_alloc_traits::deallocate(ba, m_buckets, bucket_count()); + if (nullptr != m_buckets) { + auto ba = bucket_alloc(m_values.get_allocator()); + bucket_alloc_traits::deallocate(ba, m_buckets, bucket_count()); + } } auto operator=(table const& other) -> table& { @@ -985,10 +1044,9 @@ public: // nonstandard API: // Discards the internally held container and replaces it with the one passed. Erases non-unique elements. auto replace(value_container_type&& container) { - if (container.size() > max_size()) { - throw std::out_of_range("ankerl::unordered_dense::map::replace(): too many elements"); + if (ANKERL_UNORDERED_DENSE_UNLIKELY(container.size() > max_size())) { + on_error_too_many_elements(); } - auto shifts = calc_shifts_for_size(container.size()); if (0 == m_num_buckets || shifts < m_shifts || container.get_allocator() != m_values.get_allocator()) { m_shifts = shifts; @@ -1479,10 +1537,10 @@ template <class Key, class Hash = hash<Key>, class KeyEqual = std::equal_to<Key>, class Bucket = bucket_type::standard> -using map = detail::table<Key, T, Hash, KeyEqual, std::pmr::polymorphic_allocator<std::pair<Key, T>>, Bucket>; +using map = detail::table<Key, T, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR<std::pair<Key, T>>, Bucket>; template <class Key, class Hash = hash<Key>, class KeyEqual = std::equal_to<Key>, class Bucket = bucket_type::standard> -using set = detail::table<Key, void, Hash, KeyEqual, std::pmr::polymorphic_allocator<Key>, Bucket>; +using set = detail::table<Key, void, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR_ALLOCATOR<Key>, Bucket>; } // namespace pmr @@ -1501,6 +1559,7 @@ using set = detail::table<Key, void, Hash, KeyEqual, std::pmr::polymorphic_alloc namespace std { // NOLINT(cert-dcl58-cpp) template <class Key, class T, class Hash, class KeyEqual, class AllocatorOrContainer, class Bucket, class Pred> +// NOLINTNEXTLINE(cert-dcl58-cpp) auto erase_if(ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket>& map, Pred pred) -> size_t { using map_t = ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket>; diff --git a/misc/benchmarks/external/emhash/hash_table7.hpp b/misc/benchmarks/external/emhash/hash_table7.hpp index ced0f1d0..8f8982f9 100644 --- a/misc/benchmarks/external/emhash/hash_table7.hpp +++ b/misc/benchmarks/external/emhash/hash_table7.hpp @@ -1,10 +1,10 @@ // emhash7::HashMap for C++11/14/17 -// version 2.2.3 +// version 2.2.4 // https://github.com/ktprime/ktprime/blob/master/hash_table7.hpp // // Licensed under the MIT License <http://opensource.org/licenses/MIT>. // SPDX-License-Identifier: MIT -// Copyright (c) 2019-2022 Huang Yuanbing & bailuzhou AT 163.com +// Copyright (c) 2019-2023 Huang Yuanbing & bailuzhou AT 163.com // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal @@ -166,6 +166,11 @@ namespace emhash7 { static constexpr size_type INACTIVE = 0 - 0x1u; #endif +#ifndef EMH_MALIGN + static constexpr uint32_t EMH_MALIGN = 16; +#endif +static_assert(EMH_MALIGN >= 16 && 0 == (EMH_MALIGN & (EMH_MALIGN - 1))); + #ifndef EMH_SIZE_TYPE_16BIT static_assert((int)INACTIVE < 0, "INACTIVE must negative (to int)"); #endif @@ -535,15 +540,25 @@ public: init(bucket, mlf); } - size_t AllocSize(uint64_t num_buckets) const + static size_t AllocSize(uint64_t num_buckets) { return (num_buckets + EPACK_SIZE) * sizeof(PairT) + (num_buckets + 7) / 8 + BIT_PACK; } + static PairT* alloc_bucket(size_type num_buckets) + { +#if _WIN32 + auto* new_pairs = (PairT*)malloc(AllocSize(num_buckets)); +#else + auto* new_pairs = (PairT*)aligned_alloc(EMH_MALIGN, AllocSize(num_buckets)); +#endif + return new_pairs; + } + HashMap(const HashMap& rhs) noexcept { if (rhs.load_factor() > EMH_MIN_LOAD_FACTOR) { - _pairs = (PairT*)malloc(AllocSize(rhs._num_buckets)); + _pairs = (PairT*)alloc_bucket(rhs._num_buckets); clone(rhs); } else { init(rhs._num_filled + 2, EMH_DEFAULT_LOAD_FACTOR); @@ -596,7 +611,7 @@ public: if (_num_buckets != rhs._num_buckets) { free(_pairs); - _pairs = (PairT*)malloc(AllocSize(rhs._num_buckets)); + _pairs = alloc_bucket(rhs._num_buckets); } clone(rhs); @@ -1355,7 +1370,7 @@ public: _num_buckets = num_buckets; _mask = num_buckets - 1; - _pairs = (PairT*)malloc(AllocSize(_num_buckets)); + _pairs = alloc_bucket(_num_buckets); memset((char*)(_pairs + _num_buckets), 0, sizeof(PairT) * EPACK_SIZE); _bitmask = decltype(_bitmask)(_pairs + EPACK_SIZE + num_buckets); diff --git a/misc/benchmarks/shootout_hashmaps.cpp b/misc/benchmarks/shootout_hashmaps.cpp index 78d7bce2..da523d71 100644 --- a/misc/benchmarks/shootout_hashmaps.cpp +++ b/misc/benchmarks/shootout_hashmaps.cpp @@ -35,7 +35,6 @@ KHASH_MAP_INIT_INT64(ii, IValue) // cmap template expansion #define i_key IKey #define i_val IValue -#define i_size uint32_t // optional, enables 2x expand #define i_tag ii #define i_max_load_factor MAX_LOAD_FACTOR / 100.0f #include <stc/cmap.h> |
