1 /* Copyright (c) 2012, 2014, 2015 Nicira, Inc.
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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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. */
24 static struct smap_node *smap_add__(struct smap *, char *, void *,
26 static struct smap_node *smap_find__(const struct smap *, const char *key,
27 size_t key_len, size_t hash);
28 static int compare_nodes_by_key(const void *, const void *);
30 /* Public Functions. */
33 smap_init(struct smap *smap)
35 hmap_init(&smap->map);
39 smap_destroy(struct smap *smap)
43 hmap_destroy(&smap->map);
47 /* Adds 'key' paired with 'value' to 'smap'. It is the caller's responsibility
48 * to avoid duplicate keys if desirable. */
50 smap_add(struct smap *smap, const char *key, const char *value)
52 size_t key_len = strlen(key);
53 return smap_add__(smap, xmemdup0(key, key_len), xstrdup(value),
54 hash_bytes(key, key_len, 0));
57 /* Adds 'key' paired with 'value' to 'smap'. Takes ownership of 'key' and
58 * 'value' (which will eventually be freed with free()). It is the caller's
59 * responsibility to avoid duplicate keys if desirable. */
61 smap_add_nocopy(struct smap *smap, char *key, char *value)
63 return smap_add__(smap, key, value, hash_bytes(key, strlen(key), 0));
66 /* Attempts to add 'key' to 'smap' associated with 'value'. If 'key' already
67 * exists in 'smap', does nothing and returns false. Otherwise, performs the
68 * addition and returns true. */
70 smap_add_once(struct smap *smap, const char *key, const char *value)
72 if (!smap_get(smap, key)) {
73 smap_add(smap, key, value);
80 /* Adds 'key' paired with a value derived from 'format' (similar to printf).
81 * It is the caller's responsibility to avoid duplicate keys if desirable. */
83 smap_add_format(struct smap *smap, const char *key, const char *format, ...)
89 va_start(args, format);
90 value = xvasprintf(format, args);
93 key_len = strlen(key);
94 smap_add__(smap, xmemdup0(key, key_len), value,
95 hash_bytes(key, key_len, 0));
98 /* Searches for 'key' in 'smap'. If it does not already exists, adds it.
99 * Otherwise, changes its value to 'value'. */
101 smap_replace(struct smap *smap, const char *key, const char *value)
103 size_t key_len = strlen(key);
104 size_t hash = hash_bytes(key, key_len, 0);
106 struct smap_node *node;
108 node = smap_find__(smap, key, key_len, hash);
111 node->value = xstrdup(value);
113 smap_add__(smap, xmemdup0(key, key_len), xstrdup(value), hash);
117 /* If 'key' is in 'smap', removes it. Otherwise does nothing. */
119 smap_remove(struct smap *smap, const char *key)
121 struct smap_node *node = smap_get_node(smap, key);
124 smap_remove_node(smap, node);
128 /* Removes 'node' from 'smap'. */
130 smap_remove_node(struct smap *smap, struct smap_node *node)
132 hmap_remove(&smap->map, &node->node);
138 /* Deletes 'node' from 'smap'.
140 * If 'keyp' is nonnull, stores the node's key in '*keyp' and transfers
141 * ownership to the caller. Otherwise, frees the node's key. Similarly for
142 * 'valuep' and the node's value. */
144 smap_steal(struct smap *smap, struct smap_node *node,
145 char **keyp, char **valuep)
154 *valuep = node->value;
159 hmap_remove(&smap->map, &node->node);
163 /* Removes all key-value pairs from 'smap'. */
165 smap_clear(struct smap *smap)
167 struct smap_node *node, *next;
169 SMAP_FOR_EACH_SAFE (node, next, smap) {
170 smap_remove_node(smap, node);
174 /* Returns the value associated with 'key' in 'smap', or NULL. */
176 smap_get(const struct smap *smap, const char *key)
178 struct smap_node *node = smap_get_node(smap, key);
179 return node ? node->value : NULL;
182 /* Returns the node associated with 'key' in 'smap', or NULL. */
184 smap_get_node(const struct smap *smap, const char *key)
186 size_t key_len = strlen(key);
187 return smap_find__(smap, key, key_len, hash_bytes(key, key_len, 0));
190 /* Gets the value associated with 'key' in 'smap' and converts it to a boolean.
191 * If 'key' is not in 'smap', or its value is neither "true" nor "false",
194 smap_get_bool(const struct smap *smap, const char *key, bool def)
196 const char *value = smap_get(smap, key);
203 return strcasecmp("false", value) != 0;
205 return !strcasecmp("true", value);
209 /* Gets the value associated with 'key' in 'smap' and converts it to an int
210 * using atoi(). If 'key' is not in 'smap', returns 'def'. */
212 smap_get_int(const struct smap *smap, const char *key, int def)
214 const char *value = smap_get(smap, key);
216 return value ? atoi(value) : def;
219 /* Gets the value associated with 'key' in 'smap' and converts it to a UUID
220 * using uuid_from_string(). Returns true if successful, false if 'key' is not
221 * in 'smap' or if 'key' does not have the correct syntax for a UUID. */
223 smap_get_uuid(const struct smap *smap, const char *key, struct uuid *uuid)
225 const char *value = smap_get(smap, key);
226 return value && uuid_from_string(uuid, value);
229 /* Returns true of there are no elements in 'smap'. */
231 smap_is_empty(const struct smap *smap)
233 return hmap_is_empty(&smap->map);
236 /* Returns the number of elements in 'smap'. */
238 smap_count(const struct smap *smap)
240 return hmap_count(&smap->map);
243 /* Initializes 'dst' as a clone of 'src. */
245 smap_clone(struct smap *dst, const struct smap *src)
247 const struct smap_node *node;
250 SMAP_FOR_EACH (node, src) {
251 smap_add__(dst, xstrdup(node->key), xstrdup(node->value),
256 /* Returns an array of nodes sorted on key or NULL if 'smap' is empty. The
257 * caller is responsible for freeing this array. */
258 const struct smap_node **
259 smap_sort(const struct smap *smap)
261 if (smap_is_empty(smap)) {
264 const struct smap_node **nodes;
265 struct smap_node *node;
268 n = smap_count(smap);
269 nodes = xmalloc(n * sizeof *nodes);
271 SMAP_FOR_EACH (node, smap) {
276 qsort(nodes, n, sizeof *nodes, compare_nodes_by_key);
282 /* Adds each of the key-value pairs from 'json' (which must be a JSON object
283 * whose values are strings) to 'smap'.
285 * The caller must have initialized 'smap'.
287 * The caller retains ownership of 'json' and everything in it. */
289 smap_from_json(struct smap *smap, const struct json *json)
291 const struct shash_node *node;
293 SHASH_FOR_EACH (node, json_object(json)) {
294 const struct json *value = node->data;
295 smap_add(smap, node->name, json_string(value));
299 /* Returns a JSON object that maps from the keys in 'smap' to their values.
301 * The caller owns the returned value and must eventually json_destroy() it.
303 * The caller retains ownership of 'smap' and everything in it. */
305 smap_to_json(const struct smap *smap)
307 const struct smap_node *node;
310 json = json_object_create();
311 SMAP_FOR_EACH (node, smap) {
312 json_object_put_string(json, node->key, node->value);
317 /* Returns true if the two maps are equal, meaning that they have the same set
318 * of key-value pairs.
321 smap_equal(const struct smap *smap1, const struct smap *smap2)
323 if (smap_count(smap1) != smap_count(smap2)) {
327 const struct smap_node *node;
328 SMAP_FOR_EACH (node, smap1) {
329 const char *value2 = smap_get(smap2, node->key);
330 if (!value2 || strcmp(node->value, value2)) {
337 /* Private Helpers. */
339 static struct smap_node *
340 smap_add__(struct smap *smap, char *key, void *value, size_t hash)
342 struct smap_node *node = xmalloc(sizeof *node);
345 hmap_insert(&smap->map, &node->node, hash);
349 static struct smap_node *
350 smap_find__(const struct smap *smap, const char *key, size_t key_len,
353 struct smap_node *node;
355 HMAP_FOR_EACH_WITH_HASH (node, node, hash, &smap->map) {
356 if (!strncmp(node->key, key, key_len) && !node->key[key_len]) {
365 compare_nodes_by_key(const void *a_, const void *b_)
367 const struct smap_node *const *a = a_;
368 const struct smap_node *const *b = b_;
369 return strcmp((*a)->key, (*b)->key);