Skip to content

Commit 10760be

Browse files
committed
Change doubly LL to singly LL in hash table
1 parent d8cde00 commit 10760be

File tree

1 file changed

+111
-65
lines changed

1 file changed

+111
-65
lines changed

map-reduce/word-count.c

+111-65
Original file line numberDiff line numberDiff line change
@@ -4,70 +4,103 @@
44

55
#include <stddef.h>
66

7-
#define container_of(list_ptr, container_type, member_name) \
8-
({ \
9-
const typeof(((container_type *) 0)->member_name) *__member_ptr = \
10-
(list_ptr); \
11-
(container_type *) ((char *) __member_ptr - \
12-
offsetof(container_type, member_name)); \
13-
})
7+
#include <stdint.h>
8+
#include <stdlib.h>
9+
#include <stdbool.h>
1410

15-
struct list_entry {
16-
struct list_entry *next, *prev;
11+
struct hlist_head {
12+
struct hlist_node *first;
1713
};
1814

19-
#define list_element(list_ptr, type, member) \
20-
container_of(list_ptr, type, member)
15+
struct hlist_node {
16+
struct hlist_node *next, **pprev;
17+
};
2118

22-
#define list_first(root_ptr, type, member) \
23-
list_element((root_ptr)->next, type, member)
19+
#define HLIST_HEAD_INIT { .first = NULL }
20+
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
21+
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
2422

25-
static inline struct list_entry *list_next(struct list_entry *root,
26-
struct list_entry *current)
23+
static inline void INIT_HLIST_NODE(struct hlist_node *h)
2724
{
28-
if ((root == root->next) || (current->next == root)) return NULL;
29-
return current->next;
25+
h->next = NULL;
26+
h->pprev = NULL;
3027
}
3128

32-
/* FIXME: this forbids having 2 list_for_each in the same function, because the
33-
* variable __ptr will be defined twice, which results in a compilation error.
34-
* The __ptr is necessary because some functions delete iter while traversing
35-
* the list.
36-
*/
37-
#define list_for_each_forward(root_ptr, iter) \
38-
struct list_entry *__ptr; \
39-
for (iter = (root_ptr)->next, __ptr = (struct list_entry *) (iter)->next; \
40-
iter != (root_ptr); iter = (typeof((iter))) __ptr, \
41-
__ptr = (struct list_entry *) iter->next)
42-
43-
#define list_for_each(root_ptr, iter) list_for_each_forward(root_ptr, iter)
29+
static inline int hlist_empty(const struct hlist_head *h)
30+
{
31+
return !h->first;
32+
}
4433

45-
static inline void list_root_init(struct list_entry *root)
34+
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
4635
{
47-
root->next = root->prev = root;
36+
struct hlist_node *first = h->first;
37+
n->next = first;
38+
if (first)
39+
first->pprev = &n->next;
40+
h->first = n;
41+
n->pprev = &h->first;
4842
}
4943

50-
static inline void list_add(struct list_entry *root, struct list_entry *entry)
44+
#include <stdbool.h>
45+
46+
static inline bool hlist_is_singular_node(struct hlist_node *n, struct hlist_head *h)
5147
{
52-
struct list_entry *prev_entry = root;
53-
struct list_entry *next_entry = root->next;
54-
entry->next = next_entry, entry->prev = prev_entry;
55-
prev_entry->next = entry, next_entry->prev = entry;
48+
return !n->next && n->pprev == &h->first;
5649
}
5750

58-
#define list_add_prev(root, entry) list_add((root)->prev, (entry))
51+
#define container_of(list_ptr, container_type, member_name) \
52+
({ \
53+
const typeof(((container_type *) 0)->member_name) *__member_ptr = \
54+
(list_ptr); \
55+
(container_type *) ((char *) __member_ptr - \
56+
offsetof(container_type, member_name)); \
57+
})
5958

60-
#define list_empty(root) (root == (root)->next)
59+
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
6160

62-
#include <stdint.h>
63-
#include <stdlib.h>
61+
#define hlist_first_entry(head, type, member) \
62+
hlist_entry((head)->first, type, member)
63+
64+
#define hlist_for_each(pos, head) \
65+
for (pos = (head)->first; pos ; pos = pos->next)
66+
67+
#define hlist_for_each_safe(pos, n, head) \
68+
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
69+
pos = n)
70+
71+
#define hlist_entry_safe(ptr, type, member) \
72+
({ typeof(ptr) ____ptr = (ptr); \
73+
____ptr ? hlist_entry(____ptr, type, member) : NULL; \
74+
})
75+
76+
#define hlist_for_each_entry(pos, head, member) \
77+
for (pos = hlist_entry_safe((head)->first, typeof(*(pos)), member);\
78+
pos; \
79+
pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
80+
81+
#define hlist_for_each_entry_safe(pos, n, head, member) \
82+
for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\
83+
pos && ({ n = pos->member.next; 1; }); \
84+
pos = hlist_entry_safe(n, typeof(*pos), member))
85+
86+
/* Use hash_32 when possible to allow for fast 32bit hashing in 64bit kernels. */
87+
#define hash_min(val, bits) \
88+
(sizeof(val) <= 4 ? hash_32(val, bits) : hash_long(val, bits))
89+
90+
static inline void __hash_init(struct hlist_head *ht, unsigned int sz)
91+
{
92+
unsigned int i;
93+
94+
for (i = 0; i < sz; i++)
95+
INIT_HLIST_HEAD(&ht[i]);
96+
}
6497

6598
typedef uint32_t hash_t;
6699

67100
/* A node of the table */
68101
struct ht_node {
69102
hash_t hash;
70-
struct list_entry list;
103+
struct hlist_node list;
71104
};
72105

73106
/* user-defined functions */
@@ -79,7 +112,7 @@ struct htable {
79112
hashfunc_t *hashfunc;
80113
cmp_t *cmp;
81114
uint32_t n_buckets;
82-
struct list_entry *buckets;
115+
struct hlist_head *buckets;
83116
};
84117

85118
/* Initializes a hash table */
@@ -90,9 +123,8 @@ static inline int ht_init(struct htable *h,
90123
{
91124
h->hashfunc = hashfunc, h->cmp = cmp;
92125
h->n_buckets = n_buckets;
93-
h->buckets = malloc(sizeof(struct list_entry) * n_buckets);
94-
for (size_t i = 0; i < h->n_buckets; i++) list_root_init(&h->buckets[i]);
95-
126+
h->buckets = malloc(sizeof(struct hlist_head) * n_buckets);
127+
__hash_init(h->buckets, h->n_buckets);
96128
return 0;
97129
}
98130

@@ -112,9 +144,9 @@ static inline struct ht_node *ht_find(struct htable *h, void *key)
112144
uint32_t bkt;
113145
h->hashfunc(key, &hval, &bkt);
114146

115-
struct list_entry *head = &h->buckets[bkt], *iter;
116-
list_for_each (head, iter) {
117-
struct ht_node *n = list_element(iter, struct ht_node, list);
147+
struct hlist_head *head = &h->buckets[bkt];
148+
struct ht_node *n;
149+
hlist_for_each_entry(n, head, list) {
118150
if (n->hash == hval) {
119151
int res = h->cmp(n, key);
120152
if (!res) return n;
@@ -127,45 +159,56 @@ static inline struct ht_node *ht_find(struct htable *h, void *key)
127159
/* Insert a new element with the key 'key' in the htable.
128160
* Return 0 if success.
129161
*/
162+
#include <stdio.h>
163+
130164
static inline int ht_insert(struct htable *h, struct ht_node *n, void *key)
131165
{
132166
hash_t hval;
133167
uint32_t bkt;
134168
h->hashfunc(key, &hval, &bkt);
135169
n->hash = hval;
136170

137-
struct list_entry *head = &h->buckets[bkt], *iter;
138-
list_for_each (head, iter) {
139-
struct ht_node *tmp = list_element(iter, struct ht_node, list);
171+
struct hlist_head *head = &h->buckets[bkt];
172+
struct hlist_node *iter;
173+
hlist_for_each (iter, head) {
174+
struct ht_node *tmp = hlist_entry(iter, struct ht_node, list);
140175
if (tmp->hash >= hval) {
141176
int cmp = h->cmp(tmp, key);
142177
if (!cmp) /* already exist */
143178
return -1;
144179
if (cmp > 0) {
145-
list_add_prev(iter, &n->list);
180+
hlist_add_head(&n->list, head);
146181
return 0;
147182
}
148183
}
149184
}
150185

151-
list_add_prev(head, &n->list);
186+
hlist_add_head(&n->list, head);
152187
return 0;
153188
}
154189

155190
static inline struct ht_node *ht_get_first(struct htable *h, uint32_t bucket)
156191
{
157-
struct list_entry *head = &h->buckets[bucket];
158-
if (list_empty(head)) return NULL;
159-
return list_first(head, struct ht_node, list);
192+
struct hlist_head *head = &h->buckets[bucket];
193+
if (hlist_empty(head)) return NULL;
194+
return hlist_first_entry(head, struct ht_node, list);
195+
}
196+
197+
static inline struct hlist_node *hlist_next(struct hlist_head *root,
198+
struct hlist_node *current)
199+
{
200+
if ((hlist_empty(root)) || hlist_is_singular_node(current, root) || !current) return NULL;
201+
return current->next;
160202
}
161203

162204
static inline struct ht_node *ht_get_next(struct htable *h,
163-
uint32_t bucket,
164-
struct ht_node *n)
205+
uint32_t bucket,
206+
struct ht_node *n)
165207
{
166-
struct list_entry *ln = list_next(&h->buckets[bucket], &n->list);
208+
printf("%s", &n->list ? "": "0");
209+
struct hlist_node *ln = hlist_next(&h->buckets[bucket], &n->list);
167210
if (!ln) return NULL;
168-
return list_element(ln, struct ht_node, list);
211+
return hlist_entry(ln, struct ht_node, list);
169212
}
170213

171214
/* cache of words. Count the number of word using a modified hash table */
@@ -211,7 +254,7 @@ static struct wc_cache main_cache, *thread_caches;
211254
static inline int __wc_cmp(struct ht_node *n, void *key, char m)
212255
{
213256
struct wc_word *w = m ? container_of(n, struct wc_word, node_main)
214-
: container_of(n, struct wc_word, node);
257+
: container_of(n, struct wc_word, node);
215258
return strcasecmp(GET_WORD(w), (char *) key);
216259
}
217260

@@ -384,8 +427,8 @@ int wc_print(int id)
384427
for (; iter; iter = ht_get_next(&cache->htable, j, iter)) {
385428
struct wc_word *w =
386429
valid ? container_of(iter, struct wc_word, node_main)
387-
: container_of(iter, struct wc_word, node);
388-
printf("%s : %d\n", GET_WORD(w), w->counter);
430+
: container_of(iter, struct wc_word, node);
431+
// printf("%s : %d\n", GET_WORD(w), w->counter);
389432
bkt_total++, total++;
390433
count_total += w->counter;
391434
}
@@ -402,13 +445,16 @@ static int __wc_destroy(struct wc_cache *wcc, int id)
402445
int valid = (id == -1);
403446
for (uint32_t j = 0; j < n_buckets; j++) {
404447
struct ht_node *iter = ht_get_first(&wcc->htable, j);
405-
for (; iter; iter = ht_get_next(&wcc->htable, j, iter)) {
448+
struct ht_node *tmp = ht_get_next(&wcc->htable, j, iter);
449+
for (; tmp; iter = tmp, tmp = ht_get_next(&wcc->htable, j, tmp)) {
406450
struct wc_word *w =
407451
valid ? container_of(iter, struct wc_word, node_main)
408-
: container_of(iter, struct wc_word, node);
452+
: container_of(iter, struct wc_word, node);
453+
409454
free(w->full_word);
410455
free(w);
411456
}
457+
412458
}
413459
return 0;
414460
}

0 commit comments

Comments
 (0)