+
+ht_iter_t *ht_iter_start (hashtable_t *ht, void *key) {
+ hti_t *hti = ht->hti;
+ int rcount;
+ do {
+ while (((volatile hti_t *)hti)->next != NULL) {
+ do { } while (hti_help_copy(hti) != TRUE);
+ hti = hti->next;
+ }
+
+ int old = hti->references;
+ do {
+ rcount = old;
+ if (rcount != -1) {
+ old = SYNC_CAS(&hti->references, rcount, rcount + 1);
+ }
+ } while (rcount != old);
+ } while (rcount == -1);
+
+ ht_iter_t *iter = nbd_malloc(sizeof(ht_iter_t));
+ iter->hti = hti;
+ iter->idx = -1;
+
+ return iter;
+}
+
+ht_iter_t *ht_iter_next (ht_iter_t *iter) {
+ volatile entry_t *ent;
+ uint64_t key;
+ uint64_t val;
+ uint64_t table_size = (1 << iter->hti->scale);
+ do {
+ if (++iter->idx == table_size) {
+ ht_iter_free(iter);
+ return NULL;
+ }
+ ent = &iter->hti->table[++iter->idx];
+ key = ent->key;
+ val = ent->val;
+
+ } while (key == DOES_NOT_EXIST || val == DOES_NOT_EXIST || val == TOMBSTONE);
+
+ iter->key = key;
+ if (val == COPIED_VALUE) {
+ uint32_t hash = (iter->hti->ht->key_type == NULL)
+ ? murmur32_8b(key)
+ : iter->hti->ht->key_type->hash((void *)key);
+ iter->val = hti_get(iter->hti->next, (void *)ent->key, hash);
+ } else {
+ iter->val = val;
+ }
+
+ return iter;
+}
+
+uint64_t ht_iter_val (ht_iter_t *iter) {
+ return iter->val;
+}
+
+uint64_t ht_iter_key (ht_iter_t *iter) {
+ return iter->key;
+}
+
+void ht_iter_free (ht_iter_t *iter) {
+ SYNC_ADD(&iter->hti->references, -1);
+}
+