prometheus-client-mmap 0.15.0 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,128 +5,115 @@
5
5
  * it under the terms of the MIT license. See LICENSE for details.
6
6
  */
7
7
 
8
- #include <stdlib.h>
9
- #include <stdint.h>
8
+ #include "hashmap.h"
9
+
10
+ #include <errno.h>
10
11
  #include <stdbool.h>
12
+ #include <stdint.h>
13
+ #include <stdlib.h>
11
14
  #include <string.h>
12
- #include <errno.h>
13
-
14
- #include "hashmap.h"
15
15
 
16
16
  #ifndef HASHMAP_NOASSERT
17
17
  #include <assert.h>
18
- #define HASHMAP_ASSERT(expr) assert(expr)
18
+ #define HASHMAP_ASSERT(expr) assert(expr)
19
19
  #else
20
20
  #define HASHMAP_ASSERT(expr)
21
21
  #endif
22
22
 
23
23
  /* Table sizes must be powers of 2 */
24
- #define HASHMAP_SIZE_MIN (1 << 5) /* 32 */
25
- #define HASHMAP_SIZE_DEFAULT (1 << 8) /* 256 */
26
- #define HASHMAP_SIZE_MOD(map, val) ((val) & ((map)->table_size - 1))
24
+ #define HASHMAP_SIZE_MIN (1 << 5) /* 32 */
25
+ #define HASHMAP_SIZE_DEFAULT (1 << 8) /* 256 */
26
+ #define HASHMAP_SIZE_MOD(map, val) ((val) & ((map)->table_size - 1))
27
27
 
28
28
  /* Limit for probing is 1/2 of table_size */
29
- #define HASHMAP_PROBE_LEN(map) ((map)->table_size >> 1)
29
+ #define HASHMAP_PROBE_LEN(map) ((map)->table_size >> 1)
30
30
  /* Return the next linear probe index */
31
- #define HASHMAP_PROBE_NEXT(map, index) HASHMAP_SIZE_MOD(map, (index) + 1)
31
+ #define HASHMAP_PROBE_NEXT(map, index) HASHMAP_SIZE_MOD(map, (index) + 1)
32
32
 
33
33
  /* Check if index b is less than or equal to index a */
34
- #define HASHMAP_INDEX_LE(map, a, b) \
35
- ((a) == (b) || (((b) - (a)) & ((map)->table_size >> 1)) != 0)
36
-
34
+ #define HASHMAP_INDEX_LE(map, a, b) ((a) == (b) || (((b) - (a)) & ((map)->table_size >> 1)) != 0)
37
35
 
38
36
  struct hashmap_entry {
39
- void *key;
40
- void *data;
37
+ void *key;
38
+ void *data;
41
39
  #ifdef HASHMAP_METRICS
42
- size_t num_collisions;
40
+ size_t num_collisions;
43
41
  #endif
44
42
  };
45
43
 
46
-
47
44
  /*
48
45
  * Enforce a maximum 0.75 load factor.
49
46
  */
50
- static inline size_t hashmap_table_min_size_calc(size_t num_entries)
51
- {
52
- return num_entries + (num_entries / 3);
53
- }
47
+ static inline size_t hashmap_table_min_size_calc(size_t num_entries) { return num_entries + (num_entries / 3); }
54
48
 
55
49
  /*
56
50
  * Calculate the optimal table size, given the specified max number
57
51
  * of elements.
58
52
  */
59
- static size_t hashmap_table_size_calc(size_t num_entries)
60
- {
61
- size_t table_size;
62
- size_t min_size;
63
-
64
- table_size = hashmap_table_min_size_calc(num_entries);
65
-
66
- /* Table size is always a power of 2 */
67
- min_size = HASHMAP_SIZE_MIN;
68
- while (min_size < table_size) {
69
- min_size <<= 1;
70
- }
71
- return min_size;
53
+ static size_t hashmap_table_size_calc(size_t num_entries) {
54
+ size_t table_size;
55
+ size_t min_size;
56
+
57
+ table_size = hashmap_table_min_size_calc(num_entries);
58
+
59
+ /* Table size is always a power of 2 */
60
+ min_size = HASHMAP_SIZE_MIN;
61
+ while (min_size < table_size) {
62
+ min_size <<= 1;
63
+ }
64
+ return min_size;
72
65
  }
73
66
 
74
67
  /*
75
68
  * Get a valid hash table index from a key.
76
69
  */
77
- static inline size_t hashmap_calc_index(const struct hashmap *map,
78
- const void *key)
79
- {
80
- return HASHMAP_SIZE_MOD(map, map->hash(key));
70
+ static inline size_t hashmap_calc_index(const struct hashmap *map, const void *key) {
71
+ return HASHMAP_SIZE_MOD(map, map->hash(key));
81
72
  }
82
73
 
83
74
  /*
84
75
  * Return the next populated entry, starting with the specified one.
85
76
  * Returns NULL if there are no more valid entries.
86
77
  */
87
- static struct hashmap_entry *hashmap_entry_get_populated(
88
- const struct hashmap *map, struct hashmap_entry *entry)
89
- {
90
- for (; entry < &map->table[map->table_size]; ++entry) {
91
- if (entry->key) {
92
- return entry;
93
- }
94
- }
95
- return NULL;
78
+ static struct hashmap_entry *hashmap_entry_get_populated(const struct hashmap *map, struct hashmap_entry *entry) {
79
+ for (; entry < &map->table[map->table_size]; ++entry) {
80
+ if (entry->key) {
81
+ return entry;
82
+ }
83
+ }
84
+ return NULL;
96
85
  }
97
86
 
98
87
  /*
99
88
  * Find the hashmap entry with the specified key, or an empty slot.
100
89
  * Returns NULL if the entire table has been searched without finding a match.
101
90
  */
102
- static struct hashmap_entry *hashmap_entry_find(const struct hashmap *map,
103
- const void *key, bool find_empty)
104
- {
105
- size_t i;
106
- size_t index;
107
- size_t probe_len = HASHMAP_PROBE_LEN(map);
108
- struct hashmap_entry *entry;
109
-
110
- index = hashmap_calc_index(map, key);
111
-
112
- /* Linear probing */
113
- for (i = 0; i < probe_len; ++i) {
114
- entry = &map->table[index];
115
- if (!entry->key) {
116
- if (find_empty) {
91
+ static struct hashmap_entry *hashmap_entry_find(const struct hashmap *map, const void *key, bool find_empty) {
92
+ size_t i;
93
+ size_t index;
94
+ size_t probe_len = HASHMAP_PROBE_LEN(map);
95
+ struct hashmap_entry *entry;
96
+
97
+ index = hashmap_calc_index(map, key);
98
+
99
+ /* Linear probing */
100
+ for (i = 0; i < probe_len; ++i) {
101
+ entry = &map->table[index];
102
+ if (!entry->key) {
103
+ if (find_empty) {
117
104
  #ifdef HASHMAP_METRICS
118
- entry->num_collisions = i;
105
+ entry->num_collisions = i;
119
106
  #endif
120
- return entry;
121
- }
122
- return NULL;
123
- }
124
- if (map->key_compare(key, entry->key) == 0) {
125
- return entry;
126
- }
127
- index = HASHMAP_PROBE_NEXT(map, index);
128
- }
129
- return NULL;
107
+ return entry;
108
+ }
109
+ return NULL;
110
+ }
111
+ if (map->key_compare(key, entry->key) == 0) {
112
+ return entry;
113
+ }
114
+ index = HASHMAP_PROBE_NEXT(map, index);
115
+ }
116
+ return NULL;
130
117
  }
131
118
 
132
119
  /*
@@ -134,47 +121,45 @@ static struct hashmap_entry *hashmap_entry_find(const struct hashmap *map,
134
121
  * the load factor and keep the chain continuous. This is a required
135
122
  * step for hash maps using linear probing.
136
123
  */
137
- static void hashmap_entry_remove(struct hashmap *map,
138
- struct hashmap_entry *removed_entry)
139
- {
140
- size_t i;
124
+ static void hashmap_entry_remove(struct hashmap *map, struct hashmap_entry *removed_entry) {
125
+ size_t i;
141
126
  #ifdef HASHMAP_METRICS
142
- size_t removed_i = 0;
127
+ size_t removed_i = 0;
143
128
  #endif
144
- size_t index;
145
- size_t entry_index;
146
- size_t removed_index = (removed_entry - map->table);
147
- struct hashmap_entry *entry;
148
-
149
- /* Free the key */
150
- if (map->key_free) {
151
- map->key_free(removed_entry->key);
152
- }
153
- --map->num_entries;
154
-
155
- /* Fill the free slot in the chain */
156
- index = HASHMAP_PROBE_NEXT(map, removed_index);
157
- for (i = 1; i < map->table_size; ++i) {
158
- entry = &map->table[index];
159
- if (!entry->key) {
160
- /* Reached end of chain */
161
- break;
162
- }
163
- entry_index = hashmap_calc_index(map, entry->key);
164
- /* Shift in entries with an index <= to the removed slot */
165
- if (HASHMAP_INDEX_LE(map, removed_index, entry_index)) {
129
+ size_t index;
130
+ size_t entry_index;
131
+ size_t removed_index = (removed_entry - map->table);
132
+ struct hashmap_entry *entry;
133
+
134
+ /* Free the key */
135
+ if (map->key_free) {
136
+ map->key_free(removed_entry->key);
137
+ }
138
+ --map->num_entries;
139
+
140
+ /* Fill the free slot in the chain */
141
+ index = HASHMAP_PROBE_NEXT(map, removed_index);
142
+ for (i = 1; i < map->table_size; ++i) {
143
+ entry = &map->table[index];
144
+ if (!entry->key) {
145
+ /* Reached end of chain */
146
+ break;
147
+ }
148
+ entry_index = hashmap_calc_index(map, entry->key);
149
+ /* Shift in entries with an index <= to the removed slot */
150
+ if (HASHMAP_INDEX_LE(map, removed_index, entry_index)) {
166
151
  #ifdef HASHMAP_METRICS
167
- entry->num_collisions -= (i - removed_i);
168
- removed_i = i;
152
+ entry->num_collisions -= (i - removed_i);
153
+ removed_i = i;
169
154
  #endif
170
- memcpy(removed_entry, entry, sizeof(*removed_entry));
171
- removed_index = index;
172
- removed_entry = entry;
173
- }
174
- index = HASHMAP_PROBE_NEXT(map, index);
175
- }
176
- /* Clear the last removed entry */
177
- memset(removed_entry, 0, sizeof(*removed_entry));
155
+ memcpy(removed_entry, entry, sizeof(*removed_entry));
156
+ removed_index = index;
157
+ removed_entry = entry;
158
+ }
159
+ index = HASHMAP_PROBE_NEXT(map, index);
160
+ }
161
+ /* Clear the last removed entry */
162
+ memset(removed_entry, 0, sizeof(*removed_entry));
178
163
  }
179
164
 
180
165
  /*
@@ -182,68 +167,64 @@ static void hashmap_entry_remove(struct hashmap *map,
182
167
  * new_size MUST be a power of 2.
183
168
  * Returns 0 on success and -errno on allocation or hash function failure.
184
169
  */
185
- static int hashmap_rehash(struct hashmap *map, size_t new_size)
186
- {
187
- size_t old_size;
188
- struct hashmap_entry *old_table;
189
- struct hashmap_entry *new_table;
190
- struct hashmap_entry *entry;
191
- struct hashmap_entry *new_entry;
192
-
193
- HASHMAP_ASSERT(new_size >= HASHMAP_SIZE_MIN);
194
- HASHMAP_ASSERT((new_size & (new_size - 1)) == 0);
195
-
196
- new_table = (struct hashmap_entry *)calloc(new_size,
197
- sizeof(struct hashmap_entry));
198
- if (!new_table) {
199
- return -ENOMEM;
200
- }
201
- /* Backup old elements in case of rehash failure */
202
- old_size = map->table_size;
203
- old_table = map->table;
204
- map->table_size = new_size;
205
- map->table = new_table;
206
- /* Rehash */
207
- for (entry = old_table; entry < &old_table[old_size]; ++entry) {
208
- if (!entry->data) {
209
- /* Only copy entries with data */
210
- continue;
211
- }
212
- new_entry = hashmap_entry_find(map, entry->key, true);
213
- if (!new_entry) {
214
- /*
215
- * The load factor is too high with the new table
216
- * size, or a poor hash function was used.
217
- */
218
- goto revert;
219
- }
220
- /* Shallow copy (intentionally omits num_collisions) */
221
- new_entry->key = entry->key;
222
- new_entry->data = entry->data;
223
- }
224
- free(old_table);
225
- return 0;
170
+ static int hashmap_rehash(struct hashmap *map, size_t new_size) {
171
+ size_t old_size;
172
+ struct hashmap_entry *old_table;
173
+ struct hashmap_entry *new_table;
174
+ struct hashmap_entry *entry;
175
+ struct hashmap_entry *new_entry;
176
+
177
+ HASHMAP_ASSERT(new_size >= HASHMAP_SIZE_MIN);
178
+ HASHMAP_ASSERT((new_size & (new_size - 1)) == 0);
179
+
180
+ new_table = (struct hashmap_entry *)calloc(new_size, sizeof(struct hashmap_entry));
181
+ if (!new_table) {
182
+ return -ENOMEM;
183
+ }
184
+ /* Backup old elements in case of rehash failure */
185
+ old_size = map->table_size;
186
+ old_table = map->table;
187
+ map->table_size = new_size;
188
+ map->table = new_table;
189
+ /* Rehash */
190
+ for (entry = old_table; entry < &old_table[old_size]; ++entry) {
191
+ if (!entry->data) {
192
+ /* Only copy entries with data */
193
+ continue;
194
+ }
195
+ new_entry = hashmap_entry_find(map, entry->key, true);
196
+ if (!new_entry) {
197
+ /*
198
+ * The load factor is too high with the new table
199
+ * size, or a poor hash function was used.
200
+ */
201
+ goto revert;
202
+ }
203
+ /* Shallow copy (intentionally omits num_collisions) */
204
+ new_entry->key = entry->key;
205
+ new_entry->data = entry->data;
206
+ }
207
+ free(old_table);
208
+ return 0;
226
209
  revert:
227
- map->table_size = old_size;
228
- map->table = old_table;
229
- free(new_table);
230
- return -EINVAL;
210
+ map->table_size = old_size;
211
+ map->table = old_table;
212
+ free(new_table);
213
+ return -EINVAL;
231
214
  }
232
215
 
233
216
  /*
234
217
  * Iterate through all entries and free all keys.
235
218
  */
236
- static void hashmap_free_keys(struct hashmap *map)
237
- {
238
- struct hashmap_iter *iter;
239
-
240
- if (!map->key_free) {
241
- return;
242
- }
243
- for (iter = hashmap_iter(map); iter;
244
- iter = hashmap_iter_next(map, iter)) {
245
- map->key_free((void *)hashmap_iter_get_key(iter));
246
- }
219
+ static void hashmap_free_keys(struct hashmap *map) {
220
+ struct hashmap_iter *iter;
221
+
222
+ if (!map->key_free) {
223
+ return;
224
+ }
225
+ for (iter = hashmap_iter(map); iter; iter = hashmap_iter_next(map, iter)) {
226
+ map->key_free((void *)hashmap_iter_get_key(iter));
227
+ }
247
228
  }
248
229
 
249
230
  /*
@@ -263,58 +244,52 @@ static void hashmap_free_keys(struct hashmap *map)
263
244
  * Returns 0 on success and -errno on failure.
264
245
  */
265
246
  int hashmap_init(struct hashmap *map, size_t (*hash_func)(const void *),
266
- int (*key_compare_func)(const void *, const void *),
267
- size_t initial_size)
268
- {
269
- HASHMAP_ASSERT(map != NULL);
270
- HASHMAP_ASSERT(hash_func != NULL);
271
- HASHMAP_ASSERT(key_compare_func != NULL);
272
-
273
- if (!initial_size) {
274
- initial_size = HASHMAP_SIZE_DEFAULT;
275
- } else {
276
- /* Convert init size to valid table size */
277
- initial_size = hashmap_table_size_calc(initial_size);
278
- }
279
- map->table_size_init = initial_size;
280
- map->table_size = initial_size;
281
- map->num_entries = 0;
282
- map->table = (struct hashmap_entry *)calloc(initial_size,
283
- sizeof(struct hashmap_entry));
284
- if (!map->table) {
285
- return -ENOMEM;
286
- }
287
- map->hash = hash_func;
288
- map->key_compare = key_compare_func;
289
- map->key_alloc = NULL;
290
- map->key_free = NULL;
291
- return 0;
247
+ int (*key_compare_func)(const void *, const void *), size_t initial_size) {
248
+ HASHMAP_ASSERT(map != NULL);
249
+ HASHMAP_ASSERT(hash_func != NULL);
250
+ HASHMAP_ASSERT(key_compare_func != NULL);
251
+
252
+ if (!initial_size) {
253
+ initial_size = HASHMAP_SIZE_DEFAULT;
254
+ } else {
255
+ /* Convert init size to valid table size */
256
+ initial_size = hashmap_table_size_calc(initial_size);
257
+ }
258
+ map->table_size_init = initial_size;
259
+ map->table_size = initial_size;
260
+ map->num_entries = 0;
261
+ map->table = (struct hashmap_entry *)calloc(initial_size, sizeof(struct hashmap_entry));
262
+ if (!map->table) {
263
+ return -ENOMEM;
264
+ }
265
+ map->hash = hash_func;
266
+ map->key_compare = key_compare_func;
267
+ map->key_alloc = NULL;
268
+ map->key_free = NULL;
269
+ return 0;
292
270
  }
293
271
 
294
272
  /*
295
273
  * Free the hashmap and all associated memory.
296
274
  */
297
- void hashmap_destroy(struct hashmap *map)
298
- {
299
- if (!map) {
300
- return;
301
- }
302
- hashmap_free_keys(map);
303
- free(map->table);
304
- memset(map, 0, sizeof(*map));
275
+ void hashmap_destroy(struct hashmap *map) {
276
+ if (!map) {
277
+ return;
278
+ }
279
+ hashmap_free_keys(map);
280
+ free(map->table);
281
+ memset(map, 0, sizeof(*map));
305
282
  }
306
283
 
307
284
  /*
308
285
  * Enable internal memory management of hash keys.
309
286
  */
310
- void hashmap_set_key_alloc_funcs(struct hashmap *map,
311
- void *(*key_alloc_func)(const void *),
312
- void (*key_free_func)(void *))
313
- {
314
- HASHMAP_ASSERT(map != NULL);
315
-
316
- map->key_alloc = key_alloc_func;
317
- map->key_free = key_free_func;
287
+ void hashmap_set_key_alloc_funcs(struct hashmap *map, void *(*key_alloc_func)(const void *),
288
+ void (*key_free_func)(void *)) {
289
+ HASHMAP_ASSERT(map != NULL);
290
+
291
+ map->key_alloc = key_alloc_func;
292
+ map->key_free = key_free_func;
318
293
  }
319
294
 
320
295
  /*
@@ -324,132 +299,125 @@ void hashmap_set_key_alloc_funcs(struct hashmap *map,
324
299
  * the return value with the data passed in to determine if a new entry was
325
300
  * created. Returns NULL if memory allocation failed.
326
301
  */
327
- void *hashmap_put(struct hashmap *map, const void *key, void *data)
328
- {
329
- struct hashmap_entry *entry;
330
-
331
- HASHMAP_ASSERT(map != NULL);
332
- HASHMAP_ASSERT(key != NULL);
333
-
334
- /* Rehash with 2x capacity if load factor is approaching 0.75 */
335
- if (map->table_size <= hashmap_table_min_size_calc(map->num_entries)) {
336
- hashmap_rehash(map, map->table_size << 1);
337
- }
338
- entry = hashmap_entry_find(map, key, true);
339
- if (!entry) {
340
- /*
341
- * Cannot find an empty slot. Either out of memory, or using
342
- * a poor hash function. Attempt to rehash once to reduce
343
- * chain length.
344
- */
345
- if (hashmap_rehash(map, map->table_size << 1) < 0) {
346
- return NULL;
347
- }
348
- entry = hashmap_entry_find(map, key, true);
349
- if (!entry) {
350
- return NULL;
351
- }
352
- }
353
- if (!entry->key) {
354
- /* Allocate copy of key to simplify memory management */
355
- if (map->key_alloc) {
356
- entry->key = map->key_alloc(key);
357
- if (!entry->key) {
358
- return NULL;
359
- }
360
- } else {
361
- entry->key = (void *)key;
362
- }
363
- ++map->num_entries;
364
- } else if (entry->data) {
365
- /* Do not overwrite existing data */
366
- return entry->data;
367
- }
368
- entry->data = data;
369
- return data;
302
+ void *hashmap_put(struct hashmap *map, const void *key, void *data) {
303
+ struct hashmap_entry *entry;
304
+
305
+ HASHMAP_ASSERT(map != NULL);
306
+ HASHMAP_ASSERT(key != NULL);
307
+
308
+ /* Rehash with 2x capacity if load factor is approaching 0.75 */
309
+ if (map->table_size <= hashmap_table_min_size_calc(map->num_entries)) {
310
+ hashmap_rehash(map, map->table_size << 1);
311
+ }
312
+ entry = hashmap_entry_find(map, key, true);
313
+ if (!entry) {
314
+ /*
315
+ * Cannot find an empty slot. Either out of memory, or using
316
+ * a poor hash function. Attempt to rehash once to reduce
317
+ * chain length.
318
+ */
319
+ if (hashmap_rehash(map, map->table_size << 1) < 0) {
320
+ return NULL;
321
+ }
322
+ entry = hashmap_entry_find(map, key, true);
323
+ if (!entry) {
324
+ return NULL;
325
+ }
326
+ }
327
+ if (!entry->key) {
328
+ /* Allocate copy of key to simplify memory management */
329
+ if (map->key_alloc) {
330
+ entry->key = map->key_alloc(key);
331
+ if (!entry->key) {
332
+ return NULL;
333
+ }
334
+ } else {
335
+ entry->key = (void *)key;
336
+ }
337
+ ++map->num_entries;
338
+ } else if (entry->data) {
339
+ /* Do not overwrite existing data */
340
+ return entry->data;
341
+ }
342
+ entry->data = data;
343
+ return data;
370
344
  }
371
345
 
372
346
  /*
373
347
  * Return the data pointer, or NULL if no entry exists.
374
348
  */
375
- void *hashmap_get(const struct hashmap *map, const void *key)
376
- {
377
- struct hashmap_entry *entry;
378
-
379
- HASHMAP_ASSERT(map != NULL);
380
- HASHMAP_ASSERT(key != NULL);
381
-
382
- entry = hashmap_entry_find(map, key, false);
383
- if (!entry) {
384
- return NULL;
385
- }
386
- return entry->data;
349
+ void *hashmap_get(const struct hashmap *map, const void *key) {
350
+ struct hashmap_entry *entry;
351
+
352
+ HASHMAP_ASSERT(map != NULL);
353
+ HASHMAP_ASSERT(key != NULL);
354
+
355
+ entry = hashmap_entry_find(map, key, false);
356
+ if (!entry) {
357
+ return NULL;
358
+ }
359
+ return entry->data;
387
360
  }
388
361
 
389
362
  /*
390
363
  * Remove an entry with the specified key from the map.
391
364
  * Returns the data pointer, or NULL, if no entry was found.
392
365
  */
393
- void *hashmap_remove(struct hashmap *map, const void *key)
394
- {
395
- struct hashmap_entry *entry;
396
- void *data;
397
-
398
- HASHMAP_ASSERT(map != NULL);
399
- HASHMAP_ASSERT(key != NULL);
400
-
401
- entry = hashmap_entry_find(map, key, false);
402
- if (!entry) {
403
- return NULL;
404
- }
405
- data = entry->data;
406
- /* Clear the entry and make the chain contiguous */
407
- hashmap_entry_remove(map, entry);
408
- return data;
366
+ void *hashmap_remove(struct hashmap *map, const void *key) {
367
+ struct hashmap_entry *entry;
368
+ void *data;
369
+
370
+ HASHMAP_ASSERT(map != NULL);
371
+ HASHMAP_ASSERT(key != NULL);
372
+
373
+ entry = hashmap_entry_find(map, key, false);
374
+ if (!entry) {
375
+ return NULL;
376
+ }
377
+ data = entry->data;
378
+ /* Clear the entry and make the chain contiguous */
379
+ hashmap_entry_remove(map, entry);
380
+ return data;
409
381
  }
410
382
 
411
383
  /*
412
384
  * Remove all entries.
413
385
  */
414
- void hashmap_clear(struct hashmap *map)
415
- {
416
- HASHMAP_ASSERT(map != NULL);
386
+ void hashmap_clear(struct hashmap *map) {
387
+ HASHMAP_ASSERT(map != NULL);
417
388
 
418
- hashmap_free_keys(map);
419
- map->num_entries = 0;
420
- memset(map->table, 0, sizeof(struct hashmap_entry) * map->table_size);
389
+ hashmap_free_keys(map);
390
+ map->num_entries = 0;
391
+ memset(map->table, 0, sizeof(struct hashmap_entry) * map->table_size);
421
392
  }
422
393
 
423
394
  /*
424
395
  * Remove all entries and reset the hash table to its initial size.
425
396
  */
426
- void hashmap_reset(struct hashmap *map)
427
- {
428
- struct hashmap_entry *new_table;
429
-
430
- HASHMAP_ASSERT(map != NULL);
431
-
432
- hashmap_clear(map);
433
- if (map->table_size == map->table_size_init) {
434
- return;
435
- }
436
- new_table = (struct hashmap_entry *)realloc(map->table,
437
- sizeof(struct hashmap_entry) * map->table_size_init);
438
- if (!new_table) {
439
- return;
440
- }
441
- map->table = new_table;
442
- map->table_size = map->table_size_init;
397
+ void hashmap_reset(struct hashmap *map) {
398
+ struct hashmap_entry *new_table;
399
+
400
+ HASHMAP_ASSERT(map != NULL);
401
+
402
+ hashmap_clear(map);
403
+ if (map->table_size == map->table_size_init) {
404
+ return;
405
+ }
406
+ new_table = (struct hashmap_entry *)realloc(map->table, sizeof(struct hashmap_entry) * map->table_size_init);
407
+ if (!new_table) {
408
+ return;
409
+ }
410
+ map->table = new_table;
411
+ map->table_size = map->table_size_init;
443
412
  }
444
413
 
445
414
  /*
446
415
  * Return the number of entries in the hash map.
447
416
  */
448
- size_t hashmap_size(const struct hashmap *map)
449
- {
450
- HASHMAP_ASSERT(map != NULL);
417
+ size_t hashmap_size(const struct hashmap *map) {
418
+ HASHMAP_ASSERT(map != NULL);
451
419
 
452
- return map->num_entries;
420
+ return map->num_entries;
453
421
  }
454
422
 
455
423
  /*
@@ -458,88 +426,78 @@ size_t hashmap_size(const struct hashmap *map)
458
426
  * Hashmap iterators are INVALID after a put or remove operation is performed.
459
427
  * hashmap_iter_remove() allows safe removal during iteration.
460
428
  */
461
- struct hashmap_iter *hashmap_iter(const struct hashmap *map)
462
- {
463
- HASHMAP_ASSERT(map != NULL);
464
-
465
- if (!map->num_entries) {
466
- return NULL;
467
- }
468
- return (struct hashmap_iter *)hashmap_entry_get_populated(map,
469
- map->table);
429
+ struct hashmap_iter *hashmap_iter(const struct hashmap *map) {
430
+ HASHMAP_ASSERT(map != NULL);
431
+
432
+ if (!map->num_entries) {
433
+ return NULL;
434
+ }
435
+ return (struct hashmap_iter *)hashmap_entry_get_populated(map, map->table);
470
436
  }
471
437
 
472
438
  /*
473
439
  * Return an iterator to the next hashmap entry. Returns NULL if there are
474
440
  * no more entries.
475
441
  */
476
- struct hashmap_iter *hashmap_iter_next(const struct hashmap *map,
477
- const struct hashmap_iter *iter)
478
- {
479
- struct hashmap_entry *entry = (struct hashmap_entry *)iter;
480
-
481
- HASHMAP_ASSERT(map != NULL);
482
-
483
- if (!iter) {
484
- return NULL;
485
- }
486
- return (struct hashmap_iter *)hashmap_entry_get_populated(map,
487
- entry + 1);
442
+ struct hashmap_iter *hashmap_iter_next(const struct hashmap *map, const struct hashmap_iter *iter) {
443
+ struct hashmap_entry *entry = (struct hashmap_entry *)iter;
444
+
445
+ HASHMAP_ASSERT(map != NULL);
446
+
447
+ if (!iter) {
448
+ return NULL;
449
+ }
450
+ return (struct hashmap_iter *)hashmap_entry_get_populated(map, entry + 1);
488
451
  }
489
452
 
490
453
  /*
491
454
  * Remove the hashmap entry pointed to by this iterator and return an
492
455
  * iterator to the next entry. Returns NULL if there are no more entries.
493
456
  */
494
- struct hashmap_iter *hashmap_iter_remove(struct hashmap *map,
495
- const struct hashmap_iter *iter)
496
- {
497
- struct hashmap_entry *entry = (struct hashmap_entry *)iter;
498
-
499
- HASHMAP_ASSERT(map != NULL);
500
-
501
- if (!iter) {
502
- return NULL;
503
- }
504
- if (!entry->key) {
505
- /* Iterator is invalid, so just return the next valid entry */
506
- return hashmap_iter_next(map, iter);
507
- }
508
- hashmap_entry_remove(map, entry);
509
- return (struct hashmap_iter *)hashmap_entry_get_populated(map, entry);
457
+ struct hashmap_iter *hashmap_iter_remove(struct hashmap *map, const struct hashmap_iter *iter) {
458
+ struct hashmap_entry *entry = (struct hashmap_entry *)iter;
459
+
460
+ HASHMAP_ASSERT(map != NULL);
461
+
462
+ if (!iter) {
463
+ return NULL;
464
+ }
465
+ if (!entry->key) {
466
+ /* Iterator is invalid, so just return the next valid entry */
467
+ return hashmap_iter_next(map, iter);
468
+ }
469
+ hashmap_entry_remove(map, entry);
470
+ return (struct hashmap_iter *)hashmap_entry_get_populated(map, entry);
510
471
  }
511
472
 
512
473
  /*
513
474
  * Return the key of the entry pointed to by the iterator.
514
475
  */
515
- const void *hashmap_iter_get_key(const struct hashmap_iter *iter)
516
- {
517
- if (!iter) {
518
- return NULL;
519
- }
520
- return (const void *)((struct hashmap_entry *)iter)->key;
476
+ const void *hashmap_iter_get_key(const struct hashmap_iter *iter) {
477
+ if (!iter) {
478
+ return NULL;
479
+ }
480
+ return (const void *)((struct hashmap_entry *)iter)->key;
521
481
  }
522
482
 
523
483
  /*
524
484
  * Return the data of the entry pointed to by the iterator.
525
485
  */
526
- void *hashmap_iter_get_data(const struct hashmap_iter *iter)
527
- {
528
- if (!iter) {
529
- return NULL;
530
- }
531
- return ((struct hashmap_entry *)iter)->data;
486
+ void *hashmap_iter_get_data(const struct hashmap_iter *iter) {
487
+ if (!iter) {
488
+ return NULL;
489
+ }
490
+ return ((struct hashmap_entry *)iter)->data;
532
491
  }
533
492
 
534
493
  /*
535
494
  * Set the data pointer of the entry pointed to by the iterator.
536
495
  */
537
- void hashmap_iter_set_data(const struct hashmap_iter *iter, void *data)
538
- {
539
- if (!iter) {
540
- return;
541
- }
542
- ((struct hashmap_entry *)iter)->data = data;
496
+ void hashmap_iter_set_data(const struct hashmap_iter *iter, void *data) {
497
+ if (!iter) {
498
+ return;
499
+ }
500
+ ((struct hashmap_entry *)iter)->data = data;
543
501
  }
544
502
 
545
503
  /*
@@ -550,41 +508,38 @@ void hashmap_iter_set_data(const struct hashmap_iter *iter, void *data)
550
508
  * Iteration is stopped if func returns non-zero. Returns func's return
551
509
  * value if it is < 0, otherwise, 0.
552
510
  */
553
- int hashmap_foreach(const struct hashmap *map,
554
- int (*func)(const void *, void *, void *), void *arg)
555
- {
556
- struct hashmap_entry *entry;
557
- size_t num_entries;
558
- const void *key;
559
- int rc;
560
-
561
- HASHMAP_ASSERT(map != NULL);
562
- HASHMAP_ASSERT(func != NULL);
563
-
564
- entry = map->table;
565
- for (entry = map->table; entry < &map->table[map->table_size];
566
- ++entry) {
567
- if (!entry->key) {
568
- continue;
569
- }
570
- num_entries = map->num_entries;
571
- key = entry->key;
572
- rc = func(entry->key, entry->data, arg);
573
- if (rc < 0) {
574
- return rc;
575
- }
576
- if (rc > 0) {
577
- return 0;
578
- }
579
- /* Run this entry again if func() deleted it */
580
- if (entry->key != key) {
581
- --entry;
582
- } else if (num_entries != map->num_entries) {
583
- /* Stop immediately if func put/removed another entry */
584
- return -1;
585
- }
586
- }
587
- return 0;
511
+ int hashmap_foreach(const struct hashmap *map, int (*func)(const void *, void *, void *), void *arg) {
512
+ struct hashmap_entry *entry;
513
+ size_t num_entries;
514
+ const void *key;
515
+ int rc;
516
+
517
+ HASHMAP_ASSERT(map != NULL);
518
+ HASHMAP_ASSERT(func != NULL);
519
+
520
+ entry = map->table;
521
+ for (entry = map->table; entry < &map->table[map->table_size]; ++entry) {
522
+ if (!entry->key) {
523
+ continue;
524
+ }
525
+ num_entries = map->num_entries;
526
+ key = entry->key;
527
+ rc = func(entry->key, entry->data, arg);
528
+ if (rc < 0) {
529
+ return rc;
530
+ }
531
+ if (rc > 0) {
532
+ return 0;
533
+ }
534
+ /* Run this entry again if func() deleted it */
535
+ if (entry->key != key) {
536
+ --entry;
537
+ } else if (num_entries != map->num_entries) {
538
+ /* Stop immediately if func put/removed another entry */
539
+ return -1;
540
+ }
541
+ }
542
+ return 0;
588
543
  }
589
544
 
590
545
  /*
@@ -592,101 +547,89 @@ int hashmap_foreach(const struct hashmap *map,
592
547
  * This is an implementation of the well-documented Jenkins one-at-a-time
593
548
  * hash function.
594
549
  */
595
- size_t hashmap_hash_string(const void *key)
596
- {
597
- const char *key_str = (const char *)key;
598
- size_t hash = 0;
599
-
600
- for (; *key_str; ++key_str) {
601
- hash += *key_str;
602
- hash += (hash << 10);
603
- hash ^= (hash >> 6);
604
- }
605
- hash += (hash << 3);
606
- hash ^= (hash >> 11);
607
- hash += (hash << 15);
608
- return hash;
550
+ size_t hashmap_hash_string(const void *key) {
551
+ const char *key_str = (const char *)key;
552
+ size_t hash = 0;
553
+
554
+ for (; *key_str; ++key_str) {
555
+ hash += *key_str;
556
+ hash += (hash << 10);
557
+ hash ^= (hash >> 6);
558
+ }
559
+ hash += (hash << 3);
560
+ hash ^= (hash >> 11);
561
+ hash += (hash << 15);
562
+ return hash;
609
563
  }
610
564
 
611
565
  /*
612
566
  * Default key comparator function for string keys.
613
567
  */
614
- int hashmap_compare_string(const void *a, const void *b)
615
- {
616
- return strcmp((const char *)a, (const char *)b);
617
- }
568
+ int hashmap_compare_string(const void *a, const void *b) { return strcmp((const char *)a, (const char *)b); }
618
569
 
619
570
  /*
620
571
  * Default key allocation function for string keys. Use free() for the
621
572
  * key_free_func.
622
573
  */
623
- void *hashmap_alloc_key_string(const void *key)
624
- {
625
- return (void *)strdup((const char *)key);
626
- }
574
+ void *hashmap_alloc_key_string(const void *key) { return (void *)strdup((const char *)key); }
627
575
 
628
576
  #ifdef HASHMAP_METRICS
629
577
  /*
630
578
  * Return the load factor.
631
579
  */
632
- double hashmap_load_factor(const struct hashmap *map)
633
- {
634
- HASHMAP_ASSERT(map != NULL);
635
-
636
- if (!map->table_size) {
637
- return 0;
638
- }
639
- return (double)map->num_entries / map->table_size;
580
+ double hashmap_load_factor(const struct hashmap *map) {
581
+ HASHMAP_ASSERT(map != NULL);
582
+
583
+ if (!map->table_size) {
584
+ return 0;
585
+ }
586
+ return (double)map->num_entries / map->table_size;
640
587
  }
641
588
 
642
589
  /*
643
590
  * Return the average number of collisions per entry.
644
591
  */
645
- double hashmap_collisions_mean(const struct hashmap *map)
646
- {
647
- struct hashmap_entry *entry;
648
- size_t total_collisions = 0;
649
-
650
- HASHMAP_ASSERT(map != NULL);
651
-
652
- if (!map->num_entries) {
653
- return 0;
654
- }
655
- for (entry = map->table; entry < &map->table[map->table_size];
656
- ++entry) {
657
- if (!entry->key) {
658
- continue;
659
- }
660
- total_collisions += entry->num_collisions;
661
- }
662
- return (double)total_collisions / map->num_entries;
592
+ double hashmap_collisions_mean(const struct hashmap *map) {
593
+ struct hashmap_entry *entry;
594
+ size_t total_collisions = 0;
595
+
596
+ HASHMAP_ASSERT(map != NULL);
597
+
598
+ if (!map->num_entries) {
599
+ return 0;
600
+ }
601
+ for (entry = map->table; entry < &map->table[map->table_size]; ++entry) {
602
+ if (!entry->key) {
603
+ continue;
604
+ }
605
+ total_collisions += entry->num_collisions;
606
+ }
607
+ return (double)total_collisions / map->num_entries;
663
608
  }
664
609
 
665
610
  /*
666
611
  * Return the variance between entry collisions. The higher the variance,
667
612
  * the more likely the hash function is poor and is resulting in clustering.
668
613
  */
669
- double hashmap_collisions_variance(const struct hashmap *map)
670
- {
671
- struct hashmap_entry *entry;
672
- double mean_collisions;
673
- double variance;
674
- double total_variance = 0;
675
-
676
- HASHMAP_ASSERT(map != NULL);
677
-
678
- if (!map->num_entries) {
679
- return 0;
680
- }
681
- mean_collisions = hashmap_collisions_mean(map);
682
- for (entry = map->table; entry < &map->table[map->table_size];
683
- ++entry) {
684
- if (!entry->key) {
685
- continue;
686
- }
687
- variance = (double)entry->num_collisions - mean_collisions;
688
- total_variance += variance * variance;
689
- }
690
- return total_variance / map->num_entries;
614
+ double hashmap_collisions_variance(const struct hashmap *map) {
615
+ struct hashmap_entry *entry;
616
+ double mean_collisions;
617
+ double variance;
618
+ double total_variance = 0;
619
+
620
+ HASHMAP_ASSERT(map != NULL);
621
+
622
+ if (!map->num_entries) {
623
+ return 0;
624
+ }
625
+ mean_collisions = hashmap_collisions_mean(map);
626
+ for (entry = map->table; entry < &map->table[map->table_size]; ++entry) {
627
+ if (!entry->key) {
628
+ continue;
629
+ }
630
+ variance = (double)entry->num_collisions - mean_collisions;
631
+ total_variance += variance * variance;
632
+ }
633
+ return total_variance / map->num_entries;
691
634
  }
692
635
  #endif