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/>. */
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
);