1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2009 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/>. */
17 /* If you add routines in this file, please add a corresponding test to
22 #include <libpspp/string-set.h>
27 #include <libpspp/hash-functions.h>
29 #include "gl/xalloc.h"
31 static struct string_set_node *string_set_find_node__ (
32 const struct string_set *, const char *, unsigned int hash);
33 static void string_set_insert__ (struct string_set *, char *,
35 static bool string_set_delete__ (struct string_set *, const char *,
38 /* Initializes SET as a new string set that is initially empty. */
40 string_set_init (struct string_set *set)
42 hmap_init (&set->hmap);
45 /* Initializes SET as a new string set that initially contains the same strings
48 string_set_clone (struct string_set *set, const struct string_set *old)
50 const struct string_set_node *node;
53 string_set_init (set);
54 hmap_reserve (&set->hmap, string_set_count (old));
55 STRING_SET_FOR_EACH (s, node, old)
56 string_set_insert__ (set, xstrdup (s), node->hmap_node.hash);
59 /* Exchanges the contents of string sets A and B. */
61 string_set_swap (struct string_set *a, struct string_set *b)
63 hmap_swap (&a->hmap, &b->hmap);
66 /* Frees SET and its nodes and strings. */
68 string_set_destroy (struct string_set *set)
72 string_set_clear (set);
73 hmap_destroy (&set->hmap);
77 /* Returns true if SET contains S, false otherwise. */
79 string_set_contains (const struct string_set *set, const char *s)
81 return string_set_find_node (set, s) != NULL;
84 /* Returns the node in SET that contains S, or a null pointer if SET does not
86 struct string_set_node *
87 string_set_find_node (const struct string_set *set, const char *s)
89 return string_set_find_node__ (set, s, hash_string (s, 0));
92 /* Inserts a copy of S into SET. Returns true if successful, false if SET
93 is unchanged because it already contained S. */
95 string_set_insert (struct string_set *set, const char *s)
97 unsigned int hash = hash_string (s, 0);
98 if (!string_set_find_node__ (set, s, hash))
100 string_set_insert__ (set, xstrdup (s), hash);
107 /* Inserts S, which must be a malloc'd string, into SET, transferring ownership
108 of S to SET. Returns true if successful, false if SET is unchanged because
109 it already contained a copy of S. (In the latter case, S is freed.) */
111 string_set_insert_nocopy (struct string_set *set, char *s)
113 unsigned int hash = hash_string (s, 0);
114 if (!string_set_find_node__ (set, s, hash))
116 string_set_insert__ (set, s, hash);
126 /* Deletes S from SET. Returns true if successful, false if SET is unchanged
127 because it did not contain a copy of S. */
129 string_set_delete (struct string_set *set, const char *s)
131 return string_set_delete__ (set, s, hash_string (s, 0));
134 /* Deletes NODE from SET, and frees NODE and its string. */
136 string_set_delete_node (struct string_set *set, struct string_set_node *node)
138 free (string_set_delete_nofree (set, node));
141 /* Deletes NODE from SET and frees NODE. Returns the string that NODE
142 contained, transferring ownership to the caller. */
144 string_set_delete_nofree (struct string_set *set, struct string_set_node *node)
146 char *string = node->string;
147 hmap_delete (&set->hmap, &node->hmap_node);
152 /* Removes all nodes from SET. */
154 string_set_clear (struct string_set *set)
156 struct string_set_node *node, *next;
158 HMAP_FOR_EACH_SAFE (node, next, struct string_set_node, hmap_node,
160 string_set_delete_node (set, node);
163 /* Calculates A = union(A, B).
165 If B may be modified, string_set_union_and_intersection() is
166 faster than this function. */
168 string_set_union (struct string_set *a, const struct string_set *b)
170 struct string_set_node *node;
171 HMAP_FOR_EACH (node, struct string_set_node, hmap_node, &b->hmap)
172 if (!string_set_find_node__ (a, node->string, node->hmap_node.hash))
173 string_set_insert__ (a, xstrdup (node->string), node->hmap_node.hash);
176 /* Calculates A = union(A, B) and B = intersect(A, B).
178 If only the intersection is needed, string_set_intersect() is
181 string_set_union_and_intersection (struct string_set *a, struct string_set *b)
183 struct string_set_node *node, *next;
185 HMAP_FOR_EACH_SAFE (node, next, struct string_set_node, hmap_node,
187 if (!string_set_find_node__ (a, node->string, node->hmap_node.hash))
189 hmap_delete (&b->hmap, &node->hmap_node);
190 hmap_insert (&a->hmap, &node->hmap_node, node->hmap_node.hash);
194 /* Calculates A = intersect(A, B). */
196 string_set_intersect (struct string_set *a, const struct string_set *b)
198 struct string_set_node *node, *next;
200 HMAP_FOR_EACH_SAFE (node, next, struct string_set_node, hmap_node,
202 if (!string_set_find_node__ (b, node->string, node->hmap_node.hash))
203 string_set_delete_node (a, node);
206 /* Removes from A all of the strings in B. */
208 string_set_subtract (struct string_set *a, const struct string_set *b)
210 struct string_set_node *node, *next;
212 if (string_set_count (a) < string_set_count (b))
214 HMAP_FOR_EACH_SAFE (node, next, struct string_set_node, hmap_node,
216 if (string_set_find_node__ (b, node->string, node->hmap_node.hash))
217 string_set_delete_node (a, node);
221 HMAP_FOR_EACH (node, struct string_set_node, hmap_node, &b->hmap)
222 string_set_delete__ (a, node->string, node->hmap_node.hash);
226 /* Internal functions. */
228 static struct string_set_node *
229 string_set_find_node__ (const struct string_set *set, const char *s,
232 struct string_set_node *node;
234 HMAP_FOR_EACH_WITH_HASH (node, struct string_set_node, hmap_node,
236 if (!strcmp (s, node->string))
243 string_set_insert__ (struct string_set *set, char *s, unsigned int hash)
245 struct string_set_node *node = xmalloc (sizeof *node);
247 hmap_insert (&set->hmap, &node->hmap_node, hash);
251 string_set_delete__ (struct string_set *set, const char *s, unsigned int hash)
253 struct string_set_node *node = string_set_find_node__ (set, s, hash);
256 string_set_delete_node (set, node);