Coverage Report

Created: 2026-01-17 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/hoextdown/src/hash.c
Line
Count
Source
1
#include "hash.h"
2
3
#include <stdlib.h>
4
#include <string.h>
5
6
7.92k
#define HOEDOWN_HASH_ITEM_SIZE 255
7
295M
#define HOEDOWN_HASH_FNV_PRIME 0x01000193
8
95.3k
#define HOEDOWN_HASH_FNV_OFFSET_BASIS 0x811c9dc5
9
10
static char *
11
hoedown_hash_strndup(const char* str, size_t n)
12
16.4k
{
13
16.4k
    if (str) {
14
16.4k
        char *s = (char *)malloc(sizeof(char) * (n + 1));
15
16.4k
        if (s) {
16
16.4k
            memcpy(s, str, n);
17
16.4k
            s[n] = '\0';
18
16.4k
        }
19
16.4k
        return s;
20
16.4k
    }
21
0
    return NULL;
22
16.4k
}
23
24
static char *
25
hoedown_hash_strdup(const char* str)
26
0
{
27
0
    if (str) {
28
0
        return hoedown_hash_strndup(str, strlen(str));
29
0
    }
30
0
    return NULL;
31
0
}
32
33
static unsigned int
34
hoedown_hash_fnv(const char *key, const char *max, size_t limit)
35
95.3k
{
36
95.3k
    unsigned int hash = HOEDOWN_HASH_FNV_OFFSET_BASIS;
37
38
95.3k
    if (max == NULL) {
39
0
        if (key) {
40
0
            max = key + strlen(key);
41
0
        } else {
42
0
            max = key;
43
0
        }
44
0
    }
45
46
295M
    while (key < max) {
47
295M
        hash *= HOEDOWN_HASH_FNV_PRIME;
48
295M
        hash ^= *key;
49
295M
        key++;
50
295M
    }
51
52
95.3k
    hash %= limit;
53
54
95.3k
    return hash;
55
95.3k
}
56
57
static hoedown_hash_item *
58
hoedown_hash_item_new(void)
59
16.4k
{
60
16.4k
    hoedown_hash_item *item;
61
62
16.4k
    item = (hoedown_hash_item *)malloc(sizeof(hoedown_hash_item));
63
16.4k
    if (!item) {
64
0
        return NULL;
65
0
    }
66
67
16.4k
    item->key = NULL;
68
16.4k
    item->value = NULL;
69
16.4k
    item->destruct = NULL;
70
16.4k
    item->next = NULL;
71
16.4k
    item->tail = NULL;
72
73
16.4k
    return item;
74
16.4k
}
75
76
static void
77
hoedown_hash_item_free(hoedown_hash_item *item)
78
16.4k
{
79
16.4k
    if (item) {
80
16.4k
        if (item->next) {
81
2.10k
            hoedown_hash_item_free(item->next);
82
2.10k
        }
83
16.4k
        if (item->key) {
84
16.4k
            free(item->key);
85
16.4k
        }
86
16.4k
        if (item->destruct) {
87
16.4k
            (item->destruct)(item->value);
88
16.4k
        }
89
16.4k
        free(item);
90
16.4k
    }
91
16.4k
}
92
93
static int
94
hoedown_hash_item_push(hoedown_hash_item *item, const char *key, size_t key_len,
95
                       void *value, hoedown_hash_value_destruct *destruct)
96
16.4k
{
97
16.4k
    hoedown_hash_item *entry;
98
99
16.4k
    if (!item || !key || !value) {
100
0
        return 1;
101
0
    }
102
103
16.4k
    if (item->key != NULL) {
104
2.10k
        entry = hoedown_hash_item_new();
105
2.10k
        if (!entry) {
106
0
            return 1;
107
0
        }
108
14.3k
    } else {
109
14.3k
        entry = item;
110
14.3k
    }
111
112
16.4k
    if (key_len > 0) {
113
16.4k
        entry->key = hoedown_hash_strndup(key, key_len);
114
16.4k
    } else {
115
0
        entry->key = hoedown_hash_strdup(key);
116
0
    }
117
16.4k
    entry->value = value;
118
16.4k
    entry->destruct = destruct;
119
120
16.4k
    if (item->tail) {
121
2.10k
        item->tail->next = entry;
122
14.3k
    } else if (item != entry) {
123
0
        item->next = entry;
124
0
    }
125
16.4k
    item->tail = entry;
126
127
16.4k
    return 0;
128
16.4k
}
129
130
hoedown_hash *
131
hoedown_hash_new(size_t size)
132
7.92k
{
133
7.92k
    hoedown_hash *hash;
134
7.92k
    size_t items_size;
135
136
7.92k
    hash = (hoedown_hash *)malloc(sizeof(hoedown_hash));
137
7.92k
    if (!hash) {
138
0
        return NULL;
139
0
    }
140
141
7.92k
    if (size == 0) {
142
7.92k
        size = HOEDOWN_HASH_ITEM_SIZE;
143
7.92k
    }
144
145
7.92k
    items_size = sizeof(hoedown_hash_item *) * size;
146
147
7.92k
    hash->items = (hoedown_hash_item **)malloc(items_size);
148
7.92k
    if (!hash->items) {
149
0
        free(hash);
150
0
        return NULL;
151
0
    }
152
153
7.92k
    memset(hash->items, 0, items_size);
154
155
7.92k
    hash->asize = size;
156
157
7.92k
    return hash;
158
7.92k
}
159
160
void
161
hoedown_hash_free(hoedown_hash *hash)
162
7.92k
{
163
7.92k
    if (hash) {
164
7.92k
        if (hash->items) {
165
7.92k
            size_t i = 0;
166
2.02M
            while (i < hash->asize) {
167
2.02M
                if (hash->items[i]) {
168
14.3k
                    hoedown_hash_item_free(hash->items[i]);
169
14.3k
                }
170
2.02M
                ++i;
171
2.02M
            }
172
7.92k
            free(hash->items);
173
7.92k
        }
174
7.92k
        free(hash);
175
7.92k
    }
176
7.92k
}
177
178
int
179
hoedown_hash_add(hoedown_hash *hash, const char *key, size_t key_len,
180
                 void *value, hoedown_hash_value_destruct *destruct)
181
16.4k
{
182
16.4k
    unsigned int h;
183
184
16.4k
    if (!hash || !key || !value) {
185
0
        return 1;
186
0
    }
187
188
16.4k
    h = hoedown_hash_fnv(key, key + key_len, hash->asize);
189
190
16.4k
    if (!hash->items[h]) {
191
14.3k
        hash->items[h] = hoedown_hash_item_new();
192
14.3k
        if (!hash->items[h]) {
193
0
            return 1;
194
0
        }
195
14.3k
    }
196
197
16.4k
    if (hoedown_hash_item_push(hash->items[h], key, key_len,
198
16.4k
                               value, destruct) != 0) {
199
0
        return 1;
200
0
    }
201
202
16.4k
    return 0;
203
16.4k
}
204
205
void *
206
hoedown_hash_find(hoedown_hash *hash, char *key, size_t key_len)
207
78.8k
{
208
78.8k
    unsigned int h;
209
210
78.8k
    if (!hash || !key) {
211
0
        return NULL;
212
0
    }
213
214
78.8k
    h = hoedown_hash_fnv(key, key + key_len, hash->asize);
215
216
78.8k
    if (hash->items[h]) {
217
64.5k
        hoedown_hash_item *item = hash->items[h];
218
70.3k
        while (item != NULL) {
219
68.2k
            if (item->key && strncmp(item->key, key, key_len) == 0) {
220
62.4k
                return item->value;
221
62.4k
            }
222
5.79k
            item = item->next;
223
5.79k
        }
224
64.5k
    }
225
226
16.4k
    return NULL;
227
78.8k
}