1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2009, 2011 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 #include "libpspp/string-map.h"
24 #include "libpspp/hash-functions.h"
25 #include "libpspp/string-set.h"
27 #include "gl/xalloc.h"
29 static struct string_map_node *string_map_find_node__ (
30 const struct string_map *, const char *key, unsigned int hash);
31 static bool string_map_delete__ (struct string_map *, const char *key,
33 static struct string_map_node *string_map_insert__ (struct string_map *,
34 char *key, char *value,
37 /* Sets NODE's value to a copy of NEW_VALUE and returns the node's previous
38 value. The caller is responsible for freeing the returned string (with
41 string_map_node_swap_value (struct string_map_node *node,
42 const char *new_value)
44 return string_map_node_swap_value_nocopy (node, xstrdup (new_value));
47 /* Sets NODE's value to NEW_VALUE, which must be a malloc()'d string,
48 transferring ownership of NEW_VALUE to the node. Returns the node's
49 previous value, which the caller is responsible for freeing (with
52 string_map_node_swap_value_nocopy (struct string_map_node *node,
55 char *old_value = node->value;
56 node->value = new_value;
60 /* Replaces NODE's value by a copy of VALUE. */
62 string_map_node_set_value (struct string_map_node *node, const char *value)
64 string_map_node_set_value_nocopy (node, xstrdup (value));
67 /* Replaces NODE's value by VALUE, which must be a malloc()'d string,
68 transferring ownership of VALUE to the node.. */
70 string_map_node_set_value_nocopy (struct string_map_node *node, char *value)
76 /* Frees NODE and and its key and value. Ordinarily nodes are owned by
77 string_maps, but this function should only be used by a caller that owns
78 NODE, such as one that has called string_map_delete_nofree() for the
81 string_map_node_destroy (struct string_map_node *node)
88 /* Initializes MAP as an initially empty string map. */
90 string_map_init (struct string_map *map)
92 hmap_init (&map->hmap);
95 /* Initializes MAP as a new string map that initially contains the same pairs
98 string_map_clone (struct string_map *map, const struct string_map *old)
100 const struct string_map_node *node;
101 const char *key, *value;
103 string_map_init (map);
104 hmap_reserve (&map->hmap, string_map_count (old));
105 STRING_MAP_FOR_EACH_KEY_VALUE (key, value, node, old)
106 string_map_insert__ (map, xstrdup (key), xstrdup (value),
107 node->hmap_node.hash);
110 /* Exchanges the contents of string maps A and B. */
112 string_map_swap (struct string_map *a, struct string_map *b)
114 hmap_swap (&a->hmap, &b->hmap);
117 /* Frees MAP and its nodes and key-value pairs. */
119 string_map_destroy (struct string_map *map)
123 string_map_clear (map);
124 hmap_destroy (&map->hmap);
128 /* Returns true if MAP contains KEY as a key, otherwise false. */
130 string_map_contains (const struct string_map *map, const char *key)
132 return string_map_find_node (map, key) != NULL;
135 /* If MAP contains KEY as a key, returns the corresponding value. Otherwise,
136 returns a null pointer. */
138 string_map_find (const struct string_map *map, const char *key)
140 const struct string_map_node *node = string_map_find_node (map, key);
141 return node != NULL ? node->value : NULL;
144 /* If MAP contains KEY as a key, returns the corresponding node. Otherwise,
145 returns a null pointer. */
146 struct string_map_node *
147 string_map_find_node (const struct string_map *map, const char *key)
149 return string_map_find_node__ (map, key, hash_string (key, 0));
152 /* If MAP contains KEY as a key, deletes that key's node and returns its value,
153 which the caller is responsible for freeing (using free()). Otherwise,
154 returns a null pointer. */
156 string_map_find_and_delete (struct string_map *map, const char *key)
158 struct string_map_node *node = string_map_find_node (map, key);
164 string_map_delete_node (map, node);
169 /* If MAP does not contain KEY as a key, inserts a new node containing copies
170 of KEY and VALUE and returns the new node. Otherwise, returns the existing
171 node that contains KEY. */
172 struct string_map_node *
173 string_map_insert (struct string_map *map, const char *key, const char *value)
175 unsigned int hash = hash_string (key, 0);
176 struct string_map_node *node = string_map_find_node__ (map, key, hash);
178 node = string_map_insert__ (map, xstrdup (key), xstrdup (value), hash);
182 /* If MAP does not contain KEY as a key, inserts a new node containing KEY and
183 VALUE and returns the new node. Otherwise, returns the existing node that
184 contains KEY. Either way, ownership of KEY and VALUE is transferred to
186 struct string_map_node *
187 string_map_insert_nocopy (struct string_map *map, char *key, char *value)
189 unsigned int hash = hash_string (key, 0);
190 struct string_map_node *node = string_map_find_node__ (map, key, hash);
192 node = string_map_insert__ (map, key, value, hash);
201 /* If MAP does not contain KEY as a key, inserts a new node containing copies
202 of KEY and VALUE. Otherwise, replaces the existing node's value by a copy
203 of VALUE. Returns the node. */
204 struct string_map_node *
205 string_map_replace (struct string_map *map, const char *key, const char *value)
207 unsigned int hash = hash_string (key, 0);
208 struct string_map_node *node = string_map_find_node__ (map, key, hash);
210 node = string_map_insert__ (map, xstrdup (key), xstrdup (value), hash);
212 string_map_node_set_value (node, value);
216 /* If MAP does not contain KEY as a key, inserts a new node containing KEY and
217 VALUE. Otherwise, replaces the existing node's value by VALUE. Either way,
218 ownership of KEY and VALUE is transferred to MAP. Returns the node. */
219 struct string_map_node *
220 string_map_replace_nocopy (struct string_map *map, char *key, char *value)
222 unsigned int hash = hash_string (key, 0);
223 struct string_map_node *node = string_map_find_node__ (map, key, hash);
225 node = string_map_insert__ (map, key, value, hash);
229 string_map_node_set_value_nocopy (node, value);
234 /* Searches MAP for a node with KEY as its key. If found, deletes the node
235 and its key and value and returns true. Otherwise, returns false without
238 string_map_delete (struct string_map *map, const char *key)
240 return string_map_delete__ (map, key, hash_string (key, 0));
243 /* Deletes NODE from MAP and destroys the node and its key and value. */
245 string_map_delete_node (struct string_map *map, struct string_map_node *node)
247 string_map_delete_nofree (map, node);
248 string_map_node_destroy (node);
251 /* Deletes NODE from MAP. Transfers ownership of NODE to the caller, which
252 becomes responsible for destroying it. */
254 string_map_delete_nofree (struct string_map *map, struct string_map_node *node)
256 hmap_delete (&map->hmap, &node->hmap_node);
259 /* Removes all nodes from MAP and frees them and their keys and values. */
261 string_map_clear (struct string_map *map)
263 struct string_map_node *node, *next;
265 STRING_MAP_FOR_EACH_NODE_SAFE (node, next, map)
266 string_map_delete_node (map, node);
269 /* Inserts a copy of each of the nodes in SRC into DST. When SRC and DST both
270 have a particular key, the value in DST's node is left unchanged. */
272 string_map_insert_map (struct string_map *dst, const struct string_map *src)
274 const struct string_map_node *node;
276 STRING_MAP_FOR_EACH_NODE (node, src)
278 if (!string_map_find_node__ (dst, node->key, node->hmap_node.hash))
279 string_map_insert__ (dst, xstrdup (node->key), xstrdup (node->value),
280 node->hmap_node.hash);
284 /* Inserts a copy of each of the nodes in SRC into DST. When SRC and DST both
285 have a particular key, the value in DST's node is replaced by a copy of the
286 value in SRC's node. */
288 string_map_replace_map (struct string_map *dst, const struct string_map *src)
290 const struct string_map_node *snode;
292 STRING_MAP_FOR_EACH_NODE (snode, src)
294 struct string_map_node *dnode;
295 dnode = string_map_find_node__ (dst, snode->key, snode->hmap_node.hash);
297 string_map_node_set_value (dnode, snode->value);
299 string_map_insert__ (dst, xstrdup (snode->key), xstrdup (snode->value),
300 snode->hmap_node.hash);
304 /* Inserts each of the keys in MAP into KEYS. KEYS must already have been
305 initialized (using string_set_init()). */
307 string_map_get_keys (const struct string_map *map, struct string_set *keys)
309 const struct string_map_node *node;
312 STRING_MAP_FOR_EACH_KEY (key, node, map)
313 string_set_insert (keys, key);
316 /* Inserts each of the values in MAP into VALUES. VALUES must already have
317 been initialized (using string_set_init()). */
319 string_map_get_values (const struct string_map *map, struct string_set *values)
321 const struct string_map_node *node;
324 STRING_MAP_FOR_EACH_VALUE (value, node, map)
325 string_set_insert (values, value);
328 static struct string_map_node *
329 string_map_find_node__ (const struct string_map *map, const char *key,
332 struct string_map_node *node;
334 HMAP_FOR_EACH_WITH_HASH (node, struct string_map_node, hmap_node,
336 if (!strcmp (key, node->key))
343 string_map_delete__ (struct string_map *map, const char *key,
346 struct string_map_node *node = string_map_find_node__ (map, key, hash);
349 string_map_delete_node (map, node);
356 static struct string_map_node *
357 string_map_insert__ (struct string_map *map, char *key, char *value,
360 struct string_map_node *node = xmalloc (sizeof *node);
363 hmap_insert (&map->hmap, &node->hmap_node, hash);