Replace most uses of assert by ovs_assert.
[sliver-openvswitch.git] / lib / smap.c
1 /* Copyright (c) 2012 Nicira, Inc.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License. */
14
15 #include <config.h>
16 #include "smap.h"
17
18 #include "hash.h"
19 #include "json.h"
20
21 static struct smap_node *smap_add__(struct smap *, char *, void *,
22                                     size_t hash);
23 static struct smap_node *smap_find__(const struct smap *, const char *key,
24                                      size_t key_len, size_t hash);
25 static int compare_nodes_by_key(const void *, const void *);
26 \f
27 /* Public Functions. */
28
29 void
30 smap_init(struct smap *smap)
31 {
32     hmap_init(&smap->map);
33 }
34
35 void
36 smap_destroy(struct smap *smap)
37 {
38     if (smap) {
39         smap_clear(smap);
40         hmap_destroy(&smap->map);
41     }
42 }
43
44 /* Adds 'key' paired with 'value' to 'smap'.  It is the caller's responsibility
45  * to avoid duplicate keys if desirable. */
46 struct smap_node *
47 smap_add(struct smap *smap, const char *key, const char *value)
48 {
49     size_t key_len = strlen(key);
50     return smap_add__(smap, xmemdup0(key, key_len), xstrdup(value),
51                       hash_bytes(key, key_len, 0));
52 }
53
54 /* Attempts to add 'key' to 'smap' associated with 'value'.  If 'key' already
55  * exists in 'smap', does nothing and returns false.  Otherwise, performs the
56  * addition and returns true. */
57 bool
58 smap_add_once(struct smap *smap, const char *key, const char *value)
59 {
60     if (!smap_get(smap, key)) {
61         smap_add(smap, key, value);
62         return true;
63     } else {
64         return false;
65     }
66 }
67
68 /* Adds 'key' paired with a value derived from 'format' (similar to printf).
69  * It is the caller's responsibility to avoid duplicate keys if desirable. */
70 void
71 smap_add_format(struct smap *smap, const char *key, const char *format, ...)
72 {
73     size_t key_len;
74     va_list args;
75     char *value;
76
77     va_start(args, format);
78     value = xvasprintf(format, args);
79     va_end(args);
80
81     key_len = strlen(key);
82     smap_add__(smap, xmemdup0(key, key_len), value,
83                hash_bytes(key, key_len, 0));
84 }
85
86 /* Searches for 'key' in 'smap'.  If it does not already exists, adds it.
87  * Otherwise, changes its value to 'value'. */
88 void
89 smap_replace(struct smap *smap, const char *key, const char *value)
90 {
91     size_t  key_len = strlen(key);
92     size_t hash = hash_bytes(key, key_len, 0);
93
94     struct smap_node *node;
95
96     node = smap_find__(smap, key, key_len, hash);
97     if (node) {
98         free(node->value);
99         node->value = xstrdup(value);
100     } else {
101         smap_add__(smap, xmemdup0(key, key_len), xstrdup(value), hash);
102     }
103 }
104
105 /* If 'key' is in 'smap', removes it.  Otherwise does nothing. */
106 void
107 smap_remove(struct smap *smap, const char *key)
108 {
109     struct smap_node *node = smap_get_node(smap, key);
110
111     if (node) {
112         smap_remove_node(smap, node);
113     }
114 }
115
116 /* Removes 'node' from 'smap'. */
117 void
118 smap_remove_node(struct smap *smap, struct smap_node *node)
119 {
120     hmap_remove(&smap->map, &node->node);
121     free(node->key);
122     free(node->value);
123     free(node);
124 }
125
126 /* Deletes 'node' from 'smap'.
127  *
128  * If 'keyp' is nonnull, stores the node's key in '*keyp' and transfers
129  * ownership to the caller.  Otherwise, frees the node's key.  Similarly for
130  * 'valuep' and the node's value. */
131 void
132 smap_steal(struct smap *smap, struct smap_node *node,
133            char **keyp, char **valuep)
134 {
135     if (keyp) {
136         *keyp = node->key;
137     } else {
138         free(node->key);
139     }
140
141     if (valuep) {
142         *valuep = node->value;
143     } else {
144         free(node->value);
145     }
146
147     hmap_remove(&smap->map, &node->node);
148     free(node);
149 }
150
151 /* Removes all key-value pairs from 'smap'. */
152 void
153 smap_clear(struct smap *smap)
154 {
155     struct smap_node *node, *next;
156
157     SMAP_FOR_EACH_SAFE (node, next, smap) {
158         smap_remove_node(smap, node);
159     }
160 }
161
162 /* Returns the value associated with 'key' in 'smap', or NULL. */
163 const char *
164 smap_get(const struct smap *smap, const char *key)
165 {
166     struct smap_node *node = smap_get_node(smap, key);
167     return node ? node->value : NULL;
168 }
169
170 /* Returns the node associated with 'key' in 'smap', or NULL. */
171 struct smap_node *
172 smap_get_node(const struct smap *smap, const char *key)
173 {
174     size_t key_len = strlen(key);
175     return smap_find__(smap, key, key_len, hash_bytes(key, key_len, 0));
176 }
177
178 /* Gets the value associated with 'key' in 'smap' and converts it to a boolean.
179  * If 'key' is not in 'smap', or its value is neither "true" nor "false",
180  * returns 'def'. */
181 bool
182 smap_get_bool(const struct smap *smap, const char *key, bool def)
183 {
184     const char *value = smap_get(smap, key);
185
186     if (!value) {
187         return def;
188     }
189
190     if (def) {
191         return strcasecmp("false", value) != 0;
192     } else {
193         return !strcasecmp("true", value);
194     }
195 }
196
197 /* Gets the value associated with 'key' in 'smap' and converts it to an int
198  * using atoi().  If 'key' is not in 'smap', returns 'def'. */
199 int
200 smap_get_int(const struct smap *smap, const char *key, int def)
201 {
202     const char *value = smap_get(smap, key);
203
204     return value ? atoi(value) : def;
205 }
206
207 /* Returns true of there are no elements in 'smap'. */
208 bool
209 smap_is_empty(const struct smap *smap)
210 {
211     return hmap_is_empty(&smap->map);
212 }
213
214 /* Returns the number of elements in 'smap'. */
215 size_t
216 smap_count(const struct smap *smap)
217 {
218     return hmap_count(&smap->map);
219 }
220
221 /* Initializes 'dst' as a clone of 'src. */
222 void
223 smap_clone(struct smap *dst, const struct smap *src)
224 {
225     const struct smap_node *node;
226
227     smap_init(dst);
228     SMAP_FOR_EACH (node, src) {
229         smap_add__(dst, xstrdup(node->key), xstrdup(node->value),
230                    node->node.hash);
231     }
232 }
233
234 /* Returns an array of nodes sorted on key or NULL if 'smap' is empty.  The
235  * caller is responsible for freeing this array. */
236 const struct smap_node **
237 smap_sort(const struct smap *smap)
238 {
239     if (smap_is_empty(smap)) {
240         return NULL;
241     } else {
242         const struct smap_node **nodes;
243         struct smap_node *node;
244         size_t i, n;
245
246         n = smap_count(smap);
247         nodes = xmalloc(n * sizeof *nodes);
248         i = 0;
249         SMAP_FOR_EACH (node, smap) {
250             nodes[i++] = node;
251         }
252         ovs_assert(i == n);
253
254         qsort(nodes, n, sizeof *nodes, compare_nodes_by_key);
255
256         return nodes;
257     }
258 }
259
260 /* Adds each of the key-value pairs from 'json' (which must be a JSON object
261  * whose values are strings) to 'smap'.
262  *
263  * The caller must have initialized 'smap'.
264  *
265  * The caller retains ownership of 'json' and everything in it. */
266 void
267 smap_from_json(struct smap *smap, const struct json *json)
268 {
269     const struct shash_node *node;
270
271     SHASH_FOR_EACH (node, json_object(json)) {
272         const struct json *value = node->data;
273         smap_add(smap, node->name, json_string(value));
274     }
275 }
276
277 /* Returns a JSON object that maps from the keys in 'smap' to their values.
278  *
279  * The caller owns the returned value and must eventually json_destroy() it.
280  *
281  * The caller retains ownership of 'smap' and everything in it. */
282 struct json *
283 smap_to_json(const struct smap *smap)
284 {
285     const struct smap_node *node;
286     struct json *json;
287
288     json = json_object_create();
289     SMAP_FOR_EACH (node, smap) {
290         json_object_put_string(json, node->key, node->value);
291     }
292     return json;
293 }
294 \f
295 /* Private Helpers. */
296
297 static struct smap_node *
298 smap_add__(struct smap *smap, char *key, void *value, size_t hash)
299 {
300     struct smap_node *node = xmalloc(sizeof *node);
301     node->key = key;
302     node->value = value;
303     hmap_insert(&smap->map, &node->node, hash);
304     return node;
305 }
306
307 static struct smap_node *
308 smap_find__(const struct smap *smap, const char *key, size_t key_len,
309             size_t hash)
310 {
311     struct smap_node *node;
312
313     HMAP_FOR_EACH_WITH_HASH (node, node, hash, &smap->map) {
314         if (!strncmp(node->key, key, key_len) && !node->key[key_len]) {
315             return node;
316         }
317     }
318
319     return NULL;
320 }
321
322 static int
323 compare_nodes_by_key(const void *a_, const void *b_)
324 {
325     const struct smap_node *const *a = a_;
326     const struct smap_node *const *b = b_;
327     return strcmp((*a)->key, (*b)->key);
328 }