1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2009, 2010, 2012 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/stringi-map.h"
24 #include "libpspp/hash-functions.h"
25 #include "libpspp/i18n.h"
26 #include "libpspp/string-set.h"
27 #include "libpspp/stringi-set.h"
29 #include "gl/xalloc.h"
31 static struct stringi_map_node *stringi_map_find_node__ (
32 const struct stringi_map *, const char *key, unsigned int hash);
33 static bool stringi_map_delete__ (struct stringi_map *, const char *key,
35 static struct stringi_map_node *stringi_map_insert__ (struct stringi_map *,
36 char *key, char *value,
39 /* Sets NODE's value to a copy of NEW_VALUE and returns the node's previous
40 value. The caller is responsible for freeing the returned string (with
43 stringi_map_node_swap_value (struct stringi_map_node *node,
44 const char *new_value)
46 return stringi_map_node_swap_value_nocopy (node, xstrdup (new_value));
49 /* Sets NODE's value to NEW_VALUE, which must be a malloc()'d string,
50 transferring ownership of NEW_VALUE to the node. Returns the node's
51 previous value, which the caller is responsible for freeing (with
54 stringi_map_node_swap_value_nocopy (struct stringi_map_node *node,
57 char *old_value = node->value;
58 node->value = new_value;
62 /* Replaces NODE's value by a copy of VALUE. */
64 stringi_map_node_set_value (struct stringi_map_node *node, const char *value)
66 stringi_map_node_set_value_nocopy (node, xstrdup (value));
69 /* Replaces NODE's value by VALUE, which must be a malloc()'d string,
70 transferring ownership of VALUE to the node.. */
72 stringi_map_node_set_value_nocopy (struct stringi_map_node *node, char *value)
78 /* Frees NODE and and its key and value. Ordinarily nodes are owned by
79 stringi_maps, but this function should only be used by a caller that owns
80 NODE, such as one that has called stringi_map_delete_nofree() for the
83 stringi_map_node_destroy (struct stringi_map_node *node)
90 /* Initializes MAP as an initially empty case-insensitive string map. */
92 stringi_map_init (struct stringi_map *map)
94 hmap_init (&map->hmap);
97 /* Initializes MAP as a new string map that initially contains the same pairs
100 stringi_map_clone (struct stringi_map *map, const struct stringi_map *old)
102 const struct stringi_map_node *node;
103 const char *key, *value;
105 stringi_map_init (map);
106 hmap_reserve (&map->hmap, stringi_map_count (old));
107 STRINGI_MAP_FOR_EACH_KEY_VALUE (key, value, node, old)
108 stringi_map_insert__ (map, xstrdup (key), xstrdup (value),
109 node->hmap_node.hash);
112 /* Exchanges the contents of string maps A and B. */
114 stringi_map_swap (struct stringi_map *a, struct stringi_map *b)
116 hmap_swap (&a->hmap, &b->hmap);
119 /* Frees MAP and its nodes and key-value pairs. */
121 stringi_map_destroy (struct stringi_map *map)
125 stringi_map_clear (map);
126 hmap_destroy (&map->hmap);
130 /* Returns true if MAP contains KEY (or an equivalent with different case) as a
131 key, otherwise false. */
133 stringi_map_contains (const struct stringi_map *map, const char *key)
135 return stringi_map_find_node (map, key) != NULL;
138 /* If MAP contains KEY (or an equivalent with different case) as a key, returns
139 the corresponding value. Otherwise, returns a null pointer. */
141 stringi_map_find (const struct stringi_map *map, const char *key)
143 const struct stringi_map_node *node = stringi_map_find_node (map, key);
144 return node != NULL ? node->value : NULL;
147 /* If MAP contains KEY (or an equivalent with different case) as a key, returns
148 the corresponding node. Otherwise, returns a null pointer. */
149 struct stringi_map_node *
150 stringi_map_find_node (const struct stringi_map *map, const char *key)
152 return stringi_map_find_node__ (map, key, utf8_hash_case_string (key, 0));
155 /* If MAP contains KEY (or an equivalent with different case) as a key, deletes
156 that key's node and returns its value, which the caller is responsible for
157 freeing (using free()). Otherwise, returns a null pointer. */
159 stringi_map_find_and_delete (struct stringi_map *map, const char *key)
161 struct stringi_map_node *node = stringi_map_find_node (map, key);
167 stringi_map_delete_node (map, node);
172 /* If MAP does not contain KEY (or an equivalent with different case) as a key,
173 inserts a new node containing copies of KEY and VALUE and returns the new
174 node. Otherwise, returns the existing node that contains KEY. */
175 struct stringi_map_node *
176 stringi_map_insert (struct stringi_map *map, const char *key,
179 unsigned int hash = utf8_hash_case_string (key, 0);
180 struct stringi_map_node *node = stringi_map_find_node__ (map, key, hash);
182 node = stringi_map_insert__ (map, xstrdup (key), xstrdup (value), hash);
186 /* If MAP does not contain KEY (or an equivalent with different case) as a key,
187 inserts a new node containing KEY and VALUE and returns the new node.
188 Otherwise, returns the existing node that contains KEY. Either way,
189 ownership of KEY and VALUE is transferred to MAP. */
190 struct stringi_map_node *
191 stringi_map_insert_nocopy (struct stringi_map *map, char *key, char *value)
193 unsigned int hash = utf8_hash_case_string (key, 0);
194 struct stringi_map_node *node = stringi_map_find_node__ (map, key, hash);
196 node = stringi_map_insert__ (map, key, value, hash);
205 /* If MAP does not contain KEY (or an equivalent with different case) as a key,
206 inserts a new node containing copies of KEY and VALUE. Otherwise, replaces
207 the existing node's value by a copy of VALUE. Returns the node. */
208 struct stringi_map_node *
209 stringi_map_replace (struct stringi_map *map, const char *key,
212 unsigned int hash = utf8_hash_case_string (key, 0);
213 struct stringi_map_node *node = stringi_map_find_node__ (map, key, hash);
215 node = stringi_map_insert__ (map, xstrdup (key), xstrdup (value), hash);
217 stringi_map_node_set_value (node, value);
221 /* If MAP does not contain KEY (or an equivalent with different case) as a key,
222 inserts a new node containing KEY and VALUE. Otherwise, replaces the
223 existing node's value by VALUE. Either way, ownership of KEY and VALUE is
224 transferred to MAP. Returns the node. */
225 struct stringi_map_node *
226 stringi_map_replace_nocopy (struct stringi_map *map, char *key, char *value)
228 unsigned int hash = utf8_hash_case_string (key, 0);
229 struct stringi_map_node *node = stringi_map_find_node__ (map, key, hash);
231 node = stringi_map_insert__ (map, key, value, hash);
235 stringi_map_node_set_value_nocopy (node, value);
240 /* Searches MAP for a node with KEY (or an equivalent with different case) as
241 its key. If found, deletes the node and its key and value and returns true.
242 Otherwise, returns false without modifying MAP. */
244 stringi_map_delete (struct stringi_map *map, const char *key)
246 return stringi_map_delete__ (map, key, utf8_hash_case_string (key, 0));
249 /* Deletes NODE from MAP and destroys the node and its key and value. */
251 stringi_map_delete_node (struct stringi_map *map,
252 struct stringi_map_node *node)
254 stringi_map_delete_nofree (map, node);
255 stringi_map_node_destroy (node);
258 /* Deletes NODE from MAP. Transfers ownership of NODE to the caller, which
259 becomes responsible for destroying it. */
261 stringi_map_delete_nofree (struct stringi_map *map,
262 struct stringi_map_node *node)
264 hmap_delete (&map->hmap, &node->hmap_node);
267 /* Removes all nodes from MAP and frees them and their keys and values. */
269 stringi_map_clear (struct stringi_map *map)
271 struct stringi_map_node *node, *next;
273 STRINGI_MAP_FOR_EACH_NODE_SAFE (node, next, map)
274 stringi_map_delete_node (map, node);
277 /* Inserts a copy of each of the nodes in SRC into DST. When SRC and DST both
278 have a particular key (or keys that differ only in case), the value in DST's
279 node is left unchanged. */
281 stringi_map_insert_map (struct stringi_map *dst, const struct stringi_map *src)
283 const struct stringi_map_node *node;
285 STRINGI_MAP_FOR_EACH_NODE (node, src)
287 if (!stringi_map_find_node__ (dst, node->key, node->hmap_node.hash))
288 stringi_map_insert__ (dst, xstrdup (node->key), xstrdup (node->value),
289 node->hmap_node.hash);
293 /* Inserts a copy of each of the nodes in SRC into DST. When SRC and DST both
294 have a particular key (or keys that differ only in case), the value in DST's
295 node is replaced by a copy of the value in SRC's node. */
297 stringi_map_replace_map (struct stringi_map *dst,
298 const struct stringi_map *src)
300 const struct stringi_map_node *snode;
302 STRINGI_MAP_FOR_EACH_NODE (snode, src)
304 struct stringi_map_node *dnode;
305 dnode = stringi_map_find_node__ (dst, snode->key, snode->hmap_node.hash);
307 stringi_map_node_set_value (dnode, snode->value);
309 stringi_map_insert__ (dst,
310 xstrdup (snode->key), xstrdup (snode->value),
311 snode->hmap_node.hash);
315 /* Inserts each of the keys in MAP into KEYS. KEYS must already have been
316 initialized (using stringi_set_init()). */
318 stringi_map_get_keys (const struct stringi_map *map, struct stringi_set *keys)
320 const struct stringi_map_node *node;
323 STRINGI_MAP_FOR_EACH_KEY (key, node, map)
324 stringi_set_insert (keys, key);
327 /* Inserts each of the values in MAP into VALUES. VALUES must already have
328 been initialized (using string_set_init()). */
330 stringi_map_get_values (const struct stringi_map *map,
331 struct string_set *values)
333 const struct stringi_map_node *node;
336 STRINGI_MAP_FOR_EACH_VALUE (value, node, map)
337 string_set_insert (values, value);
340 static struct stringi_map_node *
341 stringi_map_find_node__ (const struct stringi_map *map, const char *key,
344 struct stringi_map_node *node;
346 HMAP_FOR_EACH_WITH_HASH (node, struct stringi_map_node, hmap_node,
348 if (!utf8_strcasecmp (key, node->key))
355 stringi_map_delete__ (struct stringi_map *map, const char *key,
358 struct stringi_map_node *node = stringi_map_find_node__ (map, key, hash);
361 stringi_map_delete_node (map, node);
368 static struct stringi_map_node *
369 stringi_map_insert__ (struct stringi_map *map, char *key, char *value,
372 struct stringi_map_node *node = xmalloc (sizeof *node);
375 hmap_insert (&map->hmap, &node->hmap_node, hash);