737 lines
15 KiB
C
737 lines
15 KiB
C
/*
|
|
* $Id: map.c 391 2008-09-27 09:51:23Z baconevi $
|
|
*
|
|
* {License}
|
|
*/
|
|
|
|
#include <ase/cmn/map.h>
|
|
#include "mem.h"
|
|
|
|
#define map_t ase_map_t
|
|
#define pair_t ase_map_pair_t
|
|
#define copier_t ase_map_copier_t
|
|
#define freeer_t ase_map_freeer_t
|
|
#define hasher_t ase_map_hasher_t
|
|
#define comper_t ase_map_comper_t
|
|
#define keeper_t ase_map_keeper_t
|
|
#define sizer_t ase_map_sizer_t
|
|
#define walker_t ase_map_walker_t
|
|
|
|
#define KPTR(p) ASE_MAP_KPTR(p)
|
|
#define KLEN(p) ASE_MAP_KLEN(p)
|
|
#define VPTR(p) ASE_MAP_VPTR(p)
|
|
#define VLEN(p) ASE_MAP_VLEN(p)
|
|
#define NEXT(p) ASE_MAP_NEXT(p)
|
|
|
|
#define SIZEOF(x) ASE_SIZEOF(x)
|
|
#define size_t ase_size_t
|
|
#define byte_t ase_byte_t
|
|
#define uint_t ase_uint_t
|
|
#define mmgr_t ase_mmgr_t
|
|
|
|
#define KTOB(map,len) ((len)*(map)->scale[ASE_MAP_KEY])
|
|
#define VTOB(map,len) ((len)*(map)->scale[ASE_MAP_VAL])
|
|
|
|
static int reorganize (map_t* map);
|
|
|
|
static size_t hash_key (map_t* map, const void* kptr, size_t klen)
|
|
{
|
|
size_t n = 0;
|
|
const byte_t* p = (const byte_t*)kptr;
|
|
const byte_t* bound = p + klen;
|
|
|
|
while (p < bound)
|
|
{
|
|
n = n * 31 + *p++;
|
|
p++;
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
static int comp_key (map_t* map,
|
|
const void* kptr1, size_t klen1,
|
|
const void* kptr2, size_t klen2)
|
|
{
|
|
if (klen1 == klen2) return ASE_MEMCMP (kptr1, kptr2, KTOB(map,klen1));
|
|
/* it just returns 1 to indicate that they are different. */
|
|
return 1;
|
|
}
|
|
|
|
static pair_t* alloc_pair (map_t* map,
|
|
void* kptr, size_t klen, void* vptr, size_t vlen)
|
|
{
|
|
pair_t* n;
|
|
copier_t kcop = map->copier[ASE_MAP_KEY];
|
|
copier_t vcop = map->copier[ASE_MAP_VAL];
|
|
|
|
size_t as = SIZEOF(pair_t);
|
|
if (kcop == ASE_MAP_COPIER_INLINE) as += KTOB(map,klen);
|
|
if (vcop == ASE_MAP_COPIER_INLINE) as += VTOB(map,vlen);
|
|
|
|
n = (pair_t*) ASE_MMGR_ALLOC (map->mmgr, as);
|
|
if (n == ASE_NULL) return ASE_NULL;
|
|
|
|
NEXT(n) = ASE_NULL;
|
|
|
|
KLEN(n) = klen;
|
|
if (kcop == ASE_NULL)
|
|
{
|
|
KPTR(n) = kptr;
|
|
}
|
|
else if (kcop == ASE_MAP_COPIER_INLINE)
|
|
{
|
|
KPTR(n) = n + 1;
|
|
ASE_MEMCPY (KPTR(n), kptr, KTOB(map,klen));
|
|
}
|
|
else
|
|
{
|
|
KPTR(n) = kcop (map, kptr, klen);
|
|
if (KPTR(n) == ASE_NULL)
|
|
{
|
|
ASE_MMGR_FREE (map->mmgr, n);
|
|
return ASE_NULL;
|
|
}
|
|
}
|
|
|
|
VLEN(n) = vlen;
|
|
if (vcop == ASE_NULL)
|
|
{
|
|
VPTR(n) = vptr;
|
|
}
|
|
else if (vcop == ASE_MAP_COPIER_INLINE)
|
|
{
|
|
VPTR(n) = n + 1;
|
|
if (kcop == ASE_MAP_COPIER_INLINE)
|
|
VPTR(n) = (byte_t*)VPTR(n) + KTOB(map,klen);
|
|
ASE_MEMCPY (VPTR(n), vptr, VTOB(map,vlen));
|
|
}
|
|
else
|
|
{
|
|
VPTR(n) = vcop (map, vptr, vlen);
|
|
if (VPTR(n) != ASE_NULL)
|
|
{
|
|
if (map->freeer[ASE_MAP_KEY] != ASE_NULL)
|
|
map->freeer[ASE_MAP_KEY] (map, KPTR(n), KLEN(n));
|
|
ASE_MMGR_FREE (map->mmgr, n);
|
|
return ASE_NULL;
|
|
}
|
|
}
|
|
|
|
return n;
|
|
}
|
|
|
|
static void free_pair (map_t* map, pair_t* pair)
|
|
{
|
|
if (map->freeer[ASE_MAP_KEY] != ASE_NULL)
|
|
map->freeer[ASE_MAP_KEY] (map, KPTR(pair), KLEN(pair));
|
|
if (map->freeer[ASE_MAP_VAL] != ASE_NULL)
|
|
map->freeer[ASE_MAP_VAL] (map, VPTR(pair), VLEN(pair));
|
|
ASE_MMGR_FREE (map->mmgr, pair);
|
|
}
|
|
|
|
static pair_t* change_pair_val (
|
|
map_t* map, pair_t* pair, void* vptr, size_t vlen)
|
|
{
|
|
if (VPTR(pair) == vptr && VLEN(pair) == vlen)
|
|
{
|
|
/* if the old value and the new value are the same,
|
|
* it just calls the handler for this condition.
|
|
* No value replacement occurs. */
|
|
if (map->keeper != ASE_NULL)
|
|
{
|
|
map->keeper (map, vptr, vlen);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
copier_t vcop = map->copier[ASE_MAP_VAL];
|
|
void* ovptr = VPTR(pair);
|
|
size_t ovlen = VLEN(pair);
|
|
|
|
/* place the new value according to the copier */
|
|
if (vcop == ASE_NULL)
|
|
{
|
|
VPTR(pair) = vptr;
|
|
VLEN(pair) = vlen;
|
|
}
|
|
else if (vcop == ASE_MAP_COPIER_INLINE)
|
|
{
|
|
if (ovlen == vlen)
|
|
{
|
|
ASE_MEMCPY (VPTR(pair), vptr, VTOB(map,vlen));
|
|
}
|
|
else
|
|
{
|
|
/* need to reconstruct the pair */
|
|
pair_t* p = alloc_pair (map,
|
|
KPTR(pair), KLEN(pair),
|
|
vptr, vlen);
|
|
if (p == ASE_NULL) return ASE_NULL;
|
|
free_pair (map, pair);
|
|
return p;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
void* nvptr = vcop (map, vptr, vlen);
|
|
if (nvptr == ASE_NULL) return ASE_NULL;
|
|
VPTR(pair) = nvptr;
|
|
VLEN(pair) = vlen;
|
|
}
|
|
|
|
/* free up the old value */
|
|
if (map->freeer[ASE_MAP_VAL] != ASE_NULL)
|
|
{
|
|
map->freeer[ASE_MAP_VAL] (map, ovptr, ovlen);
|
|
}
|
|
}
|
|
|
|
|
|
return pair;
|
|
}
|
|
|
|
map_t* ase_map_open (mmgr_t* mmgr, size_t ext, size_t capa, int factor)
|
|
{
|
|
map_t* map;
|
|
|
|
if (mmgr == ASE_NULL)
|
|
{
|
|
mmgr = ASE_MMGR_GETDFL();
|
|
|
|
ASE_ASSERTX (mmgr != ASE_NULL,
|
|
"Set the memory manager with ASE_MMGR_SETDFL()");
|
|
|
|
if (mmgr == ASE_NULL) return ASE_NULL;
|
|
}
|
|
|
|
map = (ase_map_t*) ASE_MMGR_ALLOC (mmgr, ASE_SIZEOF(ase_map_t) + ext);
|
|
if (map == ASE_NULL) return ASE_NULL;
|
|
|
|
if (ase_map_init (map, mmgr, capa, factor) == ASE_NULL)
|
|
{
|
|
ASE_MMGR_FREE (mmgr, map);
|
|
return ASE_NULL;
|
|
}
|
|
|
|
return map;
|
|
}
|
|
|
|
void ase_map_close (map_t* map)
|
|
{
|
|
ase_map_fini (map);
|
|
ASE_MMGR_FREE (map->mmgr, map);
|
|
}
|
|
|
|
map_t* ase_map_init (map_t* map, mmgr_t* mmgr, size_t capa, int factor)
|
|
{
|
|
ASE_ASSERTX (capa > 0,
|
|
"The initial capacity should be greater than 0. Otherwise, it is adjusted to 1 in the release mode");
|
|
ASE_ASSERTX (factor >= 0 && factor <= 100,
|
|
"The load factor should be between 0 and 100 inclusive. In the release mode, a value out of the range is adjusted to 100");
|
|
|
|
/* some initial adjustment */
|
|
if (capa <= 0) capa = 1;
|
|
if (factor > 100) factor = 100;
|
|
|
|
/* do not zero out the extension */
|
|
ASE_MEMSET (map, 0, SIZEOF(map_t));
|
|
map->mmgr = mmgr;
|
|
|
|
map->bucket = ASE_MMGR_ALLOC (mmgr, capa*SIZEOF(pair_t*));
|
|
if (map->bucket == ASE_NULL) return ASE_NULL;
|
|
|
|
/*for (i = 0; i < capa; i++) map->bucket[i] = ASE_NULL;*/
|
|
ASE_MEMSET (map->bucket, 0, capa*SIZEOF(pair_t*));
|
|
|
|
map->scale[ASE_MAP_KEY] = 1;
|
|
map->scale[ASE_MAP_VAL] = 1;
|
|
map->factor = factor;
|
|
|
|
map->size = 0;
|
|
map->capa = capa;
|
|
map->threshold = map->capa * map->factor / 100;
|
|
if (map->capa > 0 && map->threshold <= 0) map->threshold = 1;
|
|
|
|
map->hasher = hash_key;
|
|
map->comper = comp_key;
|
|
|
|
/*
|
|
map->copier[ASE_MAP_KEY] = ASE_NULL;
|
|
map->copier[ASE_MAP_VAL] = ASE_NULL;
|
|
map->freeer[ASE_MAP_KEY] = ASE_NULL;
|
|
map->freeer[ASE_MAP_VAL] = ASE_NULL;
|
|
map->keeper = ASE_NULL;
|
|
map->sizer = ASE_NULL;
|
|
*/
|
|
|
|
return map;
|
|
}
|
|
|
|
void ase_map_fini (map_t* map)
|
|
{
|
|
ase_map_clear (map);
|
|
ASE_MMGR_FREE (map->mmgr, map->bucket);
|
|
}
|
|
|
|
void* ase_map_getextension (map_t* map)
|
|
{
|
|
return map + 1;
|
|
}
|
|
|
|
mmgr_t* ase_map_getmmgr (map_t* map)
|
|
{
|
|
return map->mmgr;
|
|
}
|
|
|
|
void ase_map_setmmgr (map_t* map, mmgr_t* mmgr)
|
|
{
|
|
map->mmgr = mmgr;
|
|
}
|
|
|
|
size_t ase_map_getsize (map_t* map)
|
|
{
|
|
return map->size;
|
|
}
|
|
|
|
size_t ase_map_getcapa (map_t* map)
|
|
{
|
|
return map->capa;
|
|
}
|
|
|
|
int ase_map_getscale (map_t* map, int id)
|
|
{
|
|
ASE_ASSERTX (id == ASE_MAP_KEY || id == ASE_MAP_VAL,
|
|
"The ID should be either ASE_MAP_KEY or ASE_MAP_VAL");
|
|
return map->scale[id];
|
|
}
|
|
|
|
void ase_map_setscale (map_t* map, int id, int scale)
|
|
{
|
|
ASE_ASSERTX (id == ASE_MAP_KEY || id == ASE_MAP_VAL,
|
|
"The ID should be either ASE_MAP_KEY or ASE_MAP_VAL");
|
|
|
|
ASE_ASSERTX (scale > 0 && scale <= ASE_TYPE_MAX(ase_byte_t),
|
|
"The scale should be larger than 0 and less than or equal to the maximum value that the ase_byte_t type can hold");
|
|
|
|
if (scale <= 0) scale = 1;
|
|
if (scale > ASE_TYPE_MAX(ase_byte_t)) scale = ASE_TYPE_MAX(ase_byte_t);
|
|
|
|
map->scale[id] = scale;
|
|
}
|
|
|
|
copier_t ase_map_getcopier (map_t* map, int id)
|
|
{
|
|
ASE_ASSERTX (id == ASE_MAP_KEY || id == ASE_MAP_VAL,
|
|
"The ID should be either ASE_MAP_KEY or ASE_MAP_VAL");
|
|
return map->copier[id];
|
|
}
|
|
|
|
void ase_map_setcopier (map_t* map, int id, copier_t copier)
|
|
{
|
|
ASE_ASSERTX (id == ASE_MAP_KEY || id == ASE_MAP_VAL,
|
|
"The ID should be either ASE_MAP_KEY or ASE_MAP_VAL");
|
|
map->copier[id] = copier;
|
|
}
|
|
|
|
freeer_t ase_map_getfreeer (map_t* map, int id)
|
|
{
|
|
ASE_ASSERTX (id == ASE_MAP_KEY || id == ASE_MAP_VAL,
|
|
"The ID should be either ASE_MAP_KEY or ASE_MAP_VAL");
|
|
return map->freeer[id];
|
|
}
|
|
|
|
void ase_map_setfreeer (map_t* map, int id, freeer_t freeer)
|
|
{
|
|
ASE_ASSERTX (id == ASE_MAP_KEY || id == ASE_MAP_VAL,
|
|
"The ID should be either ASE_MAP_KEY or ASE_MAP_VAL");
|
|
map->freeer[id] = freeer;
|
|
}
|
|
|
|
hasher_t ase_map_gethasher (map_t* map)
|
|
{
|
|
return map->hasher;
|
|
}
|
|
|
|
void ase_map_sethasher (map_t* map, hasher_t hasher)
|
|
{
|
|
if (hasher == ASE_NULL) hasher = hash_key;
|
|
map->hasher = hasher;
|
|
}
|
|
|
|
comper_t ase_map_getcomper (map_t* map)
|
|
{
|
|
return map->comper;
|
|
}
|
|
|
|
void ase_map_setcomper (map_t* map, comper_t comper)
|
|
{
|
|
if (comper == ASE_NULL) comper = comp_key;
|
|
map->comper = comper;
|
|
}
|
|
|
|
keeper_t ase_map_getkeeper (map_t* map)
|
|
{
|
|
return map->keeper;
|
|
}
|
|
|
|
void ase_map_setkeeper (map_t* map, keeper_t keeper)
|
|
{
|
|
map->keeper = keeper;
|
|
}
|
|
|
|
sizer_t ase_map_getsizer (map_t* map)
|
|
{
|
|
return map->sizer;
|
|
}
|
|
|
|
void ase_map_setsizer (map_t* map, sizer_t sizer)
|
|
{
|
|
map->sizer = sizer;
|
|
}
|
|
|
|
pair_t* ase_map_search (map_t* map, const void* kptr, size_t klen)
|
|
{
|
|
pair_t* pair;
|
|
size_t hc;
|
|
|
|
hc = map->hasher(map,kptr,klen) % map->capa;
|
|
pair = map->bucket[hc];
|
|
|
|
while (pair != ASE_NULL)
|
|
{
|
|
if (map->comper (map, KPTR(pair), KLEN(pair), kptr, klen) == 0)
|
|
{
|
|
return pair;
|
|
}
|
|
|
|
pair = NEXT(pair);
|
|
}
|
|
|
|
return ASE_NULL;
|
|
}
|
|
|
|
|
|
int ase_map_put (
|
|
map_t* map, void* kptr, size_t klen,
|
|
void* vptr, size_t vlen, pair_t** px)
|
|
{
|
|
pair_t* pair, * p, * prev, * next;
|
|
size_t hc;
|
|
|
|
hc = map->hasher(map,kptr,klen) % map->capa;
|
|
pair = map->bucket[hc];
|
|
prev = ASE_NULL;
|
|
|
|
while (pair != ASE_NULL)
|
|
{
|
|
next = NEXT(pair);
|
|
|
|
if (map->comper (map, KPTR(pair), KLEN(pair), kptr, klen) == 0)
|
|
{
|
|
p = change_pair_val (map, pair, vptr, vlen);
|
|
if (p == ASE_NULL) return -1; /* change error */
|
|
if (p != pair)
|
|
{
|
|
/* the pair has been reallocated. relink it */
|
|
if (prev == ASE_NULL) map->bucket[hc] = p;
|
|
else NEXT(prev) = p;
|
|
NEXT(p) = next;
|
|
}
|
|
|
|
if (px != ASE_NULL) *px = p;
|
|
return 0; /* value changed for the existing key */
|
|
}
|
|
|
|
prev = pair;
|
|
pair = next;
|
|
}
|
|
|
|
if (map->threshold > 0 && map->size >= map->threshold)
|
|
{
|
|
if (reorganize(map) == 0) /* ignore the error */
|
|
{
|
|
hc = map->hasher(map,kptr,klen) % map->capa;
|
|
}
|
|
}
|
|
|
|
ASE_ASSERT (pair == ASE_NULL);
|
|
|
|
pair = alloc_pair (map, kptr, klen, vptr, vlen);
|
|
if (pair == ASE_NULL) return -1; /* error */
|
|
|
|
NEXT(pair) = map->bucket[hc];
|
|
map->bucket[hc] = pair;
|
|
map->size++;
|
|
|
|
if (px != ASE_NULL) *px = pair;
|
|
return 1; /* new key added */
|
|
}
|
|
|
|
pair_t* ase_map_upsert (
|
|
map_t* map, void* kptr, size_t klen, void* vptr, size_t vlen)
|
|
{
|
|
/* update if the key exists, otherwise insert a new pair */
|
|
int n;
|
|
pair_t* px;
|
|
|
|
n = ase_map_put (map, kptr, klen, vptr, vlen, &px);
|
|
if (n < 0) return ASE_NULL;
|
|
return px;
|
|
}
|
|
|
|
pair_t* ase_map_insert (map_t* map, void* kptr, size_t klen, void* vptr, size_t vlen)
|
|
{
|
|
pair_t* pair;
|
|
size_t hc;
|
|
|
|
hc = map->hasher(map,kptr,klen) % map->capa;
|
|
pair = map->bucket[hc];
|
|
|
|
while (pair != ASE_NULL)
|
|
{
|
|
if (map->comper (map, KPTR(pair), KLEN(pair), kptr, klen) == 0)
|
|
{
|
|
return ASE_NULL;
|
|
}
|
|
|
|
pair = NEXT(pair);
|
|
}
|
|
|
|
if (map->threshold > 0 && map->size >= map->threshold)
|
|
{
|
|
if (reorganize(map) == 0) /* ignore the error */
|
|
{
|
|
hc = map->hasher(map,kptr,klen) % map->capa;
|
|
}
|
|
}
|
|
|
|
ASE_ASSERT (pair == ASE_NULL);
|
|
|
|
pair = alloc_pair (map, kptr, klen, vptr, vlen);
|
|
if (pair == ASE_NULL) return ASE_NULL;
|
|
|
|
NEXT(pair) = map->bucket[hc];
|
|
map->bucket[hc] = pair;
|
|
map->size++;
|
|
|
|
return pair;
|
|
}
|
|
|
|
pair_t* ase_map_update (map_t* map, void* kptr, size_t klen, void* vptr, size_t vlen)
|
|
{
|
|
pair_t* pair, * p, * prev, * next;
|
|
size_t hc;
|
|
|
|
hc = map->hasher(map,kptr,klen) % map->capa;
|
|
pair = map->bucket[hc];
|
|
prev = ASE_NULL;
|
|
|
|
while (pair != ASE_NULL)
|
|
{
|
|
next = NEXT(pair);
|
|
|
|
if (map->comper (map, KPTR(pair), KLEN(pair), kptr, klen) == 0)
|
|
{
|
|
p = change_pair_val (map, pair, vptr, vlen);
|
|
|
|
if (p == ASE_NULL) return ASE_NULL; /* change error */
|
|
if (p != pair)
|
|
{
|
|
/* the pair has been reallocated. relink it */
|
|
if (prev == ASE_NULL) map->bucket[hc] = p;
|
|
else NEXT(prev) = p;
|
|
NEXT(p) = next;
|
|
}
|
|
|
|
return p; /* value changed for the existing key */
|
|
}
|
|
|
|
prev = pair;
|
|
pair = next;
|
|
}
|
|
|
|
return ASE_NULL;
|
|
}
|
|
|
|
int ase_map_delete (map_t* map, const void* kptr, size_t klen)
|
|
{
|
|
pair_t* pair, * prev;
|
|
size_t hc;
|
|
|
|
hc = map->hasher(map,kptr,klen) % map->capa;
|
|
pair = map->bucket[hc];
|
|
prev = ASE_NULL;
|
|
|
|
while (pair != ASE_NULL)
|
|
{
|
|
if (map->comper (map, KPTR(pair), KLEN(pair), kptr, klen) == 0)
|
|
{
|
|
if (prev == ASE_NULL)
|
|
map->bucket[hc] = NEXT(pair);
|
|
else NEXT(prev) = NEXT(pair);
|
|
|
|
free_pair (map, pair);
|
|
map->size--;
|
|
|
|
return 0;
|
|
}
|
|
|
|
prev = pair;
|
|
pair = NEXT(pair);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void ase_map_clear (map_t* map)
|
|
{
|
|
size_t i;
|
|
pair_t* pair, * next;
|
|
|
|
for (i = 0; i < map->capa; i++)
|
|
{
|
|
pair = map->bucket[i];
|
|
|
|
while (pair != ASE_NULL)
|
|
{
|
|
next = NEXT(pair);
|
|
free_pair (map, pair);
|
|
map->size--;
|
|
pair = next;
|
|
}
|
|
|
|
map->bucket[i] = ASE_NULL;
|
|
}
|
|
}
|
|
|
|
|
|
void ase_map_walk (map_t* map, walker_t walker, void* arg)
|
|
{
|
|
size_t i;
|
|
pair_t* pair, * next;
|
|
|
|
for (i = 0; i < map->capa; i++)
|
|
{
|
|
pair = map->bucket[i];
|
|
|
|
while (pair != ASE_NULL)
|
|
{
|
|
next = NEXT(pair);
|
|
if (walker(map, pair, arg) == ASE_MAP_WALK_STOP) return;
|
|
pair = next;
|
|
}
|
|
}
|
|
}
|
|
|
|
pair_t* ase_map_getfirstpair (map_t* map, size_t* buckno)
|
|
{
|
|
size_t i;
|
|
pair_t* pair;
|
|
|
|
for (i = 0; i < map->capa; i++)
|
|
{
|
|
pair = map->bucket[i];
|
|
if (pair != ASE_NULL)
|
|
{
|
|
*buckno = i;
|
|
return pair;
|
|
}
|
|
}
|
|
|
|
return ASE_NULL;
|
|
}
|
|
|
|
pair_t* ase_map_getnextpair (map_t* map, pair_t* pair, size_t* buckno)
|
|
{
|
|
size_t i;
|
|
pair_t* next;
|
|
|
|
next = NEXT(pair);
|
|
if (next != ASE_NULL)
|
|
{
|
|
/* no change in bucket number */
|
|
return next;
|
|
}
|
|
|
|
for (i = (*buckno)+1; i < map->capa; i++)
|
|
{
|
|
pair = map->bucket[i];
|
|
if (pair != ASE_NULL)
|
|
{
|
|
*buckno = i;
|
|
return pair;
|
|
}
|
|
}
|
|
|
|
return ASE_NULL;
|
|
}
|
|
|
|
static int reorganize (map_t* map)
|
|
{
|
|
size_t i, hc, new_capa;
|
|
pair_t** new_buck;
|
|
|
|
if (map->sizer)
|
|
{
|
|
new_capa = map->sizer (map, map->capa + 1);
|
|
|
|
/* if no change in capacity, return success
|
|
* without reorganization */
|
|
if (new_capa == map->capa) return 0;
|
|
|
|
/* adjust to 1 if the new capacity is not reasonable */
|
|
if (new_capa <= 0) new_capa = 1;
|
|
}
|
|
else
|
|
{
|
|
/* the bucket is doubled until it grows up to 65536 slots.
|
|
* once it has reached it, it grows by 65536 slots */
|
|
new_capa = (map->capa >= 65536)? (map->capa + 65536): (map->capa << 1);
|
|
}
|
|
|
|
new_buck = (pair_t**) ASE_MMGR_ALLOC (
|
|
map->mmgr, new_capa*SIZEOF(pair_t*));
|
|
if (new_buck == ASE_NULL)
|
|
{
|
|
/* reorganization is disabled once it fails */
|
|
map->threshold = 0;
|
|
return -1;
|
|
}
|
|
|
|
/*for (i = 0; i < new_capa; i++) new_buck[i] = ASE_NULL;*/
|
|
ASE_MEMSET (new_buck, 0, new_capa*SIZEOF(pair_t*));
|
|
|
|
for (i = 0; i < map->capa; i++)
|
|
{
|
|
pair_t* pair = map->bucket[i];
|
|
|
|
while (pair != ASE_NULL)
|
|
{
|
|
pair_t* next = NEXT(pair);
|
|
|
|
hc = map->hasher (map,
|
|
KPTR(pair),
|
|
KLEN(pair)) % new_capa;
|
|
|
|
NEXT(pair) = new_buck[hc];
|
|
new_buck[hc] = pair;
|
|
|
|
pair = next;
|
|
}
|
|
}
|
|
|
|
ASE_MMGR_FREE (map->mmgr, map->bucket);
|
|
map->bucket = new_buck;
|
|
map->capa = new_capa;
|
|
map->threshold = map->capa * map->factor / 100;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void* ase_map_copyinline (map_t* map, void* dptr, size_t dlen)
|
|
{
|
|
/* this is a dummy copier */
|
|
return ASE_NULL;
|
|
}
|