PatchworkOS
Loading...
Searching...
No Matches
map.c
Go to the documentation of this file.
1#include <kernel/utils/map.h>
2
3#include <errno.h>
4#include <stdlib.h>
5#include <string.h>
6#include <sys/math.h>
7
9{
10 return n > 0 && (n & (n - 1)) == 0;
11}
12
14{
15 if (n <= 1)
16 {
17 return 2;
18 }
19
20 if ((n > 0 && (n & (n - 1)) == 0))
21 {
22 return n;
23 }
24
25 n--;
26 n |= n >> 1;
27 n |= n >> 2;
28 n |= n >> 4;
29 n |= n >> 8;
30 n |= n >> 16;
31 n |= n >> 32;
32 n++;
33
34 if (n == 0)
35 {
36 return (UINT64_MAX >> 1) + 1;
37 }
38
39 return n;
40}
41
42uint64_t hash_object(const void* object, uint64_t length)
43{
44 uint64_t hash = 0xcbf29ce484222325ULL;
45 const uint64_t prime = 0x100000001b3ULL;
46
47 for (uint64_t i = 0; i < length; ++i)
48 {
49 hash ^= (uint64_t)((uint8_t*)object)[i];
50 hash *= prime;
51 }
52
53 return hash;
54}
55
56bool map_key_is_equal(const map_key_t* a, const map_key_t* b)
57{
58 if (a->hash != b->hash)
59 {
60 return false;
61 }
62
63 if (a->len != b->len)
64 {
65 return false;
66 }
67
68 return memcmp(a->key, b->key, a->len) == 0;
69}
70
72{
73 memset(entry->key.key, 0, sizeof(entry->key.key));
74 entry->key.len = 0;
75 entry->key.hash = 0;
76}
77
78static uint64_t map_find_slot(const map_t* map, const map_key_t* key, bool forInsertion)
79{
80 uint64_t index = (uint64_t)(key->hash & (map->capacity - 1));
81 uint64_t firstTombstone = ERR;
82
83 for (uint64_t i = 0; i < map->capacity; i++)
84 {
85 uint64_t currentIndex = (index + i) & (map->capacity - 1);
86 map_entry_t* entry = map->entries[currentIndex];
87
88 if (entry == NULL)
89 {
90 if (forInsertion && firstTombstone != ERR)
91 {
92 return firstTombstone;
93 }
94 return currentIndex;
95 }
96
97 if (entry == MAP_TOMBSTONE)
98 {
99 if (forInsertion && firstTombstone == ERR)
100 {
101 firstTombstone = currentIndex;
102 }
103 continue;
104 }
105
106 if (map_key_is_equal(&entry->key, key))
107 {
108 return currentIndex;
109 }
110 }
111
112 if (forInsertion && firstTombstone != ERR)
113 {
114 return firstTombstone;
115 }
116
117 return ERR;
118}
119
120static uint64_t map_resize(map_t* map, uint64_t newCapacity)
121{
122 if (!is_power_of_two(newCapacity))
123 {
124 newCapacity = next_power_of_two(newCapacity);
125 }
126
127 if (newCapacity <= map->capacity)
128 {
129 return 0;
130 }
131
132 map_entry_t** newEntries = calloc(newCapacity, sizeof(map_entry_t*));
133 if (newEntries == NULL)
134 {
135 return ERR;
136 }
137
138 map_entry_t** oldEntries = map->entries;
139 uint64_t oldCapacity = map->capacity;
140 uint64_t oldLength = map->length;
141 uint64_t oldTombstones = map->tombstones;
142
143 map->entries = newEntries;
144 map->capacity = newCapacity;
145 map->length = 0;
146 map->tombstones = 0;
147
148 for (uint64_t i = 0; i < oldCapacity; i++)
149 {
150 map_entry_t* entry = oldEntries[i];
151 if (entry != NULL && entry != MAP_TOMBSTONE)
152 {
153 uint64_t newIndex = map_find_slot(map, &entry->key, true);
154 if (newIndex == ERR)
155 {
156 free(newEntries);
157 map->entries = oldEntries;
158 map->capacity = oldCapacity;
159 map->length = oldLength;
160 map->tombstones = oldTombstones;
161 return ERR;
162 }
163 map->entries[newIndex] = entry;
164 map->length++;
165 }
166 }
167
168 free(oldEntries);
169 return 0;
170}
171
173{
174 map->length = 0;
175 map->capacity = 0;
176 map->tombstones = 0;
177 map->entries = NULL;
178
179 return 0;
180}
181
183{
184 free(map->entries);
185 map->entries = NULL;
186 map->length = 0;
187 map->capacity = 0;
188 map->tombstones = 0;
189}
190
192{
193 if (entry == NULL)
194 {
195 errno = EINVAL;
196 return ERR;
197 }
198
199 uint32_t currentEntries = map->length + map->tombstones;
200 if (currentEntries * 100 >= MAP_MAX_LOAD_PERCENTAGE * map->capacity)
201 {
202 uint64_t newCapacity = (map->capacity == 0) ? MAP_MIN_CAPACITY : (map->capacity * 2);
203 if (map_resize(map, newCapacity) == ERR)
204 {
205 errno = ENOMEM;
206 return ERR;
207 }
208 }
209
210 uint64_t index = map_find_slot(map, key, true);
211 if (index == ERR)
212 {
213 errno = ENOMEM;
214 return ERR;
215 }
216
217 if (map->entries[index] != NULL && map->entries[index] != MAP_TOMBSTONE &&
218 map_key_is_equal(&map->entries[index]->key, key))
219 {
220 errno = EEXIST;
221 return ERR;
222 }
223
224 if (map->entries[index] == MAP_TOMBSTONE)
225 {
226 map->tombstones--;
227 }
228
229 map->entries[index] = entry;
230 entry->key = *key;
231 map->length++;
232
233 return 0;
234}
235
237{
238 uint64_t index = map_find_slot(map, key, false);
239 if (index == ERR)
240 {
241 return NULL;
242 }
243
244 map_entry_t* entry = map->entries[index];
245 if (entry == NULL || entry == MAP_TOMBSTONE)
246 {
247 return NULL;
248 }
249
250 if (map_key_is_equal(&entry->key, key))
251 {
252 return entry;
253 }
254
255 return NULL;
256}
257
258void map_remove(map_t* map, const map_key_t* key)
259{
260 uint64_t index = map_find_slot(map, key, false);
261 if (index == ERR)
262 {
263 return;
264 }
265
266 map_entry_t* entry = map->entries[index];
267 if (entry == NULL || entry == MAP_TOMBSTONE || !map_key_is_equal(&entry->key, key))
268 {
269 return;
270 }
271
272 map->entries[index] = MAP_TOMBSTONE;
273 map->length--;
274 map->tombstones++;
275
276 return;
277}
278
280{
281 return map->length;
282}
283
285{
286 return map->capacity;
287}
288
290{
291 return map->length == 0;
292}
293
294bool map_contains(map_t* map, const map_key_t* key)
295{
296 return map_get(map, key) != NULL;
297}
298
300{
301 for (uint64_t i = 0; i < map->capacity; i++)
302 {
303 map->entries[i] = NULL;
304 }
305
306 map->length = 0;
307 map->tombstones = 0;
308}
309
311{
312 if (minCapacity <= map->capacity)
313 {
314 return 0;
315 }
316
317 uint64_t newCapacity = next_power_of_two(minCapacity);
318 if (map_resize(map, newCapacity) == ERR)
319 {
320 errno = ENOMEM;
321 return ERR;
322 }
323 return 0;
324}
uint64_t hash_object(const void *object, uint64_t length)
Hash a object.
Definition map.c:42
uint64_t map_capacity(const map_t *map)
Get the capacity of the map.
Definition map.c:284
bool map_contains(map_t *map, const map_key_t *key)
Check if the map contains a key.
Definition map.c:294
void map_clear(map_t *map)
Clear all entries from the map.
Definition map.c:299
void map_deinit(map_t *map)
Deinitialize a map.
Definition map.c:182
#define MAP_MIN_CAPACITY
The minimum capacity of a map.
Definition map.h:20
void map_entry_init(map_entry_t *entry)
Initialize a map entry.
Definition map.c:71
#define MAP_MAX_LOAD_PERCENTAGE
The maximum load percentage of a map before it resizes.
Definition map.h:25
#define MAP_TOMBSTONE
The value used to indicate a tombstone (removed entry).
Definition map.h:30
uint64_t map_size(const map_t *map)
Get the number of entries in the map.
Definition map.c:279
uint64_t map_insert(map_t *map, const map_key_t *key, map_entry_t *entry)
Insert a key-value pair into the map.
Definition map.c:191
uint64_t map_init(map_t *map)
Initialize a map.
Definition map.c:172
void map_remove(map_t *map, const map_key_t *key)
Remove a key-value pair from the map.
Definition map.c:258
bool map_is_empty(const map_t *map)
Check if the map is empty.
Definition map.c:289
map_entry_t * map_get(map_t *map, const map_key_t *key)
Get a value from the map by key.
Definition map.c:236
uint64_t map_reserve(map_t *map, uint64_t minCapacity)
Reserve space in the map for at least minCapacity entries.
Definition map.c:310
#define EEXIST
File exists.
Definition errno.h:117
#define EINVAL
Invalid argument.
Definition errno.h:142
#define ENOMEM
Out of memory.
Definition errno.h:92
#define errno
Error number variable.
Definition errno.h:27
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
static uint64_t next_power_of_two(uint64_t n)
Definition map.c:13
static uint64_t map_resize(map_t *map, uint64_t newCapacity)
Definition map.c:120
static uint64_t map_find_slot(const map_t *map, const map_key_t *key, bool forInsertion)
Definition map.c:78
static bool is_power_of_two(uint64_t n)
Definition map.c:8
bool map_key_is_equal(const map_key_t *a, const map_key_t *b)
Definition map.c:56
boot_memory_map_t * map
Definition mem.c:19
__UINT32_TYPE__ uint32_t
Definition stdint.h:15
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
#define UINT64_MAX
Definition stdint.h:74
__UINT8_TYPE__ uint8_t
Definition stdint.h:11
_PUBLIC void * calloc(size_t nmemb, size_t size)
Definition calloc.c:6
_PUBLIC void free(void *ptr)
Definition free.c:11
_PUBLIC int memcmp(const void *s1, const void *s2, size_t n)
Definition memcmp.c:3
_PUBLIC void * memset(void *s, int c, size_t n)
Definition memset.c:4
uint64_t length
Definition boot_info.h:47
Map entry structure.
Definition map.h:57
map_key_t key
Definition map.h:58
Map key stucture.
Definition map.h:45
uint8_t key[MAP_KEY_MAX_LENGTH]
Definition map.h:46
uint64_t len
Definition map.h:47
uint64_t hash
Definition map.h:48
Hash map structure.
Definition map.h:76