|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- #include "strset.h"
-
- #include <string.h>
- #include <stdio.h>
-
- // sdbm from http://www.cse.yorku.ca/~oz/hash.html;
- // there are probably better algorithms out there
- static size_t hash(const void *ptr) {
- const unsigned char *str = ptr;
- size_t h = 0;
- int c;
-
- while ((c = *(str++)) != 0) {
- h = c + (h << 6) + (h << 16) - h;
- }
-
- return h;
- }
-
- void grow(struct l2_strset *set) {
- struct l2_strset old = *set;
- set->len = 0;
- set->size *= 2;
- set->mask = (set->mask << 1) | set->mask;
-
- set->keys = calloc(set->size, sizeof(*set->keys));
- set->vals = calloc(set->size, sizeof(*set->vals));
-
- for (size_t i = 0; i < old.size; ++i) {
- char *oldkey = old.keys[i];
- if (oldkey == NULL) {
- continue;
- }
-
- size_t h = hash(old.keys[i]);
- for (size_t j = 0; ; ++j) {
- size_t index = (h + j) & set->mask;
- char *k = set->keys[index];
- if (k != NULL) {
- continue;
- }
-
- set->keys[index] = oldkey;
- set->vals[index] = old.vals[i];
- break;
- }
- }
-
- free(old.keys);
- free(old.vals);
- }
-
- void l2_strset_init(struct l2_strset *set) {
- set->next = 1;
- set->len = 0;
- set->size = 16;
- set->mask = 0x0f;
- set->keys = calloc(set->size, sizeof(*set->keys));
- set->vals = calloc(set->size, sizeof(*set->vals));
- }
-
- void l2_strset_free(struct l2_strset *set) {
- for (size_t i = 0; i < set->size; ++i) {
- free(set->keys[i]);
- }
-
- free(set->keys);
- free(set->vals);
- }
-
- size_t l2_strset_put(struct l2_strset *set, char **str) {
- if (set->len >= set->size / 2) {
- grow(set);
- }
-
- size_t h = hash(*str);
- for (size_t i = 0; ; ++i) {
- size_t index = (h + i) & set->mask;
- char *k = set->keys[index];
- if (k == NULL) {
- set->keys[index] = *str;
- set->vals[index] = set->next++;
- set->len += 1;
- *str = NULL;
- return set->vals[index];
- } else if (strcmp(*str, k) == 0) {
- free(*str);
- *str = NULL;
- return set->vals[index];
- }
- }
- }
-
- size_t l2_strset_put_copy(struct l2_strset *set, const char *str) {
- if (set->len >= set->size / 2) {
- grow(set);
- }
-
- size_t h = hash(str);
- for (size_t i = 0; ; ++i) {
- size_t index = (h + i) & set->mask;
- char *k = set->keys[index];
- if (k == NULL) {
- set->keys[index] = strdup(str);
- set->vals[index] = set->next++;
- set->len += 1;
- return set->vals[index];
- } else if (strcmp(str, k) == 0) {
- return set->vals[index];
- }
- }
- }
-
- size_t l2_strset_get(struct l2_strset *set, const char *str) {
- size_t h = hash(str);
- for (size_t i = 0; ; ++i) {
- size_t index = (h + i) & set->mask;
- char *k = set->keys[index];
- if (k == NULL) {
- return 0;
- } else if (strcmp(str, k) == 0) {
- return set->vals[index];
- }
- }
- }
|