/*
- * Copyright (C) 2012
+ * Copyright (C) 2012, 2013
* Dale Weiler
* Wolfgang Bumiller
*
mem_d(ht);
}
+/*
+ * A basic implementation of a hash-set. Unlike a hashtable, a hash
+ * set doesn't maintain key-value pairs. It simply maintains a key
+ * that can be set, removed, and checked for.
+ *
+ * See EXPOSED interface comment below
+ */
+#define GMQCC_HASHSET_PRIME0 0x0049
+#define GMQCC_HASHSET_PRIME1 0x1391
+
+static int util_hsput(hash_set_t *set, void *item) {
+ size_t hash = (size_t)item; /* shouldn't drop the bits */
+ size_t iter;
+
+ /* a == 0 || a == 1 */
+ if (hash >> 1)
+ return -1;
+
+ iter = set->mask & (GMQCC_HASHSET_PRIME0 * hash);
+
+ /* while (set->items[iter] != 0 && set->items[iter] != 1) */
+ while (!(set->items[iter] >> 1)) {
+ if (set->items[iter] == hash)
+ return 0;
+
+ iter = set->mask & (iter + GMQCC_HASHSET_PRIME1);
+ }
+
+ set->total ++;
+ set->items[iter] = hash;
+
+ return 1;
+}
+
+static void util_hsupdate(hash_set_t *set) {
+ size_t *old;
+ size_t end;
+ size_t itr;
+
+ /* time to rehash? */
+ if ((float)set->total >= (size_t)((double)set->capacity * 0.85)) {
+ old = set->items;
+ end = set->capacity;
+
+ set->bits ++;
+ set->capacity = (size_t)(1 << set->bits);
+ set->mask = set->capacity - 1;
+ set->items = mem_a(set->capacity * sizeof(size_t));
+ set->total = 0;
+
+ /*assert(set->items);*/
+
+ /*
+ * this shouldn't be slow? if so unroll it a little perhaps
+ * (shouldn't be though)
+ */
+ for (itr = 0; itr < end; itr++)
+ util_hsput(set, (void*)old[itr]);
+
+ mem_d(old);
+ }
+}
+
+/*
+ * EXPOSED interface: all of these functions are exposed to the outside
+ * for use. The stuff above is static because it's the "internal" mechanics
+ * for syncronizing the set for updating, and putting data into the set.
+ */
+int util_hsadd(hash_set_t *set, void *item) {
+ int run = util_hsput(set, item); /* inlined */
+ util_hsupdate(set);
+
+ return run;
+}
+
+/* remove item in set */
+int util_hsrem(hash_set_t *set, void *item) {
+ size_t hash = (size_t)item;
+ size_t iter = set->mask & (GMQCC_HASHSET_PRIME0 * hash);
+
+ while (set->items[iter]) {
+ if (set->items[iter] == hash) {
+ set->items[iter] = 1;
+ set->total --;
+
+ return 1;
+ }
+ iter = set->mask & (iter + GMQCC_HASHSET_PRIME1);
+ }
+
+ return 0;
+}
+
+/* check if item is set */
+int util_hshas(hash_set_t *set, void *item) {
+ size_t hash = (size_t)item;
+ size_t iter = set->mask & (GMQCC_HASHSET_PRIME0 * hash);
+
+ while (set->items[iter]) {
+ if (set->items[iter] == hash)
+ return 1;
+
+ iter = set->mask & (iter + GMQCC_HASHSET_PRIME1);
+ }
+
+ return 0;
+}
+
+hash_set_t *util_hsnew(void) {
+ hash_set_t *set;
+
+ if (!(set = mem_a(sizeof(hash_set_t))))
+ return NULL;
+
+ set->bits = 3;
+ set->total = 0;
+ set->capacity = (size_t)(1 << set->bits);
+ set->mask = set->capacity - 1;
+ set->items = mem_a(set->capacity * sizeof(size_t));
+
+ if (!set->items) {
+ util_hsdel(set);
+ return NULL;
+ }
+
+ return set;
+}
+
+void util_hsdel(hash_set_t *set) {
+ if (!set) return;
+
+ if (set->items)
+ mem_d(set->items);
+
+ mem_d(set);
+}
+#undef GMQCC_HASHSET_PRIME0
+#undef GMQCC_HASHSET_PRIME1
+
+
/*
* Portable implementation of vasprintf/asprintf. Assumes vsnprintf
* exists, otherwise compiler error.