1 /* Copyright (c) 2012 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. */
22 static struct smap_node *smap_add__(struct smap *, char *, void *,
24 static struct smap_node *smap_find__(const struct smap *, const char *key,
25 size_t key_len, size_t hash);
26 static int compare_nodes_by_key(const void *, const void *);
28 /* Public Functions. */
31 smap_init(struct smap *smap)
33 hmap_init(&smap->map);
37 smap_destroy(struct smap *smap)
41 hmap_destroy(&smap->map);
45 /* Adds 'key' paired with 'value' to 'smap'. It is the caller's responsibility
46 * to avoid duplicate keys if desirable. */
48 smap_add(struct smap *smap, const char *key, const char *value)
50 size_t key_len = strlen(key);
51 return smap_add__(smap, xmemdup0(key, key_len), xstrdup(value),
52 hash_bytes(key, key_len, 0));
55 /* Attempts to add 'key' to 'smap' associated with 'value'. If 'key' already
56 * exists in 'smap', does nothing and returns false. Otherwise, performs the
57 * addition and returns true. */
59 smap_add_once(struct smap *smap, const char *key, const char *value)
61 if (!smap_get(smap, key)) {
62 smap_add(smap, key, value);
69 /* Adds 'key' paired with a value derived from 'format' (similar to printf).
70 * It is the caller's responsibility to avoid duplicate keys if desirable. */
72 smap_add_format(struct smap *smap, const char *key, const char *format, ...)
78 va_start(args, format);
79 value = xvasprintf(format, args);
82 key_len = strlen(key);
83 smap_add__(smap, xmemdup0(key, key_len), value,
84 hash_bytes(key, key_len, 0));
87 /* Searches for 'key' in 'smap'. If it does not already exists, adds it.
88 * Otherwise, changes its value to 'value'. */
90 smap_replace(struct smap *smap, const char *key, const char *value)
92 size_t key_len = strlen(key);
93 size_t hash = hash_bytes(key, key_len, 0);
95 struct smap_node *node;
97 node = smap_find__(smap, key, key_len, hash);
100 node->value = xstrdup(value);
102 smap_add__(smap, xmemdup0(key, key_len), xstrdup(value), hash);
106 /* If 'key' is in 'smap', removes it. Otherwise does nothing. */
108 smap_remove(struct smap *smap, const char *key)
110 struct smap_node *node = smap_get_node(smap, key);
113 smap_remove_node(smap, node);
117 /* Removes 'node' from 'smap'. */
119 smap_remove_node(struct smap *smap, struct smap_node *node)
121 hmap_remove(&smap->map, &node->node);
127 /* Removes all key-value pairs from 'smap'. */
129 smap_clear(struct smap *smap)
131 struct smap_node *node, *next;
133 SMAP_FOR_EACH_SAFE (node, next, smap) {
134 smap_remove_node(smap, node);
138 /* Returns the value associated with 'key' in 'smap', or NULL. */
140 smap_get(const struct smap *smap, const char *key)
142 struct smap_node *node = smap_get_node(smap, key);
143 return node ? node->value : NULL;
146 /* Returns the node associated with 'key' in 'smap', or NULL. */
148 smap_get_node(const struct smap *smap, const char *key)
150 size_t key_len = strlen(key);
151 return smap_find__(smap, key, key_len, hash_bytes(key, key_len, 0));
154 /* Gets the value associated with 'key' in 'smap' and converts it to a boolean.
155 * If 'key' is not in 'smap', or its value is neither "true" nor "false",
158 smap_get_bool(const struct smap *smap, const char *key, bool def)
160 const char *value = smap_get(smap, key);
167 return strcasecmp("false", value) != 0;
169 return !strcasecmp("true", value);
173 /* Gets the value associated with 'key' in 'smap' and converts it to an int
174 * using atoi(). If 'key' is not in 'smap', returns 'def'. */
176 smap_get_int(const struct smap *smap, const char *key, int def)
178 const char *value = smap_get(smap, key);
180 return value ? atoi(value) : def;
183 /* Returns true of there are no elements in 'smap'. */
185 smap_is_empty(const struct smap *smap)
187 return hmap_is_empty(&smap->map);
190 /* Returns the number of elements in 'smap'. */
192 smap_count(const struct smap *smap)
194 return hmap_count(&smap->map);
197 /* Initializes 'dst' as a clone of 'src. */
199 smap_clone(struct smap *dst, const struct smap *src)
201 const struct smap_node *node;
204 SMAP_FOR_EACH (node, src) {
205 smap_add__(dst, xstrdup(node->key), xstrdup(node->value),
210 /* Returns an array of nodes sorted on key or NULL if 'smap' is empty. The
211 * caller is responsible for freeing this array. */
212 const struct smap_node **
213 smap_sort(const struct smap *smap)
215 if (smap_is_empty(smap)) {
218 const struct smap_node **nodes;
219 struct smap_node *node;
222 n = smap_count(smap);
223 nodes = xmalloc(n * sizeof *nodes);
225 SMAP_FOR_EACH (node, smap) {
230 qsort(nodes, n, sizeof *nodes, compare_nodes_by_key);
236 /* Private Helpers. */
238 static struct smap_node *
239 smap_add__(struct smap *smap, char *key, void *value, size_t hash)
241 struct smap_node *node = xmalloc(sizeof *node);
244 hmap_insert(&smap->map, &node->node, hash);
248 static struct smap_node *
249 smap_find__(const struct smap *smap, const char *key, size_t key_len,
252 struct smap_node *node;
254 HMAP_FOR_EACH_WITH_HASH (node, node, hash, &smap->map) {
255 if (!strncmp(node->key, key, key_len) && !node->key[key_len]) {
264 compare_nodes_by_key(const void *a_, const void *b_)
266 const struct smap_node *const *a = a_;
267 const struct smap_node *const *b = b_;
268 return strcmp((*a)->key, (*b)->key);