Coverage Report

Created: 2023-08-07 06:59

/src/p11-kit/common/dict.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2004 Stefan Walter
3
 * Copyright (c) 2011 Collabora Ltd.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 *
9
 *     * Redistributions of source code must retain the above
10
 *       copyright notice, this list of conditions and the
11
 *       following disclaimer.
12
 *     * Redistributions in binary form must reproduce the
13
 *       above copyright notice, this list of conditions and
14
 *       the following disclaimer in the documentation and/or
15
 *       other materials provided with the distribution.
16
 *     * The names of contributors to this software may not be
17
 *       used to endorse or promote products derived from this
18
 *       software without specific prior written permission.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30
 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31
 * DAMAGE.
32
 */
33
34
#include "config.h"
35
36
#include "debug.h"
37
#include "dict.h"
38
#include "hash.h"
39
40
#include <sys/types.h>
41
42
#include <assert.h>
43
#include <stdint.h>
44
#include <stdlib.h>
45
#include <string.h>
46
47
struct _p11_dict {
48
  p11_dict_hasher hash_func;
49
  p11_dict_equals equal_func;
50
  p11_destroyer key_destroy_func;
51
  p11_destroyer value_destroy_func;
52
53
  struct _p11_dictbucket **buckets;
54
  unsigned int num_items;
55
  unsigned int num_buckets;
56
};
57
58
typedef struct _p11_dictbucket {
59
  void *key;
60
  unsigned int hashed;
61
  void *value;
62
  struct _p11_dictbucket *next;
63
} dictbucket;
64
65
static dictbucket *
66
next_entry (p11_dictiter *iter)
67
266
{
68
266
  dictbucket *bucket = iter->next;
69
950
  while (!bucket) {
70
760
    if (iter->index >= iter->dict->num_buckets)
71
76
      return NULL;
72
684
    bucket = iter->dict->buckets[iter->index++];
73
684
  }
74
190
  iter->next = bucket->next;
75
190
  return bucket;
76
266
}
77
78
79
bool
80
p11_dict_next (p11_dictiter *iter,
81
               void **key,
82
               void **value)
83
0
{
84
0
  dictbucket *bucket = next_entry (iter);
85
0
  if (bucket == NULL)
86
0
    return false;
87
0
  if (key)
88
0
    *key = bucket->key;
89
0
  if (value)
90
0
    *value = bucket->value;
91
0
  return true;
92
0
}
93
94
void
95
p11_dict_iterate (p11_dict *dict,
96
                  p11_dictiter *iter)
97
76
{
98
76
  iter->dict = dict;
99
76
  iter->index = 0;
100
76
  iter->next = NULL;
101
76
}
102
103
static dictbucket **
104
lookup_or_create_bucket (p11_dict *dict,
105
                         const void *key,
106
                         bool create)
107
380
{
108
380
  dictbucket **bucketp;
109
380
  unsigned int hash;
110
111
  /* Perform the hashing */
112
380
  hash = dict->hash_func (key);
113
114
  /* scan linked list */
115
380
  for (bucketp = &dict->buckets[hash % dict->num_buckets];
116
380
       *bucketp != NULL; bucketp = &(*bucketp)->next) {
117
0
    if((*bucketp)->hashed == hash && dict->equal_func ((*bucketp)->key, key))
118
0
      break;
119
0
  }
120
121
380
  if ((*bucketp) != NULL || !create)
122
0
    return bucketp;
123
124
  /* add a new entry for non-NULL val */
125
380
  (*bucketp) = calloc (1, sizeof (dictbucket));
126
127
380
  if (*bucketp != NULL) {
128
380
    (*bucketp)->key = (void*)key;
129
380
    (*bucketp)->hashed = hash;
130
380
    dict->num_items++;
131
380
  }
132
133
380
  return bucketp;
134
380
}
135
136
void *
137
p11_dict_get (p11_dict *dict,
138
              const void *key)
139
0
{
140
0
  dictbucket **bucketp;
141
142
0
  bucketp = lookup_or_create_bucket (dict, key, false);
143
0
  if (bucketp && *bucketp)
144
0
    return (void*)((*bucketp)->value);
145
0
  else
146
0
    return NULL;
147
0
}
148
149
bool
150
p11_dict_set (p11_dict *dict,
151
              void *key,
152
              void *val)
153
380
{
154
380
  dictbucket **bucketp;
155
380
  p11_dictiter iter;
156
380
  dictbucket *bucket;
157
380
  dictbucket **new_buckets;
158
380
  unsigned int num_buckets;
159
160
380
  bucketp = lookup_or_create_bucket (dict, key, true);
161
380
  if(bucketp && *bucketp) {
162
163
    /* Destroy the previous key */
164
380
    if ((*bucketp)->key && (*bucketp)->key != key && dict->key_destroy_func)
165
0
      dict->key_destroy_func ((*bucketp)->key);
166
167
    /* Destroy the previous value */
168
380
    if ((*bucketp)->value && (*bucketp)->value != val && dict->value_destroy_func)
169
0
      dict->value_destroy_func ((*bucketp)->value);
170
171
    /* replace entry */
172
380
    (*bucketp)->key = key;
173
380
    (*bucketp)->value = val;
174
175
    /* check that the collision rate isn't too high */
176
380
    if (dict->num_items > dict->num_buckets) {
177
0
      num_buckets = dict->num_buckets * 2 + 1;
178
0
      new_buckets = (dictbucket **)calloc (num_buckets, sizeof (dictbucket *));
179
180
      /* Ignore failures, maybe we can expand later */
181
0
      if(new_buckets) {
182
0
        p11_dict_iterate (dict, &iter);
183
0
        while ((bucket = next_entry (&iter)) != NULL) {
184
0
          unsigned int i = bucket->hashed % num_buckets;
185
0
          bucket->next = new_buckets[i];
186
0
          new_buckets[i] = bucket;
187
0
        }
188
189
0
        free (dict->buckets);
190
0
        dict->buckets = new_buckets;
191
0
        dict->num_buckets = num_buckets;
192
0
      }
193
0
    }
194
195
380
    return true;
196
380
  }
197
198
0
  return_val_if_reached (false);
199
0
}
200
201
bool
202
p11_dict_steal (p11_dict *dict,
203
                const void *key,
204
                void **stolen_key,
205
                void **stolen_value)
206
0
{
207
0
  dictbucket **bucketp;
208
209
0
  bucketp = lookup_or_create_bucket (dict, key, false);
210
0
  if (bucketp && *bucketp) {
211
0
    dictbucket *old = *bucketp;
212
0
    *bucketp = (*bucketp)->next;
213
0
    --dict->num_items;
214
0
    if (stolen_key)
215
0
      *stolen_key = old->key;
216
0
    if (stolen_value)
217
0
      *stolen_value = old->value;
218
0
    free (old);
219
0
    return true;
220
0
  }
221
222
0
  return false;
223
224
0
}
225
226
bool
227
p11_dict_remove (p11_dict *dict,
228
                 const void *key)
229
0
{
230
0
  void *old_key;
231
0
  void *old_value;
232
233
0
  if (!p11_dict_steal (dict, key, &old_key, &old_value))
234
0
    return false;
235
236
0
  if (dict->key_destroy_func)
237
0
    dict->key_destroy_func (old_key);
238
0
  if (dict->value_destroy_func)
239
0
    dict->value_destroy_func (old_value);
240
0
  return true;
241
0
}
242
243
void
244
p11_dict_clear (p11_dict *dict)
245
76
{
246
76
  dictbucket *bucket, *next;
247
76
  unsigned int i;
248
249
  /* Free all entries in the array */
250
760
  for (i = 0; i < dict->num_buckets; ++i) {
251
684
    bucket = dict->buckets[i];
252
869
    while (bucket != NULL) {
253
185
      next = bucket->next;
254
185
      if (dict->key_destroy_func)
255
0
        dict->key_destroy_func (bucket->key);
256
185
      if (dict->value_destroy_func)
257
185
        dict->value_destroy_func (bucket->value);
258
185
      free (bucket);
259
185
      bucket = next;
260
185
    }
261
684
  }
262
263
76
  memset (dict->buckets, 0, dict->num_buckets * sizeof (dictbucket *));
264
76
  dict->num_items = 0;
265
76
}
266
267
p11_dict *
268
p11_dict_new (p11_dict_hasher hash_func,
269
              p11_dict_equals equal_func,
270
              p11_destroyer key_destroy_func,
271
              p11_destroyer value_destroy_func)
272
77
{
273
77
  p11_dict *dict;
274
275
77
  assert (hash_func);
276
77
  assert (equal_func);
277
278
77
  dict = malloc (sizeof (p11_dict));
279
77
  if (dict) {
280
77
    dict->hash_func = hash_func;
281
77
    dict->equal_func = equal_func;
282
77
    dict->key_destroy_func = key_destroy_func;
283
77
    dict->value_destroy_func = value_destroy_func;
284
285
77
    dict->num_buckets = 9;
286
77
    dict->buckets = (dictbucket **)calloc (dict->num_buckets, sizeof (dictbucket *));
287
77
    if (!dict->buckets) {
288
0
      free (dict);
289
0
      return NULL;
290
0
    }
291
292
77
    dict->num_items = 0;
293
77
  }
294
295
77
  return dict;
296
77
}
297
298
void
299
p11_dict_free (p11_dict *dict)
300
76
{
301
76
  dictbucket *bucket;
302
76
  p11_dictiter iter;
303
304
76
  if (!dict)
305
0
    return;
306
307
76
  p11_dict_iterate (dict, &iter);
308
266
  while ((bucket = next_entry (&iter)) != NULL) {
309
190
    if (dict->key_destroy_func)
310
0
      dict->key_destroy_func (bucket->key);
311
190
    if (dict->value_destroy_func)
312
190
      dict->value_destroy_func (bucket->value);
313
190
    free (bucket);
314
190
  }
315
316
76
  if (dict->buckets)
317
76
    free (dict->buckets);
318
319
76
  free (dict);
320
76
}
321
322
unsigned int
323
p11_dict_size (p11_dict *dict)
324
0
{
325
0
  return dict->num_items;
326
0
}
327
328
unsigned int
329
p11_dict_str_hash (const void *string)
330
0
{
331
0
  uint32_t hash;
332
0
  p11_hash_murmur3 (&hash, string, strlen (string), NULL);
333
0
  return hash;
334
0
}
335
336
bool
337
p11_dict_str_equal (const void *string_one,
338
                    const void *string_two)
339
0
{
340
0
  assert (string_one);
341
0
  assert (string_two);
342
343
0
  return strcmp (string_one, string_two) == 0;
344
0
}
345
346
unsigned int
347
p11_dict_ulongptr_hash (const void *to_ulong)
348
0
{
349
0
  assert (to_ulong);
350
0
  return (unsigned int)*((unsigned long*)to_ulong);
351
0
}
352
353
bool
354
p11_dict_ulongptr_equal (const void *ulong_one,
355
                         const void *ulong_two)
356
0
{
357
0
  assert (ulong_one);
358
0
  assert (ulong_two);
359
0
  return *((unsigned long*)ulong_one) == *((unsigned long*)ulong_two);
360
0
}
361
362
unsigned int
363
p11_dict_intptr_hash (const void *to_int)
364
0
{
365
0
  assert (to_int);
366
0
  return (unsigned int)*((int*)to_int);
367
0
}
368
369
bool
370
p11_dict_intptr_equal (const void *int_one,
371
                        const void *int_two)
372
0
{
373
0
  assert (int_one);
374
0
  assert (int_two);
375
0
  return *((int*)int_one) == *((int*)int_two);
376
0
}
377
378
unsigned int
379
p11_dict_direct_hash (const void *ptr)
380
380
{
381
380
  return (unsigned int)(size_t)ptr;
382
380
}
383
384
bool
385
p11_dict_direct_equal (const void *ptr_one,
386
                       const void *ptr_two)
387
0
{
388
0
  return ptr_one == ptr_two;
389
0
}