diff --git a/src/std/maps.c b/src/std/maps.c index e07053f61..b0371e271 100644 --- a/src/std/maps.c +++ b/src/std/maps.c @@ -24,118 +24,7 @@ # pragma warning(disable:4034) // sizeof(void) == 0 #endif -#define H_SIZE_INIT 3 - -// successive primes that double every time -static int H_PRIMES[] = { - 7,17,37,79,163,331,673,1361,2729,5471,10949,21911,43853,87613,175229,350459,700919,1401857,2803727,5607457,11214943,22429903,44859823,89719661,179424673,373587883,776531401,1611623773 -}; - -// ----- FREE LIST --------------------------------- - -typedef struct { - int pos; - int count; -} hl_free_bucket; - -typedef struct { - hl_free_bucket *buckets; - int head; - int nbuckets; -} hl_free_list; - -static void hl_freelist_resize( hl_free_list *f, int newsize ) { - hl_free_bucket *buckets = (hl_free_bucket*)hl_gc_alloc_noptr(sizeof(hl_free_bucket)*newsize); - memcpy(buckets,f->buckets,f->head * sizeof(hl_free_bucket)); - f->buckets = buckets; - f->nbuckets = newsize; -} - -static void hl_freelist_init( hl_free_list *f ) { - memset(f,0,sizeof(hl_free_list)); -} - -static void hl_freelist_add_range( hl_free_list *f, int pos, int count ) { - hl_free_bucket *b = f->buckets; - hl_free_bucket *prev = NULL; - if( !b ) { - // special handling for countinuous space - if( f->nbuckets == 0 ) { - f->head = pos; - f->nbuckets = count; - return; - } else if( f->head + f->nbuckets == pos ) { - f->nbuckets += count; - return; - } else if( pos + count == f->head ) { - f->head -= count; - f->nbuckets += count; - return; - } else { - int cur_pos = f->head, cur_count = f->nbuckets; - f->head = 0; - f->nbuckets = 0; - hl_freelist_resize(f,2); - if( cur_count ) hl_freelist_add_range(f,cur_pos,cur_count); - b = f->buckets; - } - } - while( b < f->buckets + f->head ) { - if( b->pos > pos ) break; - prev = b; - b++; - } - if( b < f->buckets + f->head && b->pos == pos + count ) { - b->pos -= count; - b->count += count; - // merge - if( prev && prev->pos + prev->count == b->pos ) { - prev->count += b->count; - memmove(b,b+1,((f->buckets + f->head) - (b+1)) * sizeof(hl_free_bucket)); - f->head--; - } - return; - } - if( prev && prev->pos + prev->count == pos ) { - prev->count += count; - return; - } - // insert - if( f->head == f->nbuckets ) { - int pos = (int)(b - f->buckets); - hl_freelist_resize(f,((f->nbuckets * 3) + 1) >> 1); - b = f->buckets + pos; - } - memmove(b+1,b,((f->buckets + f->head) - b) * sizeof(hl_free_bucket)); - b->pos = pos; - b->count = count; - f->head++; -} - -static void hl_freelist_add( hl_free_list *f, int pos ) { - hl_freelist_add_range(f,pos,1); -} - -static int hl_freelist_get( hl_free_list *f ) { - hl_free_bucket *b; - int p; - if( !f->buckets ) { - if( f->nbuckets == 0 ) return -1; - f->nbuckets--; - return f->head++; - } - if( f->head == 0 ) - return -1; - b = f->buckets + f->head - 1; - b->count--; - p = b->pos + b->count; - if( b->count == 0 ) { - f->head--; - if( f->head < (f->nbuckets>>1) ) - hl_freelist_resize(f,f->nbuckets>>1); - } - return p; -} +#define H_SIZE_INIT 8 #define _MVAL_TYPE vdynamic* diff --git a/src/std/maps.h b/src/std/maps.h index 02bc060f3..5590969f5 100644 --- a/src/std/maps.h +++ b/src/std/maps.h @@ -7,9 +7,6 @@ #define t_map _MNAME(_map) #define t_entry _MNAME(_entry) #define t_value _MNAME(_value) -#define _MLIMIT 128 -#define _MINDEX(m,ckey) ((m)->maxentries < _MLIMIT ? (int)((signed char*)(m)->cells)[ckey] : ((int*)(m)->cells)[ckey]) -#define _MNEXT(m,ckey) ((m)->maxentries < _MLIMIT ? (int)((signed char*)(m)->nexts)[ckey] : ((int*)(m)->nexts)[ckey]) #ifdef _MNO_EXPORTS #define _MSTATIC #else @@ -17,12 +14,10 @@ #endif typedef struct { - void *cells; - void *nexts; t_entry *entries; t_value *values; - hl_free_list lfree; - int ncells; + int *psl; + int nbuckets; int nentries; int maxentries; } t_map; @@ -37,17 +32,17 @@ t_map *_MNAME(alloc)() { } _MSTATIC _MVAL_TYPE *_MNAME(find)( t_map *m, t_key key ) { - int c, ckey; + int c, dc = 0; unsigned int hash; - if( !m->values ) return NULL; + if (m->nbuckets == 0) return NULL; hash = _MNAME(hash)(key); - ckey = hash % ((unsigned)m->ncells); - c = _MINDEX(m,ckey); - while( c >= 0 ) { - if( _MMATCH(c) ) + c = hash % ((unsigned)m->nbuckets); + while( m->psl[c] >= 0 && dc <= m->psl[c] ) { + if (_MMATCH(c)) return &m->values[c].value; - c = _MNEXT(m,c); + dc++; + c = (c + 1) % m->nbuckets; } return NULL; } @@ -55,34 +50,48 @@ _MSTATIC _MVAL_TYPE *_MNAME(find)( t_map *m, t_key key ) { static void _MNAME(resize)( t_map *m ); _MSTATIC void _MNAME(set_impl)( t_map *m, t_key key, _MVAL_TYPE value ) { - int c, ckey = 0; + int c = -1, prev = -1, dc = 0; unsigned int hash = _MNAME(hash)(key); - if( m->values ) { - ckey = hash % ((unsigned)m->ncells); - c = _MINDEX(m,ckey); - while( c >= 0 ) { - if( _MMATCH(c) ) { + if( m->nbuckets > 0 ) { + c = hash % ((unsigned)m->nbuckets); + while (m->psl[c] >= 0 && dc <= m->psl[c]) { + if (_MMATCH(c)) { m->values[c].value = value; return; } - c = _MNEXT(m,c); + dc++; + prev = c; + c = (c + 1) % m->nbuckets; + } + if (prev > 0) { + dc--; + c = prev; } } - c = hl_freelist_get(&m->lfree); - if( c < 0 ) { + if (m->nentries >= m->maxentries) { _MNAME(resize)(m); - ckey = hash % ((unsigned)m->ncells); - c = hl_freelist_get(&m->lfree); + dc = 0; + c = hash % ((unsigned)m->nbuckets); } - _MSET(c); - if( m->maxentries < _MLIMIT ) { - ((signed char*)m->nexts)[c] = ((signed char*)m->cells)[ckey]; - ((signed char*)m->cells)[ckey] = (signed char)c; - } else { - ((int*)m->nexts)[c] = ((int*)m->cells)[ckey]; - ((int*)m->cells)[ckey] = c; + while (m->psl[c] >= 0) { + if (dc > m->psl[c]) { + t_key key_tmp = _MKEY(m, c); + _MVAL_TYPE value_tmp = m->values[c].value; + int dc_tmp = m->psl[c]; + _MSET(c); + m->values[c].value = value; + m->psl[c] = dc; + key = key_tmp; + value = value_tmp; + dc = dc_tmp; + hash = _MNAME(hash)(key); + } + dc++; + c = (c + 1) % m->nbuckets; } + _MSET(c); m->values[c].value = value; + m->psl[c] = dc; m->nentries++; } @@ -93,42 +102,20 @@ static void _MNAME(resize)( t_map *m ) { if( m->nentries != m->maxentries ) hl_error("assert"); // resize - int i = 0; - int nentries = m->maxentries ? ((m->maxentries * 3) + 1) >> 1 : H_SIZE_INIT; - int ncells = nentries >> 2; - - while( H_PRIMES[i] < ncells ) i++; - ncells = H_PRIMES[i]; - - int ksize = nentries < _MLIMIT ? 1 : sizeof(int); - m->entries = (t_entry*)hl_gc_alloc_noptr(nentries * sizeof(t_entry)); - m->values = (t_value*)hl_gc_alloc_raw(nentries * sizeof(t_value)); - m->maxentries = nentries; - - if( old.ncells == ncells && (nentries < _MLIMIT || old.maxentries >= _MLIMIT) ) { - // simply expand - m->nexts = hl_gc_alloc_noptr(nentries * ksize); - memcpy(m->entries,old.entries,old.maxentries * sizeof(t_entry)); - memcpy(m->values,old.values,old.maxentries * sizeof(t_value)); - memcpy(m->nexts,old.nexts,old.maxentries * ksize); - memset(m->values + old.maxentries, 0, (nentries - old.maxentries) * sizeof(t_value)); - hl_freelist_add_range(&m->lfree,old.maxentries,m->maxentries - old.maxentries); - } else { - // expand and remap - m->cells = hl_gc_alloc_noptr((ncells + nentries) * ksize); - m->nexts = (signed char*)m->cells + ncells * ksize; - m->ncells = ncells; - m->nentries = 0; - memset(m->cells,0xFF,ncells * ksize); - memset(m->values, 0, nentries * sizeof(t_value)); - hl_freelist_init(&m->lfree); - hl_freelist_add_range(&m->lfree,0,m->maxentries); - for(i=0;i= 0 ) { - _MNAME(set_impl)(m,_MKEY((&old),c),old.values[c].value); - c = _MNEXT(&old,c); - } + int nbuckets = old.nbuckets ? old.nbuckets << 1 : H_SIZE_INIT; + m->entries = (t_entry *)hl_gc_alloc_noptr(nbuckets * sizeof(t_entry)); + m->values = (t_value *)hl_gc_alloc_raw(nbuckets * sizeof(t_value)); + m->psl = (int *)hl_gc_alloc_noptr(nbuckets * sizeof(int)); + m->nbuckets = nbuckets; + m->maxentries = nbuckets * 11 >> 4; + + // remap + m->nentries = 0; + memset(m->values, 0, nbuckets * sizeof(t_value)); + memset(m->psl, -1, nbuckets * sizeof(int)); + for (int c = 0; c < old.nbuckets; c++) { + if (old.psl[c] >= 0) { + _MNAME(set_impl)(m, _MKEY((&old), c), old.values[c].value); } } } @@ -150,63 +137,59 @@ HL_PRIM vdynamic* _MNAME(get)( t_map *m, t_key key ) { } HL_PRIM bool _MNAME(remove)( t_map *m, t_key key ) { - int c, prev = -1, ckey; + int c, dc = 0; unsigned int hash; - if( !m->cells ) return false; + if( m->nentries == 0 ) return false; key = _MNAME(filter)(key); hash = _MNAME(hash)(key); - ckey = hash % ((unsigned)m->ncells); - c = _MINDEX(m,ckey); - while( c >= 0 ) { - if( _MMATCH(c) ) { - hl_freelist_add(&m->lfree,c); + c = hash % ((unsigned)m->nbuckets); + while (m->psl[c] >= 0 && dc <= m->psl[c]) { + if (_MMATCH(c)) { m->nentries--; _MERASE(c); m->values[c].value = NULL; - if( m->maxentries < _MLIMIT ) { - if( prev >= 0 ) - ((signed char*)m->nexts)[prev] = ((signed char*)m->nexts)[c]; - else - ((signed char*)m->cells)[ckey] = ((signed char*)m->nexts)[c]; - } else { - if( prev >= 0 ) - ((int*)m->nexts)[prev] = ((int*)m->nexts)[c]; - else - ((int*)m->cells)[ckey] = ((int*)m->nexts)[c]; + m->psl[c] = -1; + // Move all following elements + int next = (c + 1) % m->nbuckets; + while (m->psl[next] > 0) { + key = _MKEY(m, next); + hash = _MNAME(hash)(key); + _MSET(c); + _MERASE(next); + m->values[c].value = m->values[next].value; + m->values[next].value = NULL; + m->psl[c] = m->psl[next] - 1; + m->psl[next] = -1; + c = next; + next = (c + 1) % m->nbuckets; } return true; } - prev = c; - c = _MNEXT(m,c); + dc++; + c = (c + 1) % m->nbuckets; } return false; } HL_PRIM varray* _MNAME(keys)( t_map *m ) { - varray *a = hl_alloc_array(&hlt_key,m->nentries); - t_key *keys = hl_aptr(a,t_key); + varray *a = hl_alloc_array(&hlt_key, m->nentries); + t_key *keys = hl_aptr(a, t_key); int p = 0; - int i; - for(i=0;incells;i++) { - int c = _MINDEX(m,i); - while( c >= 0 ) { - keys[p++] = _MKEY(m,c); - c = _MNEXT(m,c); + for (int c = 0; c < m->nbuckets; c++) { + if (m->psl[c] >= 0) { + keys[p++] = _MKEY(m, c); } } return a; } HL_PRIM varray* _MNAME(values)( t_map *m ) { - varray *a = hl_alloc_array(&hlt_dyn,m->nentries); - vdynamic **values = hl_aptr(a,vdynamic*); + varray *a = hl_alloc_array(&hlt_dyn, m->nentries); + vdynamic **values = hl_aptr(a, vdynamic*); int p = 0; - int i; - for(i=0;incells;i++) { - int c = _MINDEX(m,i); - while( c >= 0 ) { + for (int c = 0; c < m->nbuckets; c++) { + if (m->psl[c] >= 0) { values[p++] = m->values[c].value; - c = _MNEXT(m,c); } } return a;