forked from seflerZ/lf_table
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lf_hash.c
142 lines (114 loc) · 3.14 KB
/
lf_hash.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#include "lf_hash.h"
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;
}
}
}
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_get(LF_HashTable* table, void* key)
{
return lf_table_find(&table->buckets[HASH(key)], CONSTRUCT(0,key), NULL, NULL);
}
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;
}
int lf_table_remove(LF_HashTable* table, void* key)
{
if(remove_node(&table->buckets[HASH(key)], CONSTRUCT(0,key)))
{
INCR(&table->size, -1);
return 1;
}
return 0;
}