Coverage Report

Created: 2026-07-16 06:23

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/work/open62541/src_generated/mdnsd/xht.c
Line
Count
Source
1
/* Simple string->void* hashtable, very static and bare minimal, but efficient
2
 *
3
 * Copyright (c) 2003  Jeremie Miller <jer@jabber.org>
4
 * Copyright (c) 2016-2026  Joachim Wiberg <troglobit@gmail.com>
5
 * All rights reserved.
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions are met:
9
 *     * Redistributions of source code must retain the above copyright
10
 *       notice, this list of conditions and the following disclaimer.
11
 *     * Redistributions in binary form must reproduce the above copyright
12
 *       notice, this list of conditions and the following disclaimer in the
13
 *       documentation and/or other materials provided with the distribution.
14
 *     * Neither the name of the copyright holders nor the names of its
15
 *       contributors may be used to endorse or promote products derived from
16
 *       this software without specific prior written permission.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
 * POSSIBILITY OF SUCH DAMAGE.
29
 */
30
31
#include "config.h"
32
#include "xht.h"
33
#include <string.h>
34
#include <stdlib.h>
35
36
typedef struct xhn {
37
  char flag;
38
  struct xhn *next;
39
  union {
40
    char *key;
41
    const char *ckey;
42
  } u;
43
  void *val;
44
} xhn_t;
45
46
struct xht {
47
  int prime;
48
  xhn_t *zen;
49
};
50
51
/* Generates a hash code for a string.
52
 * This function uses the ELF hashing algorithm as reprinted in 
53
 * Andrew Binstock, "Hashing Rehashed," Dr. Dobb's Journal, April 1996.
54
 */
55
static int _xhter(const char *s)
56
21.4k
{
57
  /* ELF hash uses unsigned chars and unsigned arithmetic for portability */
58
21.4k
  const unsigned char *name = (const unsigned char *)s;
59
21.4k
  unsigned long h = 0, g;
60
61
523k
  while (*name) {   /* do some fancy bitwanking on the string */
62
502k
    h = (h << 4) + (unsigned long)(*name++);
63
502k
    if ((g = (h & 0xF0000000UL)) != 0)
64
361k
      h ^= (g >> 24);
65
502k
    h &= ~g;
66
67
502k
  }
68
69
21.4k
  return (int)h;
70
21.4k
}
71
72
73
static xhn_t *_xht_node_find(xhn_t *n, const char *key)
74
21.4k
{
75
113k
  for (; n != 0; n = n->next)
76
99.3k
    if (n->u.ckey && strcmp(key, n->u.ckey) == 0)
77
6.78k
      return n;
78
14.6k
  return 0;
79
21.4k
}
80
81
82
xht_t *xht_new(int prime)
83
945
{
84
945
  xht_t *xnew;
85
86
945
  xnew = malloc(sizeof(struct xht));
87
945
  if (!xnew)
88
0
    return NULL;
89
90
945
  xnew->prime = prime;
91
945
  xnew->zen = calloc(1, sizeof(struct xhn) * prime);  /* array of xhn_t size of prime */
92
945
  if (!xnew->zen) {
93
0
    free(xnew);
94
0
    return NULL;
95
0
  }
96
97
945
  return xnew;
98
945
}
99
100
/* does the set work, used by xht_set and xht_store */
101
static xhn_t *_xht_set(xht_t *h, const char *key, void *val, char flag)
102
21.4k
{
103
21.4k
  int i;
104
21.4k
  xhn_t *n;
105
106
  /* get our index for this key */
107
21.4k
  i = _xhter(key) % h->prime;
108
109
  /* check for existing key first, or find an empty one */
110
21.4k
  n = _xht_node_find(&h->zen[i], key);
111
21.4k
  if (n == NULL) {
112
82.8k
    for (n = &h->zen[i]; n != 0; n = n->next) {
113
71.7k
      if (n->val == NULL)
114
3.55k
        break;
115
71.7k
    }
116
14.6k
  }
117
118
  /* if none, make a new one, link into this index */
119
21.4k
  if (n == NULL) {
120
11.0k
    n = calloc(1, sizeof(struct xhn));
121
11.0k
    if (n == NULL)
122
0
      return NULL;
123
124
11.0k
    n->next = h->zen[i].next;
125
11.0k
    h->zen[i].next = n;
126
11.0k
  }
127
128
  /* When flag is set, we manage their mem and free em first */
129
21.4k
  if (n->flag) {
130
6.78k
    free(n->u.key);
131
6.78k
    free(n->val);
132
6.78k
  }
133
134
21.4k
  n->flag = flag;
135
21.4k
  n->u.ckey = key;
136
21.4k
  n->val = val;
137
138
21.4k
  return n;
139
21.4k
}
140
141
void xht_set(xht_t *h, const char *key, void *val)
142
558
{
143
558
  if (h == NULL || h->zen == NULL || key == NULL)
144
0
    return;
145
558
  _xht_set(h, key, val, 0);
146
558
}
147
148
void xht_store(xht_t *h, const char *key, int klen, void *val, int vlen)
149
13.2k
{
150
13.2k
  char *ckey, *cval;
151
152
13.2k
  if (h == NULL || h->zen == NULL || key == NULL || klen == 0 || val == NULL)
153
895
    return;
154
155
12.3k
  ckey = malloc(klen + 1);
156
12.3k
  if (!ckey)
157
0
    return;
158
159
12.3k
  memcpy(ckey, key, klen);
160
12.3k
  ckey[klen] = '\0';
161
162
12.3k
  cval = malloc(vlen + 1);
163
12.3k
  if (!cval) {
164
0
    free(ckey);
165
0
    return;
166
0
  }
167
168
12.3k
  memcpy(cval, val, vlen);
169
12.3k
  cval[vlen] = '\0';  /* convenience, in case it was a string too */
170
12.3k
  if (!_xht_set(h, ckey, cval, 1)) {
171
0
    free(ckey);
172
0
    free(cval);
173
0
  }
174
12.3k
}
175
176
177
void *xht_get(xht_t *h, const char *key)
178
0
{
179
0
  xhn_t *n;
180
181
0
  if (h == NULL || h->zen == NULL || key == NULL)
182
0
    return NULL;
183
184
0
  n = _xht_node_find(&h->zen[_xhter(key) % h->prime], key);
185
0
  if (n == NULL)
186
0
    return NULL;
187
188
0
  return n->val;
189
0
}
190
191
192
void xht_free(xht_t *h)
193
945
{
194
945
  int i;
195
196
945
  if (h == NULL)
197
0
    return;
198
199
19.3k
  for (i = 0; i < h->prime; i++) {
200
18.3k
    xhn_t *n = &h->zen[i];
201
202
18.3k
    if (n->flag) {
203
2.99k
      free(n->u.key);
204
2.99k
      n->u.key = NULL;
205
2.99k
      free(n->val);
206
2.99k
      n->val = NULL;
207
2.99k
    }
208
209
29.4k
    for (n = (&h->zen[i])->next; n != 0;) {
210
11.0k
      xhn_t *f = n->next;
211
212
11.0k
      n->next = NULL;
213
11.0k
      if (n->flag) {
214
11.0k
        free(n->u.key);
215
11.0k
        n->u.key = NULL;
216
11.0k
        free(n->val);
217
11.0k
        n->val = NULL;
218
11.0k
      }
219
11.0k
      free(n);
220
11.0k
      n = f;
221
11.0k
    }
222
18.3k
  }
223
224
945
  free(h->zen);
225
945
  h->zen = NULL;
226
945
  free(h);
227
945
}
228
229
void xht_walk(xht_t *h, xht_walker w, void *arg)
230
1.85k
{
231
1.85k
  int i;
232
1.85k
  xhn_t *n;
233
234
1.85k
  if (h == NULL || h->zen == NULL || w == NULL)
235
0
    return;
236
237
37.7k
  for (i = 0; i < h->prime; i++) {
238
93.8k
    for (n = &h->zen[i]; n != 0; n = n->next) {
239
58.0k
      if (n->u.ckey != 0 && n->val != 0)
240
29.2k
        (*w)(h, n->u.ckey, n->val, arg);
241
58.0k
    }
242
35.8k
  }
243
1.85k
}