| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #ifndef UTIL_HASHSET_H | ||
| 2 | #define UTIL_HASHSET_H | ||
| 3 | |||
| 4 | #include <stdbool.h> | ||
| 5 | #include <stddef.h> | ||
| 6 | #include "macros.h" | ||
| 7 | |||
| 8 | // A container type for holding a set of strings, using hashing for | ||
| 9 | // primary lookups and separate chaining for collision resolution. | ||
| 10 | typedef struct { | ||
| 11 | struct HashSetEntry **table; | ||
| 12 | size_t table_size; | ||
| 13 | size_t nr_entries; | ||
| 14 | size_t grow_at; | ||
| 15 | size_t (*hash)(const char *str, size_t len); | ||
| 16 | bool (*equal)(const void *s1, const void *s2, size_t n); | ||
| 17 | } HashSet; | ||
| 18 | |||
| 19 | typedef struct HashSetEntry { | ||
| 20 | struct HashSetEntry *next; | ||
| 21 | size_t str_len; | ||
| 22 | char str[]; | ||
| 23 | } HashSetEntry; | ||
| 24 | |||
| 25 | typedef struct { | ||
| 26 | const HashSet *set; | ||
| 27 | const HashSetEntry *entry; | ||
| 28 | size_t idx; | ||
| 29 | } HashSetIter; | ||
| 30 | |||
| 31 | 3 | static inline HashSetIter hashset_iter(const HashSet *set) | |
| 32 | { | ||
| 33 | 3 | return (HashSetIter){.set = set}; | |
| 34 | } | ||
| 35 | |||
| 36 | // Set `iter->entry` to the next active HashSetEntry in iter->set and | ||
| 37 | // return true, or return false when there are no remaining entries to | ||
| 38 | // visit. Note that `iter->entry` is only NULL prior to the first call. | ||
| 39 | 18 | static inline bool hashset_next(HashSetIter *iter) | |
| 40 | { | ||
| 41 |
4/4✓ Branch 2 → 3 taken 14 times.
✓ Branch 2 → 5 taken 4 times.
✓ Branch 3 → 4 taken 3 times.
✓ Branch 3 → 5 taken 11 times.
|
18 | if (likely(iter->entry) && iter->entry->next) { |
| 42 | // Traverse linked entries | ||
| 43 | 3 | iter->entry = iter->entry->next; | |
| 44 | 3 | return true; | |
| 45 | } | ||
| 46 | |||
| 47 | // Traverse table entries | ||
| 48 | 15 | const HashSet *set = iter->set; | |
| 49 |
2/2✓ Branch 9 → 6 taken 98 times.
✓ Branch 9 → 10 taken 5 times.
|
103 | for (size_t i = iter->idx, n = set->table_size; i < n; i++) { |
| 50 | 98 | const HashSetEntry *e = set->table[i]; | |
| 51 |
2/2✓ Branch 6 → 7 taken 10 times.
✓ Branch 6 → 8 taken 88 times.
|
98 | if (e) { |
| 52 | 10 | iter->entry = e; | |
| 53 | 10 | iter->idx = i + 1; | |
| 54 | 10 | return true; | |
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | return false; | ||
| 59 | } | ||
| 60 | |||
| 61 | void hashset_init(HashSet *set, size_t initial_size, bool icase); | ||
| 62 | void hashset_free(HashSet *set); | ||
| 63 | HashSetEntry *hashset_get(const HashSet *set, const char *str, size_t str_len); | ||
| 64 | HashSetEntry *hashset_insert(HashSet *set, const char *str, size_t str_len); | ||
| 65 | |||
| 66 | #endif | ||
| 67 |