AquilaOS documentation
How it works, and its code
Toggle main menu visibility
Loading...
Searching...
No Matches
hashmap.h
Go to the documentation of this file.
1
#ifndef _DS_HASHMAP_H
2
#define _DS_HASHMAP_H
3
4
#include <
core/system.h
>
5
6
struct
hashmap
;
7
struct
hashmap_node
;
8
9
#include <
core/string.h
>
10
#include <aquila/errno.h>
11
#include <
ds/queue.h
>
12
13
/*
14
* Hash tables: entries found by a hash of their key. Each bucket is a
15
* queue of nodes, and a node points to its entry. The caller computes
16
* the hash (hashmap_digest()), and gives the table a function that says
17
* whether an entry is the one for a key. The table doubles its buckets
18
* when it holds more than HASHMAP_LOAD entries per bucket on average.
19
*/
20
21
/* A key's hash. */
22
typedef
uintptr_t
hash_t
;
23
24
/* How many buckets a new table has, unless the caller says. */
25
#define HASHMAP_DEFAULT 20
26
27
/* With more entries than this per bucket on average, the table doubles
28
* its buckets. */
29
#define HASHMAP_LOAD 2
30
32
struct
hashmap
{
33
size_t
count
;
34
35
size_t
buckets_nr
;
36
struct
queue
*
buckets
;
37
38
/* says whether entry `a` is the one for key `b` */
39
int (*
eq
)(
void
*a,
void
*b);
40
};
41
43
struct
hashmap_node
{
44
hash_t
hash
;
45
void
*
entry
;
46
struct
qnode
*
qnode
;
47
};
48
49
/* Loops over each node of a hash table, as a queue node `n` whose value
50
* is the hashmap_node. */
51
#define hashmap_for(n, h) \
52
for (size_t __i__ = 0; __i__ < (h)->buckets_nr; ++__i__) \
53
queue_for ((n), &(h)->buckets[__i__])
54
57
static
inline
struct
hashmap
*
hashmap_new
(
size_t
n,
int
(*
eq
)(
void
*,
void
*))
58
{
59
if
(!n) n =
HASHMAP_DEFAULT
;
60
61
struct
hashmap
*
hashmap
;
62
63
hashmap
=
kmalloc
(
sizeof
(
struct
hashmap
), &M_HASHMAP, 0);
64
if
(!
hashmap
)
return
NULL
;
65
66
67
memset
(
hashmap
, 0,
sizeof
(
struct
hashmap
));
68
69
hashmap
->
eq
=
eq
;
70
hashmap
->
buckets
=
kmalloc
(n *
sizeof
(
struct
queue
), &M_QUEUE, 0);
71
72
if
(!
hashmap
->
buckets
) {
73
kfree
(
hashmap
);
74
return
NULL
;
75
}
76
77
memset
(
hashmap
->
buckets
, 0, n *
sizeof
(
struct
queue
));
78
79
hashmap
->
buckets_nr
= n;
80
81
return
hashmap
;
82
}
83
85
static
inline
hash_t
hashmap_digest
(
const
void
*_id,
size_t
size)
86
{
87
/* FNV-1a, where every byte changes the whole hash: page offsets, all
88
* multiples of 4096, would mostly collide in a sum of the bytes */
89
const
unsigned
char
*
id
= (
const
unsigned
char
*) _id;
90
91
#if ARCH_BITS==64
92
hash_t
hash = 14695981039346656037ULL;
93
const
hash_t
prime = 1099511628211ULL;
94
#else
95
hash_t
hash = 2166136261U;
96
const
hash_t
prime = 16777619U;
97
#endif
98
99
while
(size--) {
100
hash ^= *
id
++;
101
hash *= prime;
102
}
103
104
return
hash;
105
}
106
110
static
inline
void
hashmap_grow
(
struct
hashmap
*
hashmap
)
111
{
112
size_t
nr =
hashmap
->
buckets_nr
* 2;
113
struct
queue
*
buckets
=
kmalloc
(nr *
sizeof
(
struct
queue
), &M_QUEUE,
M_ZERO
);
114
115
if
(!
buckets
)
116
return
;
117
118
for
(
size_t
i = 0; i <
hashmap
->
buckets_nr
; ++i) {
119
struct
qnode
*
qnode
=
hashmap
->
buckets
[i].
head
;
120
121
while
(
qnode
) {
122
struct
qnode
*
next
=
qnode
->
next
;
123
struct
hashmap_node
*node = (
struct
hashmap_node
*)
qnode
->
value
;
124
struct
queue
*
queue
= &
buckets
[node->
hash
% nr];
125
126
qnode
->
prev
=
queue
->
tail
;
127
qnode
->
next
=
NULL
;
128
129
if
(
queue
->
tail
)
130
queue
->
tail
->
next
=
qnode
;
131
else
132
queue
->
head
=
qnode
;
133
134
queue
->
tail
=
qnode
;
135
queue
->
count
++;
136
137
qnode
= next;
138
}
139
}
140
141
kfree
(
hashmap
->
buckets
);
142
hashmap
->
buckets
=
buckets
;
143
hashmap
->
buckets_nr
= nr;
144
}
145
148
static
inline
int
hashmap_insert
(
struct
hashmap
*
hashmap
,
hash_t
hash,
void
*entry)
149
{
150
if
(!
hashmap
|| !
hashmap
->
buckets_nr
|| !
hashmap
->
buckets
)
151
return
-EINVAL;
152
153
struct
hashmap_node
*node;
154
155
node =
kmalloc
(
sizeof
(
struct
hashmap_node
), &M_HASHMAP_NODE, 0);
156
157
if
(!node)
return
-ENOMEM;
158
159
node->
hash
=
hash
;
160
node->
entry
=
entry
;
161
162
size_t
idx =
hash
%
hashmap
->
buckets_nr
;
163
164
node->
qnode
= enqueue(&
hashmap
->
buckets
[idx], node);
165
166
if
(!node->
qnode
) {
167
kfree
(node);
168
return
-ENOMEM;
169
}
170
171
hashmap
->
count
++;
172
173
if
(
hashmap
->
count
>
hashmap
->
buckets_nr
*
HASHMAP_LOAD
)
174
hashmap_grow
(
hashmap
);
175
176
return
0;
177
}
178
181
static
inline
struct
hashmap_node
*
hashmap_lookup
(
struct
hashmap
*
hashmap
,
hash_t
hash
,
void
*key)
182
{
183
if
(!
hashmap
|| !
hashmap
->
buckets
|| !
hashmap
->
buckets_nr
|| !
hashmap
->
count
)
184
return
NULL
;
185
186
size_t
idx =
hash
%
hashmap
->
buckets_nr
;
187
struct
queue
*
queue
= &
hashmap
->
buckets
[idx];
188
189
queue_for
(node,
queue
) {
190
struct
hashmap_node
*hnode = (
struct
hashmap_node
*) node->value;
191
if
(hnode && hnode->
hash
==
hash
&&
hashmap
->
eq
(hnode->
entry
, key))
192
return
hnode;
193
}
194
195
return
NULL
;
196
}
197
200
static
inline
int
hashmap_replace
(
struct
hashmap
*
hashmap
,
hash_t
hash
,
void
*key,
void
*
entry
)
201
{
202
if
(!
hashmap
|| !
hashmap
->
buckets
|| !
hashmap
->
buckets_nr
|| !
hashmap
->
count
)
203
return
-EINVAL;
204
205
size_t
idx =
hash
%
hashmap
->
buckets_nr
;
206
struct
queue
*
queue
= &
hashmap
->
buckets
[idx];
207
208
queue_for
(node,
queue
) {
209
struct
hashmap_node
*hnode = (
struct
hashmap_node
*) node->value;
210
if
(hnode && hnode->
hash
==
hash
&&
hashmap
->
eq
(hnode->
entry
, key)) {
211
hnode->
entry
=
entry
;
212
return
0;
213
}
214
}
215
216
return
hashmap_insert
(
hashmap
,
hash
,
entry
);
217
}
218
220
static
inline
void
hashmap_node_remove
(
struct
hashmap
*
hashmap
,
struct
hashmap_node
*node)
221
{
222
if
(!
hashmap
|| !
hashmap
->
buckets
||
223
!
hashmap
->
buckets_nr
|| !node || !node->
qnode
)
224
return
;
225
226
size_t
idx = node->
hash
%
hashmap
->
buckets_nr
;
227
struct
queue
*
queue
= &
hashmap
->
buckets
[idx];
228
229
queue_node_remove(
queue
, node->
qnode
);
230
kfree
(node);
231
hashmap
->
count
--;
232
}
233
235
static
inline
void
hashmap_free
(
struct
hashmap
*
hashmap
)
236
{
237
for
(
size_t
i = 0; i <
hashmap
->
buckets_nr
; ++i) {
238
struct
queue
*
queue
= &
hashmap
->
buckets
[i];
239
240
struct
hashmap_node
*node;
241
while
((node = dequeue(
queue
))) {
242
kfree
(node);
243
}
244
}
245
246
kfree
(
hashmap
->
buckets
);
247
kfree
(
hashmap
);
248
}
249
250
#endif
/* ! _DS_HASHMAP_H */
buckets
static struct blk * buckets[CACHE_BUCKETS]
Definition
blkcache.c:66
hashmap_replace
static int hashmap_replace(struct hashmap *hashmap, hash_t hash, void *key, void *entry)
Replaces the entry for a key, or adds it if there's none.
Definition
hashmap.h:200
hashmap_digest
static hash_t hashmap_digest(const void *_id, size_t size)
Returns the hash of a key of size bytes.
Definition
hashmap.h:85
HASHMAP_LOAD
#define HASHMAP_LOAD
Definition
hashmap.h:29
hash_t
uintptr_t hash_t
Definition
hashmap.h:22
hashmap_insert
static int hashmap_insert(struct hashmap *hashmap, hash_t hash, void *entry)
Adds an entry to a hash table.
Definition
hashmap.h:148
hashmap_free
static void hashmap_free(struct hashmap *hashmap)
Frees a hash table and its nodes (not their entries).
Definition
hashmap.h:235
hashmap_node_remove
static void hashmap_node_remove(struct hashmap *hashmap, struct hashmap_node *node)
Removes a node from a hash table, and frees it (not its entry).
Definition
hashmap.h:220
hashmap_lookup
static struct hashmap_node * hashmap_lookup(struct hashmap *hashmap, hash_t hash, void *key)
Finds the node of the entry for a key, or returns NULL if there's none.
Definition
hashmap.h:181
HASHMAP_DEFAULT
#define HASHMAP_DEFAULT
Definition
hashmap.h:25
hashmap_grow
static void hashmap_grow(struct hashmap *hashmap)
Doubles a table's buckets, and moves each entry to its new bucket.
Definition
hashmap.h:110
hashmap_new
static struct hashmap * hashmap_new(size_t n, int(*eq)(void *, void *))
Makes a new, empty hash table of n buckets (0: HASHMAP_DEFAULT).
Definition
hashmap.h:57
system.h
kmalloc
void * kmalloc(size_t size, struct malloc_type *type, int flags)
Allocates memory for one of the kernel's structures.
Definition
kvmem.c:123
M_ZERO
#define M_ZERO
Definition
kvmem.h:26
kfree
void kfree(void *)
Frees an object that kmalloc() gave.
Definition
kvmem.c:146
memset
void * memset(void *dst, int c, size_t n)
Sets n bytes to c.
Definition
libc.c:23
queue.h
queue_for
#define queue_for(n, q)
Definition
queue.h:37
NULL
#define NULL
Definition
stddef.h:27
uintptr_t
__SIZE_TYPE__ uintptr_t
Definition
stddef.h:12
string.h
hashmap_node
A hash table's node: an entry, with its key's hash.
Definition
hashmap.h:43
hashmap_node::hash
hash_t hash
Definition
hashmap.h:44
hashmap_node::entry
void * entry
Definition
hashmap.h:45
hashmap_node::qnode
struct qnode * qnode
Definition
hashmap.h:46
hashmap
A hash table.
Definition
hashmap.h:32
hashmap::eq
int(*) eq(void *a, void *b)
Definition
hashmap.h:39
hashmap::count
size_t count
Definition
hashmap.h:33
hashmap::buckets_nr
size_t buckets_nr
Definition
hashmap.h:35
hashmap::buckets
struct queue * buckets
Definition
hashmap.h:36
qnode
A queue's node, holding one entry.
Definition
queue.h:19
qnode::value
void * value
Definition
queue.h:20
qnode::next
struct qnode * next
Definition
queue.h:22
qnode::prev
struct qnode * prev
Definition
queue.h:21
queue
A queue.
Definition
queue.h:29
queue::tail
struct qnode * tail
Definition
queue.h:32
queue::count
size_t count
Definition
queue.h:30
queue::head
struct qnode * head
Definition
queue.h:31
kernel
include
ds
hashmap.h
Generated by
1.18.0