diff options
| author | _Tradam <[email protected]> | 2023-09-08 01:29:47 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2023-09-08 01:29:47 +0000 |
| commit | 3c76c7f3d5db3f9586a90d03f8fbb02d79de9acd (patch) | |
| tree | afbe4b540967223911f7c5de36559b82154f02f3 /include/stc/cmap.h | |
| parent | 0841165881871ee01b782129be681209aeed2423 (diff) | |
| parent | 1a72205fe05c2375cfd380dd8381a8460d9ed8d1 (diff) | |
| download | STC-modified-3c76c7f3d5db3f9586a90d03f8fbb02d79de9acd.tar.gz STC-modified-3c76c7f3d5db3f9586a90d03f8fbb02d79de9acd.zip | |
Diffstat (limited to 'include/stc/cmap.h')
| -rw-r--r-- | include/stc/cmap.h | 458 |
1 files changed, 223 insertions, 235 deletions
diff --git a/include/stc/cmap.h b/include/stc/cmap.h index 14782b71..c069fbd8 100644 --- a/include/stc/cmap.h +++ b/include/stc/cmap.h @@ -47,43 +47,32 @@ int main(void) { cmap_ichar_drop(&m); } */ -#include "ccommon.h" +#include "priv/linkage.h" #ifndef CMAP_H_INCLUDED +#include "ccommon.h" #include "forward.h" #include <stdlib.h> #include <string.h> -typedef struct { int64_t idx; uint8_t hx; } chash_bucket_t; +struct chash_slot { uint8_t hashx; }; #endif // CMAP_H_INCLUDED #ifndef _i_prefix -#define _i_prefix cmap_ -#endif -#ifdef _i_isset - #define _i_MAP_ONLY c_false - #define _i_SET_ONLY c_true - #define _i_keyref(vp) (vp) -#else + #define _i_prefix cmap_ #define _i_ismap #define _i_MAP_ONLY c_true #define _i_SET_ONLY c_false #define _i_keyref(vp) (&(vp)->first) -#endif -#define _i_ishash -#ifndef i_max_load_factor - #define i_max_load_factor 0.85f -#endif -#ifndef i_ssize - #define i_ssize int32_t - #define _i_size intptr_t - #define _i_expandby 1 #else - #define _i_expandby 2 - #define _i_size i_ssize + #define _i_isset + #define _i_MAP_ONLY c_false + #define _i_SET_ONLY c_true + #define _i_keyref(vp) (vp) #endif +#define _i_ishash #include "priv/template.h" #ifndef i_is_forward - _cx_deftypes(_c_chash_types, _cx_self, i_key, i_val, i_ssize, _i_MAP_ONLY, _i_SET_ONLY); + _cx_DEFTYPES(_c_chash_types, _cx_Self, i_key, i_val, _i_MAP_ONLY, _i_SET_ONLY); #endif _i_MAP_ONLY( struct _cx_value { @@ -92,61 +81,61 @@ _i_MAP_ONLY( struct _cx_value { }; ) typedef i_keyraw _cx_keyraw; -typedef i_valraw _cx_memb(_rmapped); +typedef i_valraw _cx_MEMB(_rmapped); typedef _i_SET_ONLY( i_keyraw ) _i_MAP_ONLY( struct { i_keyraw first; i_valraw second; } ) _cx_raw; -STC_API _cx_self _cx_memb(_with_capacity)(_i_size cap); +STC_API _cx_Self _cx_MEMB(_with_capacity)(intptr_t cap); #if !defined i_no_clone -STC_API _cx_self _cx_memb(_clone)(_cx_self map); +STC_API _cx_Self _cx_MEMB(_clone)(_cx_Self map); #endif -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, _i_size capacity); -STC_API chash_bucket_t _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_INLINE _cx_self _cx_memb(_init)(void) { _cx_self map = {0}; return map; } -STC_INLINE void _cx_memb(_shrink_to_fit)(_cx_self* self) { _cx_memb(_reserve)(self, self->size); } -STC_INLINE float _cx_memb(_max_load_factor)(const _cx_self* self) { return (float)(i_max_load_factor); } -STC_INLINE bool _cx_memb(_empty)(const _cx_self* map) { return !map->size; } -STC_INLINE _i_size _cx_memb(_size)(const _cx_self* map) { return map->size; } -STC_INLINE _i_size _cx_memb(_bucket_count)(_cx_self* map) { return map->bucket_count; } -STC_INLINE _i_size _cx_memb(_capacity)(const _cx_self* map) - { return (_i_size)((float)map->bucket_count * (i_max_load_factor)); } -STC_INLINE bool _cx_memb(_contains)(const _cx_self* self, _cx_keyraw rkey) - { return self->size && self->_hashx[_cx_memb(_bucket_)(self, &rkey).idx]; } - -#ifndef _i_isset - STC_API _cx_result _cx_memb(_insert_or_assign)(_cx_self* self, i_key key, i_val mapped); +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 _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); +STC_API intptr_t _cx_MEMB(_capacity)(const _cx_Self* map); + +STC_INLINE _cx_Self _cx_MEMB(_init)(void) { _cx_Self map = {0}; return map; } +STC_INLINE void _cx_MEMB(_shrink_to_fit)(_cx_Self* self) { _cx_MEMB(_reserve)(self, (intptr_t)self->size); } +STC_INLINE bool _cx_MEMB(_empty)(const _cx_Self* map) { return !map->size; } +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).inserted; } + +#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); + STC_API _cx_result _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped); #endif STC_INLINE const _cx_mapped* - _cx_memb(_at)(const _cx_self* self, _cx_keyraw rkey) { - chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey); - assert(self->_hashx[b.idx]); - return &self->table[b.idx].second; + _cx_MEMB(_at)(const _cx_Self* self, _cx_keyraw rkey) { + _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 + _cx_MEMB(_at_mut)(_cx_Self* self, _cx_keyraw rkey) + { return (_cx_mapped*)_cx_MEMB(_at)(self, rkey); } +#endif // _i_ismap #if !defined i_no_clone -STC_INLINE void _cx_memb(_copy)(_cx_self *self, const _cx_self* other) { - if (self->table == other->table) +STC_INLINE void _cx_MEMB(_copy)(_cx_Self *self, const _cx_Self* other) { + if (self->data == other->data) return; - _cx_memb(_drop)(self); - *self = _cx_memb(_clone)(*other); + _cx_MEMB(_drop)(self); + *self = _cx_MEMB(_clone)(*other); } STC_INLINE _cx_value -_cx_memb(_value_clone)(_cx_value _val) { +_cx_MEMB(_value_clone)(_cx_value _val) { *_i_keyref(&_val) = i_keyclone((*_i_keyref(&_val))); _i_MAP_ONLY( _val.second = i_valclone(_val.second); ) return _val; @@ -155,31 +144,39 @@ _cx_memb(_value_clone)(_cx_value _val) { #if !defined i_no_emplace STC_INLINE _cx_result -_cx_memb(_emplace)(_cx_self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) { - _cx_result _res = _cx_memb(_insert_entry_)(self, rkey); +_cx_MEMB(_emplace)(_cx_Self* self, _cx_keyraw rkey _i_MAP_ONLY(, i_valraw rmapped)) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey); if (_res.inserted) { *_i_keyref(_res.ref) = i_keyfrom(rkey); _i_MAP_ONLY( _res.ref->second = i_valfrom(rmapped); ) } 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) { +STC_INLINE _cx_raw _cx_MEMB(_value_toraw)(const _cx_value* val) { return _i_SET_ONLY( i_keyto(val) ) _i_MAP_ONLY( c_LITERAL(_cx_raw){i_keyto((&val->first)), i_valto((&val->second))} ); } -STC_INLINE void -_cx_memb(_value_drop)(_cx_value* _val) { +STC_INLINE void _cx_MEMB(_value_drop)(_cx_value* _val) { i_keydrop(_i_keyref(_val)); _i_MAP_ONLY( i_valdrop((&_val->second)); ) } 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))); +_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))); if (_res.inserted) { *_i_keyref(_res.ref) = _key; _i_MAP_ONLY( _res.ref->second = _mapped; )} else @@ -187,157 +184,150 @@ _cx_memb(_insert)(_cx_self* self, i_key _key _i_MAP_ONLY(, i_val _mapped)) { return _res; } -STC_INLINE _cx_result -_cx_memb(_push)(_cx_self* self, _cx_value _val) { - _cx_result _res = _cx_memb(_insert_entry_)(self, i_keyto(_i_keyref(&_val))); +STC_INLINE _cx_value* _cx_MEMB(_push)(_cx_Self* self, _cx_value _val) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, i_keyto(_i_keyref(&_val))); if (_res.inserted) *_res.ref = _val; else - _cx_memb(_value_drop)(&_val); - return _res; + _cx_MEMB(_value_drop)(&_val); + return _res.ref; } -STC_INLINE void _cx_memb(_put_n)(_cx_self* self, const _cx_raw* raw, _i_size n) { +STC_INLINE void _cx_MEMB(_put_n)(_cx_Self* self, const _cx_raw* raw, intptr_t n) { while (n--) #if defined _i_isset && defined i_no_emplace - _cx_memb(_insert)(self, *raw++); + _cx_MEMB(_insert)(self, *raw++); #elif defined _i_isset - _cx_memb(_emplace)(self, *raw++); + _cx_MEMB(_emplace)(self, *raw++); #elif defined i_no_emplace - _cx_memb(_insert_or_assign)(self, raw->first, raw->second), ++raw; + _cx_MEMB(_insert_or_assign)(self, raw->first, raw->second), ++raw; #else - _cx_memb(_emplace_or_assign)(self, raw->first, raw->second), ++raw; + _cx_MEMB(_emplace_or_assign)(self, raw->first, raw->second), ++raw; #endif } -STC_INLINE _cx_self _cx_memb(_from_n)(const _cx_raw* raw, _i_size n) - { _cx_self cx = {0}; _cx_memb(_put_n)(&cx, raw, n); return cx; } +STC_INLINE _cx_Self _cx_MEMB(_from_n)(const _cx_raw* raw, intptr_t n) + { _cx_Self cx = {0}; _cx_MEMB(_put_n)(&cx, raw, n); return cx; } -STC_INLINE _cx_iter _cx_memb(_begin)(const _cx_self* self) { - _cx_iter it = {self->table, self->table+self->bucket_count, self->_hashx}; - if (it._hx) - while (*it._hx == 0) - ++it.ref, ++it._hx; - if (it.ref == it._end) it.ref = NULL; - return it; -} +STC_API _cx_iter _cx_MEMB(_begin)(const _cx_Self* self); -STC_INLINE _cx_iter -_cx_memb(_end)(const _cx_self* self) +STC_INLINE _cx_iter _cx_MEMB(_end)(const _cx_Self* self) { return c_LITERAL(_cx_iter){NULL}; } -STC_INLINE void -_cx_memb(_next)(_cx_iter* it) { - while ((++it->ref, *++it->_hx == 0)) ; +STC_INLINE void _cx_MEMB(_next)(_cx_iter* it) { + while ((++it->ref, (++it->sref)->hashx == 0)) ; if (it->ref == it->_end) it->ref = NULL; } -STC_INLINE _cx_iter -_cx_memb(_advance)(_cx_iter it, size_t n) { - while (n-- && it.ref) _cx_memb(_next)(&it); +STC_INLINE _cx_iter _cx_MEMB(_advance)(_cx_iter it, size_t n) { + while (n-- && it.ref) _cx_MEMB(_next)(&it); return it; } STC_INLINE _cx_iter -_cx_memb(_find)(const _cx_self* self, _cx_keyraw rkey) { - int64_t idx; - if (self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx]) - return c_LITERAL(_cx_iter){self->table + idx, - self->table + self->bucket_count, - self->_hashx + idx}; - return _cx_memb(_end)(self); +_cx_MEMB(_find)(const _cx_Self* self, _cx_keyraw rkey) { + _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.ref - self->data)}; + return _cx_MEMB(_end)(self); } STC_INLINE const _cx_value* -_cx_memb(_get)(const _cx_self* self, _cx_keyraw rkey) { - int64_t idx; - if (self->size && self->_hashx[idx = _cx_memb(_bucket_)(self, &rkey).idx]) - return self->table + idx; +_cx_MEMB(_get)(const _cx_Self* self, _cx_keyraw rkey) { + _cx_result b; + if (self->size && !(b = _cx_MEMB(_bucket_)(self, &rkey)).inserted) + return b.ref; return NULL; } STC_INLINE _cx_value* -_cx_memb(_get_mut)(_cx_self* self, _cx_keyraw rkey) - { return (_cx_value*)_cx_memb(_get)(self, rkey); } +_cx_MEMB(_get_mut)(_cx_Self* self, _cx_keyraw rkey) + { return (_cx_value*)_cx_MEMB(_get)(self, rkey); } STC_INLINE int -_cx_memb(_erase)(_cx_self* self, _cx_keyraw rkey) { - if (self->size == 0) - return 0; - chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey); - return self->_hashx[b.idx] ? _cx_memb(_erase_entry)(self, self->table + b.idx), 1 : 0; +_cx_MEMB(_erase)(_cx_Self* self, _cx_keyraw rkey) { + _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 -_cx_memb(_erase_at)(_cx_self* self, _cx_iter it) { - _cx_memb(_erase_entry)(self, it.ref); - if (*it._hx == 0) - _cx_memb(_next)(&it); +_cx_MEMB(_erase_at)(_cx_Self* self, _cx_iter it) { + _cx_MEMB(_erase_entry)(self, it.ref); + if (it.sref->hashx == 0) + _cx_MEMB(_next)(&it); return it; } STC_INLINE bool -_cx_memb(_eq)(const _cx_self* self, const _cx_self* other) { - if (_cx_memb(_size)(self) != _cx_memb(_size)(other)) return false; - for (_cx_iter i = _cx_memb(_begin)(self); i.ref; _cx_memb(_next)(&i)) { +_cx_MEMB(_eq)(const _cx_Self* self, const _cx_Self* other) { + if (_cx_MEMB(_size)(self) != _cx_MEMB(_size)(other)) return false; + for (_cx_iter i = _cx_MEMB(_begin)(self); i.ref; _cx_MEMB(_next)(&i)) { const _cx_keyraw _raw = i_keyto(_i_keyref(i.ref)); - if (!_cx_memb(_contains)(other, _raw)) return false; + if (!_cx_MEMB(_contains)(other, _raw)) return false; } return true; } /* -------------------------- IMPLEMENTATION ------------------------- */ -#if defined(i_implement) +#if defined(i_implement) || defined(i_static) +#ifndef i_max_load_factor + #define i_max_load_factor 0.80f +#endif +#define fastrange_2(x, n) (intptr_t)((x) & (size_t)((n) - 1)) // n power of 2. -#ifndef CMAP_H_INCLUDED -STC_INLINE int64_t fastrange_1(uint64_t x, uint64_t n) - { return (int64_t)((uint32_t)x*n >> 32); } // n < 2^32 - -STC_INLINE int64_t fastrange_2(uint64_t x, uint64_t n) - { return (int64_t)(x & (n - 1)); } // n power of 2. - -STC_INLINE uint64_t next_power_of_2(uint64_t n) { - n--; - n |= n >> 1, n |= n >> 2; - n |= n >> 4, n |= n >> 8; - n |= n >> 16, n |= n >> 32; - return n + 1; +STC_DEF _cx_iter _cx_MEMB(_begin)(const _cx_Self* self) { + _cx_iter it = {self->data, self->data+self->bucket_count, self->slot}; + if (it.sref) + while (it.sref->hashx == 0) + ++it.ref, ++it.sref; + if (it.ref == it._end) it.ref = NULL; + return it; +} + +STC_DEF float _cx_MEMB(_max_load_factor)(const _cx_Self* self) { + return (float)(i_max_load_factor); +} + +STC_DEF intptr_t _cx_MEMB(_capacity)(const _cx_Self* map) { + return (intptr_t)((float)map->bucket_count * (i_max_load_factor)); } -#endif // CMAP_H_INCLUDED -STC_DEF _cx_self -_cx_memb(_with_capacity)(const _i_size cap) { - _cx_self h = {0}; - _cx_memb(_reserve)(&h, cap); - return h; +STC_DEF _cx_Self _cx_MEMB(_with_capacity)(const intptr_t cap) { + _cx_Self map = {0}; + _cx_MEMB(_reserve)(&map, cap); + return map; } -STC_INLINE void _cx_memb(_wipe_)(_cx_self* self) { +STC_INLINE void _cx_MEMB(_wipe_)(_cx_Self* self) { if (self->size == 0) return; - _cx_value* e = self->table, *end = e + self->bucket_count; - uint8_t *hx = self->_hashx; - for (; e != end; ++e) - if (*hx++) - _cx_memb(_value_drop)(e); + _cx_value* d = self->data, *_end = d + self->bucket_count; + struct chash_slot* s = self->slot; + for (; d != _end; ++d) + if ((s++)->hashx) + _cx_MEMB(_value_drop)(d); } -STC_DEF void _cx_memb(_drop)(_cx_self* self) { - _cx_memb(_wipe_)(self); - i_free(self->_hashx); - i_free((void *) self->table); +STC_DEF void _cx_MEMB(_drop)(_cx_Self* self) { + _cx_MEMB(_wipe_)(self); + i_free(self->slot); + i_free(self->data); } -STC_DEF void _cx_memb(_clear)(_cx_self* self) { - _cx_memb(_wipe_)(self); +STC_DEF void _cx_MEMB(_clear)(_cx_Self* self) { + _cx_MEMB(_wipe_)(self); self->size = 0; - c_memset(self->_hashx, 0, self->bucket_count); + c_memset(self->slot, 0, c_sizeof(struct 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))); + _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))); _cx_mapped* _mp = _res.ref ? &_res.ref->second : &_mapped; if (_res.inserted) _res.ref->first = _key; @@ -349,8 +339,8 @@ STC_DEF void _cx_memb(_clear)(_cx_self* self) { #if !defined i_no_emplace STC_DEF _cx_result - _cx_memb(_emplace_or_assign)(_cx_self* self, _cx_keyraw rkey, i_valraw rmapped) { - _cx_result _res = _cx_memb(_insert_entry_)(self, rkey); + _cx_MEMB(_emplace_or_assign)(_cx_Self* self, _cx_keyraw rkey, i_valraw rmapped) { + _cx_result _res = _cx_MEMB(_insert_entry_)(self, rkey); if (_res.inserted) _res.ref->first = i_keyfrom(rkey); else { @@ -361,119 +351,117 @@ 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_t -_cx_memb(_bucket_)(const _cx_self* self, const _cx_keyraw* rkeyptr) { +STC_DEF _cx_result +_cx_MEMB(_bucket_)(const _cx_Self* self, const _cx_keyraw* rkeyptr) { const uint64_t _hash = i_hash(rkeyptr); - int64_t _cap = self->bucket_count; - chash_bucket_t b = {c_PASTE(fastrange_,_i_expandby)(_hash, (uint64_t)_cap), (uint8_t)(_hash | 0x80)}; - const uint8_t* _hx = self->_hashx; - while (_hx[b.idx]) { - if (_hx[b.idx] == b.hx) { - const _cx_keyraw _raw = i_keyto(_i_keyref(self->table + b.idx)); - if (i_eq((&_raw), rkeyptr)) + intptr_t _cap = self->bucket_count; + intptr_t _idx = fastrange_2(_hash, _cap); + _cx_result b = {NULL, true, (uint8_t)(_hash | 0x80)}; + const struct chash_slot* s = self->slot; + 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.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 + 2 > (i_ssize)((float)self->bucket_count * (i_max_load_factor))) - if (!_cx_memb(_reserve)(self, self->size*3/2)) - return res; - - chash_bucket_t b = _cx_memb(_bucket_)(self, &rkey); - res.ref = &self->table[b.idx]; - if ((res.inserted = !self->_hashx[b.idx])) { - self->_hashx[b.idx] = b.hx; +_cx_MEMB(_insert_entry_)(_cx_Self* self, _cx_keyraw rkey) { + 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 c_LITERAL(_cx_result){NULL}; + + _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 -STC_DEF _cx_self -_cx_memb(_clone)(_cx_self m) { - if (m.table) { - _cx_value *t = (_cx_value *)i_malloc(c_sizeof(_cx_value)*m.bucket_count), - *dst = t, *m_end = m.table + m.bucket_count; - uint8_t *h = (uint8_t *)c_memcpy(i_malloc(m.bucket_count + 1), m._hashx, m.bucket_count + 1); - if (!(t && h)) - { i_free(t), i_free(h), t = 0, h = 0, m.bucket_count = 0; } +STC_DEF _cx_Self +_cx_MEMB(_clone)(_cx_Self m) { + if (m.data) { + _cx_value *d = (_cx_value *)i_malloc(c_sizeof(_cx_value)*m.bucket_count), + *_dst = d, *_end = m.data + m.bucket_count; + const intptr_t _mem = c_sizeof(struct chash_slot)*(m.bucket_count + 1); + struct chash_slot *s = (struct chash_slot *)c_memcpy(i_malloc(_mem), m.slot, _mem); + if (!(d && s)) + { i_free(d), i_free(s), d = 0, s = 0, m.bucket_count = 0; } else - for (; m.table != m_end; ++m.table, ++m._hashx, ++dst) - if (*m._hashx) - *dst = _cx_memb(_value_clone)(*m.table); - m.table = t, m._hashx = h; + for (; m.data != _end; ++m.data, ++m.slot, ++_dst) + if (m.slot->hashx) + *_dst = _cx_MEMB(_value_clone)(*m.data); + m.data = d, m.slot = s; } return m; } #endif STC_DEF bool -_cx_memb(_reserve)(_cx_self* self, const _i_size newcap) { - const i_ssize _oldbuckets = self->bucket_count, _newcap = (i_ssize)newcap; - if (_newcap != self->size && _newcap <= _oldbuckets) +_cx_MEMB(_reserve)(_cx_Self* self, const intptr_t _newcap) { + const intptr_t _oldbucks = self->bucket_count; + if (_newcap != self->size && _newcap <= _oldbucks) return true; - i_ssize _nbuckets = (i_ssize)((float)_newcap / (i_max_load_factor)) + 4; - #if _i_expandby == 2 - _nbuckets = (i_ssize)next_power_of_2(_nbuckets); - #else - _nbuckets |= 1; - #endif - _cx_self m = { - (_cx_value *)i_malloc(c_sizeof(_cx_value)*_nbuckets), - (uint8_t *)i_calloc(_nbuckets + 1, 1), - self->size, _nbuckets, + intptr_t _newbucks = (intptr_t)((float)_newcap / (i_max_load_factor)) + 4; + _newbucks = stc_nextpow2(_newbucks); + _cx_Self m = { + (_cx_value *)i_malloc(_newbucks*c_sizeof(_cx_value)), + (struct chash_slot *)i_calloc(_newbucks + 1, c_sizeof(struct chash_slot)), + self->size, _newbucks }; - bool ok = m.table && m._hashx; - if (ok) { /* Rehash: */ - m._hashx[_nbuckets] = 0xff; - const _cx_value* e = self->table; - const uint8_t* h = self->_hashx; - for (i_ssize i = 0; i < _oldbuckets; ++i, ++e) if (*h++) { - _cx_keyraw r = i_keyto(_i_keyref(e)); - chash_bucket_t b = _cx_memb(_bucket_)(&m, &r); - m.table[b.idx] = *e; - m._hashx[b.idx] = b.hx; + bool ok = m.data && m.slot; + if (ok) { // Rehash: + m.slot[_newbucks].hashx = 0xff; + const _cx_value* d = self->data; + const struct 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)); + _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); + c_swap(_cx_Self, self, &m); } - i_free(m._hashx); - i_free(m.table); + i_free(m.slot); + i_free(m.data); return ok; } STC_DEF void -_cx_memb(_erase_entry)(_cx_self* self, _cx_value* _val) { - 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); - for (;;) { /* delete without leaving tombstone */ - if (++j == _cap) - j = 0; - if (! _hashx[j]) +_cx_MEMB(_erase_entry)(_cx_Self* self, _cx_value* _val) { + _cx_value* d = self->data; + struct chash_slot* s = self->slot; + intptr_t i = _val - d, j = i, k; + const intptr_t _cap = self->bucket_count; + _cx_MEMB(_value_drop)(_val); + for (;;) { // delete without leaving tombstone + if (++j == _cap) j = 0; + if (! s[j].hashx) break; - const _cx_keyraw _raw = i_keyto(_i_keyref(_slot + j)); - k = (i_ssize)c_PASTE(fastrange_,_i_expandby)(i_hash((&_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; + const _cx_keyraw _raw = i_keyto(_i_keyref(d + j)); + k = fastrange_2(i_hash((&_raw)), _cap); + if ((j < i) ^ (k <= i) ^ (k > j)) { // is k outside (i, j]? + d[i] = d[j]; + s[i] = s[j]; + i = j; + } } - _hashx[i] = 0; + s[i].hashx = 0; --self->size; } - #endif // i_implement #undef i_max_load_factor -#undef _i_size #undef _i_isset #undef _i_ismap #undef _i_ishash |
