Coverage Report

Created: 2026-09-01 06:49

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
9.36k
#define HOEDOWN_HASH_ITEM_SIZE 255
7
342M
#define HOEDOWN_HASH_FNV_PRIME 0x01000193
8
119k
#define HOEDOWN_HASH_FNV_OFFSET_BASIS 0x811c9dc5
9
10
static char *
11
hoedown_hash_strndup(const char* str, size_t n)
12
20.7k
{
13
20.7k
    if (str) {
14
20.7k
        char *s = (char *)malloc(sizeof(char) * (n + 1));
15
20.7k
        if (s) {
16
20.7k
            memcpy(s, str, n);
17
20.7k
            s[n] = '\0';
18
20.7k
        }
19
20.7k
        return s;
20
20.7k
    }
21
0
    return NULL;
22
20.7k
}
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
119k
{
36
119k
    unsigned int hash = HOEDOWN_HASH_FNV_OFFSET_BASIS;
37
38
119k
    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
342M
    while (key < max) {
47
342M
        hash *= HOEDOWN_HASH_FNV_PRIME;
48
342M
        hash ^= *key;
49
342M
        key++;
50
342M
    }
51
52
119k
    hash %= limit;
53
54
119k
    return hash;
55
119k
}
56
57
static hoedown_hash_item *
58
hoedown_hash_item_new(void)
59
20.7k
{
60
20.7k
    hoedown_hash_item *item;
61
62
20.7k
    item = (hoedown_hash_item *)malloc(sizeof(hoedown_hash_item));
63
20.7k
    if (!item) {
64
0
        return NULL;
65
0
    }
66
67
20.7k
    item->key = NULL;
68
20.7k
    item->value = NULL;
69
20.7k
    item->destruct = NULL;
70
20.7k
    item->next = NULL;
71
20.7k
    item->tail = NULL;
72
73
20.7k
    return item;
74
20.7k
}
75
76
static void
77
hoedown_hash_item_free(hoedown_hash_item *item)
78
20.7k
{
79
20.7k
    if (item) {
80
20.7k
        if (item->next) {
81
2.52k
            hoedown_hash_item_free(item->next);
82
2.52k
        }
83
20.7k
        if (item->key) {
84
20.7k
            free(item->key);
85
20.7k
        }
86
20.7k
        if (item->destruct) {
87
20.7k
            (item->destruct)(item->value);
88
20.7k
        }
89
20.7k
        free(item);
90
20.7k
    }
91
20.7k
}
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
20.7k
{
97
20.7k
    hoedown_hash_item *entry;
98
99
20.7k
    if (!item || !key || !value) {
100
0
        return 1;
101
0
    }
102
103
20.7k
    if (item->key != NULL) {
104
2.52k
        entry = hoedown_hash_item_new();
105
2.52k
        if (!entry) {
106
0
            return 1;
107
0
        }
108
18.2k
    } else {
109
18.2k
        entry = item;
110
18.2k
    }
111
112
20.7k
    if (key_len > 0) {
113
20.7k
        entry->key = hoedown_hash_strndup(key, key_len);
114
20.7k
    } else {
115
0
        entry->key = hoedown_hash_strdup(key);
116
0
    }
117
20.7k
    entry->value = value;
118
20.7k
    entry->destruct = destruct;
119
120
20.7k
    if (item->tail) {
121
2.52k
        item->tail->next = entry;
122
18.2k
    } else if (item != entry) {
123
0
        item->next = entry;
124
0
    }
125
20.7k
    item->tail = entry;
126
127
20.7k
    return 0;
128
20.7k
}
129
130
hoedown_hash *
131
hoedown_hash_new(size_t size)
132
9.36k
{
133
9.36k
    hoedown_hash *hash;
134
9.36k
    size_t items_size;
135
136
9.36k
    hash = (hoedown_hash *)malloc(sizeof(hoedown_hash));
137
9.36k
    if (!hash) {
138
0
        return NULL;
139
0
    }
140
141
9.36k
    if (size == 0) {
142
9.36k
        size = HOEDOWN_HASH_ITEM_SIZE;
143
9.36k
    }
144
145
9.36k
    items_size = sizeof(hoedown_hash_item *) * size;
146
147
9.36k
    hash->items = (hoedown_hash_item **)malloc(items_size);
148
9.36k
    if (!hash->items) {
149
0
        free(hash);
150
0
        return NULL;
151
0
    }
152
153
9.36k
    memset(hash->items, 0, items_size);
154
155
9.36k
    hash->asize = size;
156
157
9.36k
    return hash;
158
9.36k
}
159
160
void
161
hoedown_hash_free(hoedown_hash *hash)
162
9.36k
{
163
9.36k
    if (hash) {
164
9.36k
        if (hash->items) {
165
9.36k
            size_t i = 0;
166
2.39M
            while (i < hash->asize) {
167
2.38M
                if (hash->items[i]) {
168
18.2k
                    hoedown_hash_item_free(hash->items[i]);
169
18.2k
                }
170
2.38M
                ++i;
171
2.38M
            }
172
9.36k
            free(hash->items);
173
9.36k
        }
174
9.36k
        free(hash);
175
9.36k
    }
176
9.36k
}
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
20.7k
{
182
20.7k
    unsigned int h;
183
184
20.7k
    if (!hash || !key || !value) {
185
0
        return 1;
186
0
    }
187
188
20.7k
    h = hoedown_hash_fnv(key, key + key_len, hash->asize);
189
190
20.7k
    if (!hash->items[h]) {
191
18.2k
        hash->items[h] = hoedown_hash_item_new();
192
18.2k
        if (!hash->items[h]) {
193
0
            return 1;
194
0
        }
195
18.2k
    }
196
197
20.7k
    if (hoedown_hash_item_push(hash->items[h], key, key_len,
198
20.7k
                               value, destruct) != 0) {
199
0
        return 1;
200
0
    }
201
202
20.7k
    return 0;
203
20.7k
}
204
205
void *
206
hoedown_hash_find(hoedown_hash *hash, char *key, size_t key_len)
207
99.1k
{
208
99.1k
    unsigned int h;
209
210
99.1k
    if (!hash || !key) {
211
0
        return NULL;
212
0
    }
213
214
99.1k
    h = hoedown_hash_fnv(key, key + key_len, hash->asize);
215
216
99.1k
    if (hash->items[h]) {
217
80.9k
        hoedown_hash_item *item = hash->items[h];
218
89.1k
        while (item != NULL) {
219
86.6k
            if (item->key && strncmp(item->key, key, key_len) == 0) {
220
78.3k
                return item->value;
221
78.3k
            }
222
8.25k
            item = item->next;
223
8.25k
        }
224
80.9k
    }
225
226
20.7k
    return NULL;
227
99.1k
}