-#define ston_dht_size(_HT) (ston_ht_size(_HT))
-#define ston_dht_rows(_HT) (ston_ht_rows(_HT))
-#define ston_dht_cols(_HT) (ston_ht_cols(_HT))
-#define ston_dht_keyrow(_HT,_KEY) (ston_ht_keyrow(_HT,_KEY))
-#define ston_dht_start(_HT) (_HT->ht_pages[0])
-#define ston_dht32_start(_HT) ((_uint32*)ston_dht_start(_HT))
-ston_dht ston_dht32_create(uint16_t,size_t,void*(*)(size_t));
-uint32_t* ston_dht32_row(ston_dht,uint32_t);
-#define ston_dht32_col(_HT,_KEY,_COL) (ston_dht32_row(_HT,_KEY) + _COL)
-uint32_t ston_dht32_insert(ston_dht,uint32_t,uint16_t,uint32_t);
-#define ston_dht32_insertx(_HT,_KEY,_COL,_VAL) *ston_dht32_col(_HT,_KEY,_COL) = _VAL
+STON_FUNC
+ston_dht ston_dht_new(uint16_t,uint8_t,void*(*)(size_t),void(*)(void*));
+STON_FUNC
+ston_dht ston_dht_free(ston_dht);
+STON_FUNC
+void* ston_dht_val(ston_dht,void*);
+STON_FUNC_STATIC
+STON_FUNC_NOINLINE
+void ston_dht_free_bucket(ston_dht,void*);
+STON_FUNC
+void ston_dht_iterate(ston_dht,void(*)(void*,void*,void*),void*);
+STON_FUNC_STATIC
+STON_FUNC_NOINLINE
+void ston_dht_iterate_r(ston_dht,void*);
+
+// Compatibility macros
+#define ston_dht32_new(_COL,_ALOC,_FRE) (ston_dht_new(4 * _COL, 4, _ALOC, _FRE))
+#define ston_dht32_row(_HT,_K) ((uint32_t*)((uint8_t*)ston_dht_val(_HT,&(_K)) - 4))
+#define ston_dht32_insertx(_HT,_K,_VP,_OFFS,_N) \
+ memcpy((uint32_t*)((uint8_t*)ston_dht_val(_HT,&(_K)) + ((_OFFS - 1) * 4)),_VP,_N * 4)
+
+/* Creates a new bucketted hash table, provided a memory allocation function
+ that takes a single size_t bytes, a memory free function, a column count, and
+ a row count which determines the size of the buckets.
+*/
+STON_FUNC
+ston_dht ston_dht_new
+( uint16_t val_bytes,
+ uint8_t key_bytes,
+ void* (*ht_alloc)(size_t),
+ void (*ht_free)(void*)
+)
+{ ston_dht ht = (ston_dht) ht_alloc(sizeof(struct ston_dht_t));
+ if (ht != NULL)
+ { ht->header.val_bytes = val_bytes;
+ ht->header.key_bytes = key_bytes;
+ ht->rowsize = sizeof(void*) + key_bytes + val_bytes;
+ ht->bucketsize = ht->rowsize * 0x100;
+ ht->ht_alloc = ht_alloc;
+ ht->ht_free = ht_free;
+ ht->bucket_root = ht_alloc(ht->bucketsize);
+ if (ht->bucket_root == NULL && ht_free != NULL)
+ ht_free(ht);
+ else
+ memset((ht->bucket_root), 0, ht->bucketsize);
+ }
+ return ht;
+}
+
+
+/* Returns a pointer to the value in the hashtable matching the provided key,
+ inserting if not found, or NULL if a memory error occurs */
+STON_FUNC
+void* ston_dht_val
+( struct ston_dht_t* ht,
+ void* key
+)
+{ size_t key_bytes = ht->header.key_bytes;
+ uint8_t* key_byte = (uint8_t*)key;
+ uint8_t* bucket = (uint8_t*)ht->bucket_root;
+ uint8_t** bucketp;
+ uint8_t* row,* a,* b;
+ uint8_t a_not_empty;
+ size_t i;
+ next_row:
+ row = bucket + (ht->rowsize * (*key_byte));
+ a = row + sizeof(void*);
+ b = (uint8_t*)key;
+ a_not_empty = 0;
+ for (i = 0; i < key_bytes; i++)
+ { a_not_empty |= a[i];
+ if (a_not_empty && a[i] != b[i])
+ goto next_bucket;
+ }
+ if (!a_not_empty)
+ memcpy(row + sizeof(void*),key,key_bytes);
+ goto done;
+ next_bucket:
+ key_byte++;
+ bucketp = (uint8_t**)row;
+ if (*bucketp == NULL)
+ { if ((*bucketp = ht->ht_alloc(ht->bucketsize)) == NULL)
+ return NULL;
+ else
+ memset(*bucketp,0,ht->bucketsize);
+ }
+ bucket = *bucketp;
+ goto next_row;
+ done:
+ return (void*) row + sizeof(void*) + key_bytes;
+}