int remove_node(marked_ptr_t* head, hash_key_t key) { marked_ptr_t cur; marked_ptr_t* prev; while(1) { if(lf_table_find(head, key, &prev, &cur) == NULL) { return 0; } if (CAS(prev, CONSTRUCT(0, cur), CONSTRUCT(1, cur)) != CONSTRUCT(0, cur)) {continue;} if (CAS(prev, CONSTRUCT(1, cur), PTR_OF(cur)->next) == CONSTRUCT(1, cur)) { free(PTR_OF(cur)); // problem here } else { lf_table_find(head, key, NULL, NULL); // use find to remove the marked node } return 1; } }
void* lf_table_put_if_absent(LF_HashTable* table, void* key, void* value) { marked_ptr_t* prev; marked_ptr_t cur; marked_ptr_t new_node; uint32_t index; index = HASH(key); while(1) { if(lf_table_find(&table->buckets[index], CONSTRUCT(0, key), &prev, &cur) != NULL) { return PTR_OF(cur)->value; } new_node = CONSTRUCT(0, malloc(sizeof(Node))); PTR_OF(new_node)->value = value; PTR_OF(new_node)->key = CONSTRUCT(0, key); PTR_OF(new_node)->next = *prev; if(CAS(prev, cur, CONSTRUCT(0, new_node)) == cur) { break; } } INCR(&table->size, 1); return NULL; }
static list_entry *qt_dictionary_iterator_next_element(qt_dictionary_iterator *it) { if((it == NULL) || (it->dict == NULL)) { return ERROR; } qt_dictionary *h = it->dict; if(h->count == 0) { it->bkt = 1; return NULL; } if(it->bkt == -1) { int csize = h->size, bucket; for(bucket = 0; bucket < csize; bucket++) if (h->B[bucket] != UNINITIALIZED) { it->bkt = 1; it->crt = PTR_OF(h->B[bucket]); return it->crt; } } if(it->crt == UNINITIALIZED) { return NULL; } it->crt = PTR_OF(it->crt->next); return it->crt; }
static int qt_lf_list_delete(marked_ptr_t *head, so_key_t hashed_key, qt_key_t key, qt_dict_key_equals_f op_equals, qt_dict_cleanup_f cleanup) { while (1) { marked_ptr_t *lprev; marked_ptr_t lcur; marked_ptr_t lnext; if (qt_lf_list_find(head, hashed_key, key, &lprev, &lcur, &lnext, op_equals) == NULL) { qthread_debug(ALWAYS_OUTPUT, "### inside delete - return 0\n"); return 0; } if (qthread_cas_ptr(&PTR_OF(lcur)->next, (void*)CONSTRUCT(0, lnext), (void*)CONSTRUCT(1, lnext)) != (void *)CONSTRUCT(0, lnext)) { qthread_debug(ALWAYS_OUTPUT, "### inside delete - cas failed continue\n"); continue; } if (qthread_cas(lprev, CONSTRUCT(0, lcur), CONSTRUCT(0, lnext)) == CONSTRUCT(0, lcur)) { if (cleanup != NULL) { cleanup(PTR_OF(lcur)->key, NULL); } qpool_free(hash_entry_pool, PTR_OF(lcur)); } else { qt_lf_list_find(head, hashed_key, key, NULL, NULL, NULL, op_equals); // needs to set cur/prev/next } return 1; } }
static void prepare_for_dump_l(L_NODE *l_root, int idx, void **data_v, int *bal_v) { data_v[idx] = l_root->data; if (IS_DEEPER(l_root->left)) { bal_v[idx] = IS_DEEPER(l_root->right) ? -2 : -1; } else { bal_v[idx] = IS_DEEPER(l_root->right) ? 1 : 0; } if (l_root->left) prepare_for_dump_l(PTR_OF(l_root->left ), idx << 1 , data_v, bal_v); if (l_root->right) prepare_for_dump_l(PTR_OF(l_root->right), idx << 1 | 1, data_v, bal_v); }
/** * Insert node "node" in the list starting at position "head". * Set "ocur" to be the item with the same key if it exists * or the item which follows if the node was added successfully. * Set crt_node to point to the current node with key = "node->key" * Return 0 if item existed and 1 if it was inserted */ static int qt_lf_list_insert(marked_ptr_t *head, hash_entry *node, marked_ptr_t *ocur, hash_entry **crt_node, qt_dict_key_equals_f op_equals) { so_key_t hashed_key = node->hashed_key; qt_key_t key = node->key; while (1) { marked_ptr_t *lprev; marked_ptr_t cur; if (qt_lf_list_find(head, hashed_key, key, &lprev, &cur, NULL, op_equals) != NULL) { // needs to set cur/prev if (ocur) { *ocur = cur; } if (crt_node) { *crt_node = PTR_OF(cur); } return 0; } node->next = (hash_entry *)CONSTRUCT(0, cur); if (qthread_cas(lprev, (marked_ptr_t)(uintptr_t)node->next, CONSTRUCT(0, node)) == CONSTRUCT(0, cur)) { if (ocur) { *ocur = cur; } if (crt_node) { *crt_node = node; } return 1; } } }
static int depth_l(L_NODE *root, bool check) { int depth_left, depth_right; depth_left = root->left ? depth_l(PTR_OF(root->left ), check) : 0; depth_right = root->right ? depth_l(PTR_OF(root->right), check) : 0; if (check) { assert(depth_left <= depth_right + 1); assert(depth_right <= depth_left + 1); if (depth_left > depth_right) { assert( IS_DEEPER(root->left )); assert( !IS_DEEPER(root->right)); } else if (depth_left < depth_right) { assert( !IS_DEEPER(root->left )); assert( IS_DEEPER(root->right)); } else { assert( !IS_DEEPER(root->left )); assert( !IS_DEEPER(root->right)); } } return (depth_left > depth_right ? depth_left : depth_right) + 1; }
void avl_dump_w_ctx(TREE *tree, void (*callback)(void *data, int idx, int bal, void *context), void *context) { if (tree->root) { int max_depth = 0; int idx, idx_top; void **data_v; int *bal_v; if (IS_X(tree)) max_depth = depth_x(PTR_OF(tree->x_root), false); else max_depth = depth_l(PTR_OF(tree->l_root), false); idx_top = 1 << max_depth; data_v = calloc(idx_top, sizeof(void*)); bal_v = calloc(idx_top, sizeof(int)); if (IS_X(tree)) prepare_for_dump_x(PTR_OF(tree->x_root), 1, data_v, bal_v); else prepare_for_dump_l(PTR_OF(tree->l_root), 1, data_v, bal_v); for (idx = 1; idx < idx_top; idx++) { (*callback)(data_v[idx], idx, bal_v[idx], context); } free(data_v); free(bal_v); } else { (*callback)(NULL, 1, 0, context); } }
// old public method static inline void qt_hash_destroy(qt_hash h) { marked_ptr_t cursor; assert(h); assert(h->B); cursor = h->B[0]; while (PTR_OF(cursor) != NULL) { marked_ptr_t tmp = cursor; assert(MARK_OF(tmp) == 0); cursor = (marked_ptr_t)((PTR_OF(cursor)->next)); if (h->op_cleanup && ((PTR_OF(tmp)->key || PTR_OF(tmp)->value))) { // only call the cleanup function on non-place-holders h->op_cleanup(PTR_OF(tmp)->key, PTR_OF(tmp)->value); } qpool_free(hash_entry_pool, PTR_OF(tmp)); } FREE(h->B, hard_max_buckets * sizeof(marked_ptr_t)); FREE(h, sizeof(qt_hash)); }
static void initialize_bucket(qt_hash h, size_t bucket) { size_t parent = GET_PARENT(bucket); marked_ptr_t cur; if (h->B[parent] == UNINITIALIZED) { initialize_bucket(h, parent); } hash_entry *dummy = qpool_alloc(hash_entry_pool); assert(dummy); dummy->hashed_key = so_dummykey(bucket); dummy->key = NULL; dummy->value = NULL; dummy->next = (hash_entry*)UNINITIALIZED; if (!qt_lf_list_insert(&(h->B[parent]), dummy, &cur, NULL, h->op_equals)) { qpool_free(hash_entry_pool, dummy); dummy = PTR_OF(cur); while (h->B[bucket] != CONSTRUCT(0, dummy)) ; } else { h->B[bucket] = CONSTRUCT(0, dummy); } }
void* lf_table_find(marked_ptr_t* head, hash_key_t key, marked_ptr_t** prev, marked_ptr_t* cur) { marked_ptr_t* tp_prev; marked_ptr_t tp_cur; marked_ptr_t* tp_next; hash_key_t cur_key; void* cur_value; if(PTR_OF(*head) == NULL) { if(prev) {*prev = head;}; if(cur){*cur = *head;}; return NULL; } while(1) { tp_prev = head; tp_cur = *head; while(1) { if (PTR_OF(tp_cur) == NULL) { if(prev){*prev = tp_prev;}; if(cur){*cur = tp_cur;}; return NULL; } tp_next = &PTR_OF(tp_cur)->next; cur_key = PTR_OF(tp_cur)->key; cur_value = PTR_OF(tp_cur)->value; if(*tp_prev != tp_cur) { break; // someone has mucked with the list, start over } if(MARK_OF(tp_cur)) { if (CAS(tp_prev, CONSTRUCT(1, tp_cur), tp_next) == CONSTRUCT(1, tp_cur)) { free(PTR_OF(tp_cur)); tp_cur = *tp_next; continue; } else { break; //start over } } if (key >= cur_key) { if(prev){*prev = tp_prev;}; if(cur){*cur = tp_cur;}; return key == cur_key ? cur_value : NULL; } tp_prev = tp_next; tp_cur = *tp_next; } } }
static void *qt_lf_list_find(marked_ptr_t *head, so_key_t hashed_key, qt_key_t key, marked_ptr_t **oprev, marked_ptr_t *ocur, marked_ptr_t *onext, qt_dict_key_equals_f op_equals) { so_key_t ckey; qt_key_t okey; void *cval; marked_ptr_t *prev = NULL; marked_ptr_t cur = UNINITIALIZED; marked_ptr_t next = UNINITIALIZED; // int foundInsertPos = 0; while (1) { prev = head; cur = *prev; while (1) { if (PTR_OF(cur) == NULL) { if (oprev) { *oprev = prev; } if (ocur) { *ocur = cur; } if (onext) { *onext = next; } return 0; } next = (marked_ptr_t)(PTR_OF(cur)->next); ckey = PTR_OF(cur)->hashed_key; cval = PTR_OF(cur)->value; okey = PTR_OF(cur)->key; if (*prev != CONSTRUCT(0, cur)) { break; // this means someone mucked with the list; start over } if (!MARK_OF(next)) { // if next pointer is not marked if (ckey >= hashed_key) { // if current key > hashed_key, the key isn't in the list; if current key == hashed_key, the key IS in the list // if (foundInsertPos == 0) { if (oprev) { *oprev = prev; } if (ocur) { *ocur = cur; } if (onext) { *onext = next; } // foundInsertPos = 1; // } if(ckey == hashed_key) { if((okey != NULL) && op_equals(okey, key)) { /* * if (oprev) { *oprev = prev; } * if (ocur) { *ocur = cur; } * if (onext) { *onext = next; } */ return cval; } // else, keep looking } else { return NULL; } } // but if current key < hashed_key, the we don't know yet, keep looking prev = (marked_ptr_t *)&(PTR_OF(cur)->next); } else { if (qthread_cas(prev, CONSTRUCT(0, cur), CONSTRUCT(0, next)) == CONSTRUCT(0, cur)) { qpool_free(hash_entry_pool, PTR_OF(cur)); } else { break; } } cur = next; } } }