#include "common.h"
#include "mlocal.h"
+#include "list.h"
#include "mem.h"
typedef struct node {
struct ll {
node_t *head;
- cmp_fun_t cmp_fun;
- clone_fun_t clone_fun;
+ const datatype_t *key_type;
};
static const map_impl_t ll_map_impl = {
return item;
}
-list_t *ll_alloc (cmp_fun_t cmp_fun, hash_fun_t hash_fun, clone_fun_t clone_fun) {
+list_t *ll_alloc (const datatype_t *key_type) {
list_t *ll = (list_t *)nbd_malloc(sizeof(list_t));
- ll->cmp_fun = cmp_fun;
- ll->clone_fun = clone_fun;
+ ll->key_type = key_type;
ll->head = node_alloc(NULL, 0);
ll->head->next = NULL;
return ll;
TRACE("l3", "find_pred: now current item is %p next is %p", item, next);
// The thread that completes the unlink should free the memory.
- if (ll->clone_fun != NULL) {
+ if (ll->key_type != NULL) {
nbd_defer_free((void*)other->key);
}
nbd_defer_free(other);
TRACE("l4", "find_pred: key %p val %p", item->key, item->val);
int d;
- if (EXPECT_TRUE(ll->cmp_fun == NULL)) {
+ if (EXPECT_TRUE(ll->key_type == NULL)) {
d = (uint64_t)item->key - (uint64_t)key;
} else {
- d = ll->cmp_fun(item->key, key);
+ d = ll->key_type->cmp(item->key, key);
}
// If we reached the key (or passed where it should be), we found the right predesssor
// Create a new item and insert it into the list.
TRACE("l2", "ll_cas: attempting to insert item between %p and %p", pred, pred->next);
- void *new_key = (ll->clone_fun == NULL) ? key : ll->clone_fun(key);
+ void *new_key = (ll->key_type == NULL) ? key : ll->key_type->clone(key);
node_t *new_item = node_alloc(new_key, new_val);
node_t *next = new_item->next = old_item;
node_t *other = SYNC_CAS(&pred->next, next, new_item);
// Lost a race. Failed to insert the new item into the list.
TRACE("l1", "ll_cas: lost a race. CAS failed. expected pred's link to be %p but found %p", next, other);
- if (ll->clone_fun != NULL) {
+ if (ll->key_type != NULL) {
nbd_free(new_key);
}
nbd_free(new_item);
return DOES_NOT_EXIST;
}
- // Mark <item> removed. This must be atomic. If multiple threads try to remove the same item
- // only one of them should succeed.
+ // Mark <item> removed. If multiple threads try to remove the same item only one of them should succeed.
node_t *next;
node_t *old_next = item->next;
do {
TRACE("l2", "ll_remove: logically removed item %p", item, 0);
ASSERT(IS_TAGGED(item->next));
- // This has to be an atomic swap in case another thread is updating the item while we are removing it.
+ // Atomically swap out the item's value in case another thread is updating the item while we are
+ // removing it. This establishes which operation occurs first logically, the update or the remove.
uint64_t val = SYNC_SWAP(&item->val, DOES_NOT_EXIST);
TRACE("l2", "ll_remove: replaced item's val %p with DOES_NOT_EXIT", val, 0);
}
// The thread that completes the unlink should free the memory.
- if (ll->clone_fun != NULL) {
+ if (ll->key_type != NULL) {
nbd_defer_free(item->key);
}
nbd_defer_free(item);