Coverage Report

Created: 2025-07-18 06:07

/src/openvswitch/lib/simap.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2009, 2010, 2011, 2012, 2017, 2019 Nicira, Inc.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at:
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
17
#include <config.h>
18
#include "simap.h"
19
#include "hash.h"
20
#include "util.h"
21
22
static size_t hash_name(const char *, size_t length);
23
static struct simap_node *simap_find__(const struct simap *,
24
                                       const char *name, size_t name_len,
25
                                       size_t hash);
26
static struct simap_node *simap_add_nocopy__(struct simap *,
27
                                             char *name, unsigned int data,
28
                                             size_t hash);
29
static int compare_nodes_by_name(const void *a_, const void *b_);
30
31
/* Initializes 'simap' as an empty string-to-integer map. */
32
void
33
simap_init(struct simap *simap)
34
0
{
35
0
    hmap_init(&simap->map);
36
0
}
37
38
/* Frees all the data that 'simap' contains. */
39
void
40
simap_destroy(struct simap *simap)
41
0
{
42
0
    if (simap) {
43
0
        simap_clear(simap);
44
0
        hmap_destroy(&simap->map);
45
0
    }
46
0
}
47
48
/* Exchanges the contents of 'a' and 'b'. */
49
void
50
simap_swap(struct simap *a, struct simap *b)
51
0
{
52
0
    hmap_swap(&a->map, &b->map);
53
0
}
54
55
/* Adjusts 'simap' so that it is still valid after it has been moved around in
56
 * memory (e.g. due to realloc()). */
57
void
58
simap_moved(struct simap *simap)
59
0
{
60
0
    hmap_moved(&simap->map);
61
0
}
62
63
/* Removes all of the mappings from 'simap' and frees them. */
64
void
65
simap_clear(struct simap *simap)
66
0
{
67
0
    struct simap_node *node;
68
69
0
    SIMAP_FOR_EACH_SAFE (node, simap) {
70
0
        hmap_remove(&simap->map, &node->node);
71
0
        free(node->name);
72
0
        free(node);
73
0
    }
74
0
}
75
76
/* Returns true if 'simap' contains no mappings, false if it contains at least
77
 * one. */
78
bool
79
simap_is_empty(const struct simap *simap)
80
0
{
81
0
    return hmap_is_empty(&simap->map);
82
0
}
83
84
/* Returns the number of mappings in 'simap'. */
85
size_t
86
simap_count(const struct simap *simap)
87
0
{
88
0
    ovs_assert(simap);
89
0
    return hmap_count(&simap->map);
90
0
}
91
92
/* Inserts a mapping from 'name' to 'data' into 'simap', replacing any
93
 * existing mapping for 'name'.  Returns true if a new mapping was added,
94
 * false if an existing mapping's value was replaced.
95
 *
96
 * The caller retains ownership of 'name'. */
97
bool
98
simap_put(struct simap *simap, const char *name, unsigned int data)
99
0
{
100
0
    size_t length = strlen(name);
101
0
    size_t hash = hash_name(name, length);
102
0
    struct simap_node *node;
103
104
0
    node = simap_find__(simap, name, length, hash);
105
0
    if (node) {
106
0
        node->data = data;
107
0
        return false;
108
0
    } else {
109
0
        simap_add_nocopy__(simap, xmemdup0(name, length), data, hash);
110
0
        return true;
111
0
    }
112
0
}
113
114
/* Increases the data value in the mapping for 'name' by 'amt', or inserts a
115
 * mapping from 'name' to 'amt' if no such mapping exists.  Returns the
116
 * new total data value for the mapping.
117
 *
118
 * If 'amt' is zero, this function does nothing and returns 0.  That is, this
119
 * function won't create a mapping with a initial value of 0.
120
 *
121
 * The caller retains ownership of 'name'. */
122
unsigned int
123
simap_increase(struct simap *simap, const char *name, unsigned int amt)
124
0
{
125
0
    if (amt) {
126
0
        size_t length = strlen(name);
127
0
        size_t hash = hash_name(name, length);
128
0
        struct simap_node *node;
129
130
0
        node = simap_find__(simap, name, length, hash);
131
0
        if (node) {
132
0
            node->data += amt;
133
0
        } else {
134
0
            node = simap_add_nocopy__(simap, xmemdup0(name, length),
135
0
                                      amt, hash);
136
0
        }
137
0
        return node->data;
138
0
    } else {
139
0
        return 0;
140
0
    }
141
0
}
142
143
/* Deletes 'node' from 'simap' and frees its associated memory. */
144
void
145
simap_delete(struct simap *simap, struct simap_node *node)
146
0
{
147
0
    hmap_remove(&simap->map, &node->node);
148
0
    free(node->name);
149
0
    free(node);
150
0
}
151
152
/* Searches for 'name' in 'simap'.  If found, deletes it and returns true.  If
153
 * not found, returns false without modifying 'simap'. */
154
bool
155
simap_find_and_delete(struct simap *simap, const char *name)
156
0
{
157
0
    struct simap_node *node = simap_find(simap, name);
158
0
    if (node) {
159
0
        simap_delete(simap, node);
160
0
        return true;
161
0
    }
162
0
    return false;
163
0
}
164
165
/* Searches 'simap' for a mapping with the given 'name'.  Returns it, if found,
166
 * or a null pointer if not. */
167
struct simap_node *
168
simap_find(const struct simap *simap, const char *name)
169
0
{
170
0
    return simap_find_len(simap, name, strlen(name));
171
0
}
172
173
/* Searches 'simap' for a mapping whose name is the first 'name_len' bytes
174
 * starting at 'name'.  Returns it, if found, or a null pointer if not. */
175
struct simap_node *
176
simap_find_len(const struct simap *simap, const char *name, size_t len)
177
0
{
178
0
    return simap_find__(simap, name, len, hash_name(name, len));
179
0
}
180
181
/* Searches 'simap' for a mapping with the given 'name'.  Returns the
182
 * associated data value, if found, otherwise zero. */
183
unsigned int
184
simap_get(const struct simap *simap, const char *name)
185
0
{
186
0
    struct simap_node *node = simap_find(simap, name);
187
0
    return node ? node->data : 0;
188
0
}
189
190
/* Returns true if 'simap' contains a copy of 'name', false otherwise. */
191
bool
192
simap_contains(const struct simap *simap, const char *name)
193
0
{
194
0
    return simap_find(simap, name) != NULL;
195
0
}
196
197
/* Returns an array that contains a pointer to each mapping in 'simap',
198
 * ordered alphabetically by name.  The returned array has simap_count(simap)
199
 * elements.
200
 *
201
 * The caller is responsible for freeing the returned array (with free()).  It
202
 * should not free the individual "simap_node"s in the array, because they are
203
 * still part of 'simap'. */
204
const struct simap_node **
205
simap_sort(const struct simap *simap)
206
0
{
207
0
    if (simap_is_empty(simap)) {
208
0
        return NULL;
209
0
    } else {
210
0
        const struct simap_node **nodes;
211
0
        struct simap_node *node;
212
0
        size_t i, n;
213
214
0
        n = simap_count(simap);
215
0
        nodes = xmalloc(n * sizeof *nodes);
216
0
        i = 0;
217
0
        SIMAP_FOR_EACH (node, simap) {
218
0
            nodes[i++] = node;
219
0
        }
220
0
        ovs_assert(i == n);
221
222
0
        qsort(nodes, n, sizeof *nodes, compare_nodes_by_name);
223
224
0
        return nodes;
225
0
    }
226
0
}
227
228
/* Returns true if the two maps are equal, meaning that they have the same set
229
 * of key-value pairs, otherwise false. */
230
bool
231
simap_equal(const struct simap *a, const struct simap *b)
232
0
{
233
0
    if (simap_count(a) != simap_count(b)) {
234
0
        return false;
235
0
    }
236
237
0
    const struct simap_node *an;
238
0
    SIMAP_FOR_EACH (an, a) {
239
0
        const struct simap_node *bn = simap_find(b, an->name);
240
0
        if (!bn || an->data != bn->data) {
241
0
            return false;
242
0
        }
243
0
    }
244
0
    return true;
245
0
}
246
247
uint32_t
248
simap_hash(const struct simap *simap)
249
0
{
250
0
    uint32_t hash = 0;
251
252
0
    const struct simap_node *node;
253
0
    SIMAP_FOR_EACH (node, simap) {
254
0
        hash ^= hash_int(node->data,
255
0
                         hash_name(node->name, strlen(node->name)));
256
0
    }
257
0
    return hash;
258
0
}
259
260
static size_t
261
hash_name(const char *name, size_t length)
262
0
{
263
0
    return hash_bytes(name, length, 0);
264
0
}
265
266
static struct simap_node *
267
simap_find__(const struct simap *simap, const char *name, size_t name_len,
268
             size_t hash)
269
0
{
270
0
    struct simap_node *node;
271
272
0
    HMAP_FOR_EACH_WITH_HASH (node, node, hash, &simap->map) {
273
0
        if (!strncmp(node->name, name, name_len) && !node->name[name_len]) {
274
0
            return node;
275
0
        }
276
0
    }
277
0
    return NULL;
278
0
}
279
280
static struct simap_node *
281
simap_add_nocopy__(struct simap *simap, char *name, unsigned int data,
282
                   size_t hash)
283
0
{
284
0
    struct simap_node *node = xmalloc(sizeof *node);
285
0
    node->name = name;
286
0
    node->data = data;
287
0
    hmap_insert(&simap->map, &node->node, hash);
288
0
    return node;
289
0
}
290
291
static int
292
compare_nodes_by_name(const void *a_, const void *b_)
293
0
{
294
0
    const struct simap_node *const *a = a_;
295
0
    const struct simap_node *const *b = b_;
296
0
    return strcmp((*a)->name, (*b)->name);
297
0
}