Coverage Report

Created: 2025-06-22 06:49

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