Skip to content

Commit

Permalink
breaking change to stringmap
Browse files Browse the repository at this point in the history
  • Loading branch information
wmorgan committed Mar 27, 2012
1 parent 3ee4d6d commit 540ef7b
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 67 deletions.
117 changes: 61 additions & 56 deletions stringmap.c
Expand Up @@ -33,20 +33,15 @@ static inline int string_equals(const char* a, const char* b) {
return strcmp(a, b) == 0;
}

// set flags, keys and vals to correct locations based on h->n_buckets
void stringmap_setup(stringmap* h, stringpool* p) {
h->pool = p;
h->flags = (uint32_t*)h->boundary;
h->keys = (uint32_t*)((uint32_t*)h->boundary + ((h->n_buckets >> 4) + 1));
}
#define STRINGMAP_FLAGS(h) ((uint32_t*)(h)->boundary)
#define STRINGMAP_KEYS(h) ((uint32_t*)((uint32_t*)(h)->boundary + (((h)->n_buckets >> 4) + 1)))

void stringmap_init(stringmap* h, stringpool* p) {
void stringmap_init(stringmap* h) {
h->n_buckets_idx = INITIAL_N_BUCKETS_IDX;
h->n_buckets = prime_list[h->n_buckets_idx];
h->upper_bound = (uint32_t)(h->n_buckets * HASH_UPPER + 0.5);
h->size = h->n_occupied = 0;
stringmap_setup(h, p);
memset(h->flags, 0xaa, ((h->n_buckets>>4) + 1) * sizeof(uint32_t));
memset(STRINGMAP_FLAGS(h), 0xaa, ((h->n_buckets>>4) + 1) * sizeof(uint32_t));
}

/*
Expand All @@ -66,74 +61,80 @@ static void kh_clear_##name(kh_##name##_t *h) {
}
*/

uint32_t stringmap_get(stringmap *h, const char* key) {
uint32_t stringmap_get(stringmap *h, stringpool* pool, const char* key) {
uint32_t* flags = STRINGMAP_FLAGS(h);
uint32_t* keys = STRINGMAP_KEYS(h);

if(h->n_buckets) {
uint32_t inc, k, i, last;
k = string_hash(key); i = k % h->n_buckets;
inc = 1 + k % (h->n_buckets - 1); last = i;
while (!isempty(h->flags, i) && (isdel(h->flags, i) || !string_equals(stringpool_lookup(h->pool, h->keys[i]), key))) {
while (!isempty(flags, i) && (isdel(flags, i) || !string_equals(stringpool_lookup(pool, keys[i]), key))) {
if (i + inc >= h->n_buckets) i = i + inc - h->n_buckets;
else i += inc;
if (i == last) return h->n_buckets;
}
return iseither(h->flags, i)? h->n_buckets : i;
return iseither(flags, i)? h->n_buckets : i;
}
else return 0;
}

wp_error* stringmap_bump_size(stringmap *h) {
wp_error* stringmap_bump_size(stringmap *h, stringpool* pool) {
DEBUG("bumping size for string hash at %p with size %u and boundary %p", h, stringmap_size(h), h->boundary);

if(h->n_buckets_idx >= (HASH_PRIME_SIZE - 1)) RAISE_ERROR("stringmap can't be this big");

h->n_buckets_idx++;
uint32_t new_n_buckets = prime_list[h->n_buckets_idx];

// first make a backup of the oldflags
size_t oldflagsize = ((h->n_buckets >> 4) + 1) * sizeof(uint32_t);
uint32_t* oldflags = malloc(oldflagsize);
memcpy(oldflags, h->flags, oldflagsize);
// get pointers to the old locations
uint32_t* oldkeys = STRINGMAP_KEYS(h);
uint32_t* oldflags = STRINGMAP_FLAGS(h);

// keep pointers to the old locations
uint32_t* oldkeys = h->keys;
// make a backup of the old flags in a separate memory region
size_t flagbaksize = ((h->n_buckets >> 4) + 1) * sizeof(uint32_t);
uint32_t* flagbaks = malloc(flagbaksize);
memcpy(flagbaks, oldflags, flagbaksize);

// set pointers to the new locations
h->keys = (uint32_t*)((uint32_t*)h->boundary + ((new_n_buckets >> 4) + 1));
// get a pointer pointers to the new locations
//h->keys = (uint32_t*)((uint32_t*)h->boundary + ((new_n_buckets >> 4) + 1));
uint32_t* newflags = (uint32_t*)h->boundary; // unchanged, actually
uint32_t* newkeys = (uint32_t*)((uint32_t*)h->boundary + ((new_n_buckets >> 4) + 1));

// move the keys
memmove(h->keys, oldkeys, h->n_buckets * sizeof(uint32_t));
memmove(newkeys, oldkeys, h->n_buckets * sizeof(uint32_t));

// clear the new flags
memset(h->flags, 0xaa, ((new_n_buckets>>4) + 1) * sizeof(uint32_t));
memset(STRINGMAP_FLAGS(h), 0xaa, ((new_n_buckets>>4) + 1) * sizeof(uint32_t));

// do the complicated stuff from khash.h
for (unsigned int j = 0; j != h->n_buckets; ++j) {
if (iseither(oldflags, j) == 0) {
uint32_t key = h->keys[j];
set_isdel_true(oldflags, j);
if (iseither(flagbaks, j) == 0) {
uint32_t key = newkeys[j];
set_isdel_true(flagbaks, j);
while (1) {
uint32_t inc, k, i;
k = string_hash(stringpool_lookup(h->pool, key));
k = string_hash(stringpool_lookup(pool, key));
i = k % new_n_buckets;
inc = 1 + k % (new_n_buckets - 1);
while (!isempty(h->flags, i)) {
while (!isempty(newflags, i)) {
if (i + inc >= new_n_buckets) i = i + inc - new_n_buckets;
else i += inc;
}
set_isempty_false(h->flags, i);
if (i < h->n_buckets && iseither(oldflags, i) == 0) {
{ uint32_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; }
set_isdel_true(oldflags, i);
set_isempty_false(newflags, i);
if (i < h->n_buckets && iseither(flagbaks, i) == 0) {
{ uint32_t tmp = newkeys[i]; newkeys[i] = key; key = tmp; }
set_isdel_true(flagbaks, i);
} else {
h->keys[i] = key;
newkeys[i] = key;
break;
}
}
}
}

free(oldflags);
h->n_buckets = new_n_buckets;
free(flagbaks);
h->n_buckets = new_n_buckets; // STRINGMAP_KEYS now works
h->n_occupied = h->size;
h->upper_bound = (uint32_t)(h->n_buckets * HASH_UPPER + 0.5);

Expand All @@ -144,8 +145,10 @@ wp_error* stringmap_bump_size(stringmap *h) {
return NO_ERROR;
}

uint32_t stringmap_put(stringmap *h, const char* key, int *ret) {
uint32_t stringmap_put(stringmap *h, stringpool* pool, const char* key, int *ret) {
uint32_t x;
uint32_t* flags = STRINGMAP_FLAGS(h);
uint32_t* keys = STRINGMAP_KEYS(h);

{
#ifdef DEBUGOUTPUT
Expand All @@ -154,27 +157,27 @@ int num_loops = 0;
uint32_t inc, k, i, site, last;
x = site = h->n_buckets; k = string_hash(key); i = k % h->n_buckets;
//DEBUG("asked to hash '%s'. initial hash is %u => %u and n_occupied is %u", key, k, i, h->n_occupied);
if (isempty(h->flags, i)) x = i;
if (isempty(flags, i)) x = i;
else {
inc = 1 + k % (h->n_buckets - 1); last = i;
while (!isempty(h->flags, i) && (isdel(h->flags, i) || !string_equals(stringpool_lookup(h->pool, h->keys[i]), key))) {
while (!isempty(flags, i) && (isdel(flags, i) || !string_equals(stringpool_lookup(pool, keys[i]), key))) {
#ifdef DEBUGOUTPUT
num_loops++;
#endif
if (isdel(h->flags, i)) site = i;
if (isdel(flags, i)) site = i;
if (i + inc >= h->n_buckets) i = i + inc - h->n_buckets;
else i += inc;
if (i == last) { x = site; break; }
}
if ((x == h->n_buckets) && (i == last)) { // out of space
if(!string_equals(stringpool_lookup(h->pool, h->keys[i]), key)) {
if(!string_equals(stringpool_lookup(pool, keys[i]), key)) {
DEBUG("out of space!");
*ret = -1;
return x;
}
}
if (x == h->n_buckets) { // didn't find it on the first try
if (isempty(h->flags, i) && site != h->n_buckets) x = site;
if (isempty(flags, i) && site != h->n_buckets) x = site;
else x = i;
}
}
Expand All @@ -185,15 +188,15 @@ num_loops++;
//DEBUG("for pos %u, isempty? %d and isdel %d", x, isempty(h->flags, x), isdel(h->flags, x));

uint32_t idx;
if(isempty(h->flags, x) || isdel(h->flags, x)) {
idx = stringpool_add(h->pool, key);
if(isempty(flags, x) || isdel(flags, x)) {
idx = stringpool_add(pool, key);
if(idx == (uint32_t)-1) {
*ret = -2;
return x;
}
if (isempty(h->flags, x)) ++h->n_occupied;
h->keys[x] = idx;
set_isboth_false(h->flags, x);
if (isempty(flags, x)) ++h->n_occupied;
keys[x] = idx;
set_isboth_false(flags, x);
++h->size;
*ret = 1;
}
Expand All @@ -203,8 +206,9 @@ num_loops++;
}

void stringmap_del(stringmap *h, uint32_t x) {
if (x != h->n_buckets && !iseither(h->flags, x)) {
set_isdel_true(h->flags, x);
uint32_t* flags = STRINGMAP_FLAGS(h);
if (x != h->n_buckets && !iseither(flags, x)) {
set_isdel_true(flags, x);
--h->size;
}
}
Expand Down Expand Up @@ -255,24 +259,25 @@ uint32_t stringmap_next_size(stringmap* h) {
return size(prime_list[next_idx]);
}

const char* stringmap_int_to_string(stringmap* h, uint32_t i) {
return stringpool_lookup(h->pool, i);
const char* stringmap_int_to_string(stringmap* h, stringpool* p, uint32_t i) {
(void)h;
return stringpool_lookup(p, i);
}

// returns -1 if not found
uint32_t stringmap_string_to_int(stringmap* h, const char* s) {
uint32_t idx = stringmap_get(h, s);
uint32_t stringmap_string_to_int(stringmap* h, stringpool* pool, const char* s) {
uint32_t idx = stringmap_get(h, pool, s);
if(idx == h->n_buckets) return (uint32_t)-1; // not there
return h->keys[idx];
return STRINGMAP_KEYS(h)[idx];
}

wp_error* stringmap_add(stringmap *h, const char* s, uint32_t* id) {
wp_error* stringmap_add(stringmap *h, stringpool* pool, const char* s, uint32_t* id) {
int status;
uint32_t idx = stringmap_put(h, s, &status);
uint32_t idx = stringmap_put(h, pool, s, &status);
if(status == -1) RAISE_ERROR("out of space in hash put");
if(status == -2) RAISE_ERROR("out of space in pool put");

*id = h->keys[idx];
*id = STRINGMAP_KEYS(h)[idx];

return NO_ERROR;
}
16 changes: 5 additions & 11 deletions stringmap.h
Expand Up @@ -35,9 +35,6 @@
typedef struct stringmap {
uint8_t n_buckets_idx;
uint32_t n_buckets, size, n_occupied, upper_bound;
uint32_t *flags;
uint32_t *keys;
stringpool* pool;
uint8_t boundary[];
// in memory at this point
// ((n_buckets >> 4) + 1) uint32_t's for the flags
Expand All @@ -47,21 +44,18 @@ typedef struct stringmap {
// API methods

// public: write a new stringmap to memory
void stringmap_init(stringmap* h, stringpool* p);

// public: set up an existing stringmap in memory
void stringmap_setup(stringmap* h, stringpool* p);
void stringmap_init(stringmap* h);

// public: add a string. sets id to its id. dupes are fine; will just set the
// id correctly.
wp_error* stringmap_add(stringmap *h, const char* s, uint32_t* id) RAISES_ERROR;
wp_error* stringmap_add(stringmap *h, stringpool* p, const char* s, uint32_t* id) RAISES_ERROR;

// public: get the int value given a string. returns (uint32_t)-1 if not found.
uint32_t stringmap_string_to_int(stringmap* h, const char* s);
uint32_t stringmap_string_to_int(stringmap* h, stringpool* pool, const char* s);

// public: get the string value given an int. returns corrupt data if the int
// is invalid.
const char* stringmap_int_to_string(stringmap* h, uint32_t i);
const char* stringmap_int_to_string(stringmap* h, stringpool* p, uint32_t i);

// public: returns the byte size of the stringmap
uint32_t stringmap_size(stringmap* h);
Expand All @@ -76,6 +70,6 @@ uint32_t stringmap_next_size(stringmap* h);
int stringmap_needs_bump(stringmap* h);

// public: increases the size of the stringmap
wp_error* stringmap_bump_size(stringmap *h) RAISES_ERROR;
wp_error* stringmap_bump_size(stringmap *h, stringpool* pool) RAISES_ERROR;

#endif

0 comments on commit 540ef7b

Please sign in to comment.