]>
git.proxmox.com Git - mirror_ovs.git/blob - lib/sset.c
2 * Copyright (c) 2011 Nicira, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
26 hash_name__(const char *name
, size_t length
)
28 return hash_bytes(name
, length
, 0);
32 hash_name(const char *name
)
34 return hash_name__(name
, strlen(name
));
37 static struct sset_node
*
38 sset_find__(const struct sset
*set
, const char *name
, size_t hash
)
40 struct sset_node
*node
;
42 HMAP_FOR_EACH_WITH_HASH (node
, hmap_node
, hash
, &set
->map
) {
43 if (!strcmp(node
->name
, name
)) {
50 static struct sset_node
*
51 sset_add__(struct sset
*set
, const char *name
, size_t length
, size_t hash
)
53 struct sset_node
*node
= xmalloc(length
+ sizeof *node
);
54 memcpy(node
->name
, name
, length
+ 1);
55 hmap_insert(&set
->map
, &node
->hmap_node
, hash
);
59 /* Initializes 'set' as an empty set of strings. */
61 sset_init(struct sset
*set
)
66 /* Destroys 'sets'. */
68 sset_destroy(struct sset
*set
)
72 hmap_destroy(&set
->map
);
76 /* Initializes 'set' to contain the same strings as 'orig'. */
78 sset_clone(struct sset
*set
, const struct sset
*orig
)
80 struct sset_node
*node
;
83 HMAP_FOR_EACH (node
, hmap_node
, &orig
->map
) {
84 sset_add__(set
, node
->name
, strlen(node
->name
),
85 node
->hmap_node
.hash
);
89 /* Exchanges the contents of 'a' and 'b'. */
91 sset_swap(struct sset
*a
, struct sset
*b
)
93 hmap_swap(&a
->map
, &b
->map
);
96 /* Adjusts 'set' so that it is still valid after it has been moved around in
97 * memory (e.g. due to realloc()). */
99 sset_moved(struct sset
*set
)
101 hmap_moved(&set
->map
);
104 /* Returns true if 'set' contains no strings, false if it contains at least one
107 sset_is_empty(const struct sset
*set
)
109 return hmap_is_empty(&set
->map
);
112 /* Returns the number of strings in 'set'. */
114 sset_count(const struct sset
*set
)
116 return hmap_count(&set
->map
);
119 /* Adds 'name' to 'set'. If 'name' is new, returns the new sset_node;
120 * otherwise (if a copy of 'name' already existed in 'set'), returns NULL. */
122 sset_add(struct sset
*set
, const char *name
)
124 size_t length
= strlen(name
);
125 uint32_t hash
= hash_name__(name
, length
);
127 return (sset_find__(set
, name
, hash
)
129 : sset_add__(set
, name
, length
, hash
));
132 /* Adds a copy of 'name' to 'set' and frees 'name'.
134 * If 'name' is new, returns the new sset_node; otherwise (if a copy of 'name'
135 * already existed in 'set'), returns NULL. */
137 sset_add_and_free(struct sset
*set
, char *name
)
139 struct sset_node
*node
= sset_add(set
, name
);
144 /* Adds 'name' to 'set'. Assert-fails if a copy of 'name' was already in
147 sset_add_assert(struct sset
*set
, const char *name
)
149 bool added OVS_UNUSED
= sset_add(set
, name
);
153 /* Adds a copy of each of the 'n' names in 'names' to 'set'. */
155 sset_add_array(struct sset
*set
, char **names
, size_t n
)
159 for (i
= 0; i
< n
; i
++) {
160 sset_add(set
, names
[i
]);
164 /* Removes all of the strings from 'set'. */
166 sset_clear(struct sset
*set
)
168 const char *name
, *next
;
170 SSET_FOR_EACH_SAFE (name
, next
, set
) {
171 sset_delete(set
, SSET_NODE_FROM_NAME(name
));
175 /* Deletes 'node' from 'set' and frees 'node'. */
177 sset_delete(struct sset
*set
, struct sset_node
*node
)
179 hmap_remove(&set
->map
, &node
->hmap_node
);
183 /* Searches for 'name' in 'set'. If found, deletes it and returns true. If
184 * not found, returns false without modifying 'set'. */
186 sset_find_and_delete(struct sset
*set
, const char *name
)
188 struct sset_node
*node
= sset_find(set
, name
);
190 sset_delete(set
, node
);
195 /* Searches for 'name' in 'set' and deletes it. Assert-fails if 'name' is not
198 sset_find_and_delete_assert(struct sset
*set
, const char *name
)
200 bool deleted OVS_UNUSED
= sset_find_and_delete(set
, name
);
204 /* Removes a string from 'set' and returns a copy of it. The caller must free
205 * the returned string (with free()).
207 * 'set' must not be empty.
209 * This is not a very good way to iterate through an sset: it copies each name
210 * and it takes O(n**2) time to remove all the names. Use SSET_FOR_EACH_SAFE
211 * instead, if you can. */
213 sset_pop(struct sset
*set
)
215 const char *name
= SSET_FIRST(set
);
216 char *copy
= xstrdup(name
);
217 sset_delete(set
, SSET_NODE_FROM_NAME(name
));
221 /* Searches for 'name' in 'set'. Returns its node, if found, otherwise a null
224 sset_find(const struct sset
*set
, const char *name
)
226 return sset_find__(set
, name
, hash_name(name
));
229 /* Returns true if 'set' contains a copy of 'name', false otherwise. */
231 sset_contains(const struct sset
*set
, const char *name
)
233 return sset_find(set
, name
) != NULL
;
236 /* Returns true if 'a' and 'b' contain the same strings, false otherwise. */
238 sset_equals(const struct sset
*a
, const struct sset
*b
)
240 struct sset_node
*node
;
242 if (sset_count(a
) != sset_count(b
)) {
246 HMAP_FOR_EACH (node
, hmap_node
, &a
->map
) {
247 if (!sset_find__(b
, node
->name
, node
->hmap_node
.hash
)) {
255 /* Returns the next node in 'set' in hash order, or NULL if no nodes remain in
256 * 'set'. Uses '*bucketp' and '*offsetp' to determine where to begin
257 * iteration, and stores new values to pass on the next iteration into them
260 * It's better to use plain SSET_FOR_EACH and related functions, since they are
261 * faster and better at dealing with ssets that change during iteration.
263 * Before beginning iteration, store 0 into '*bucketp' and '*offsetp'.
266 sset_at_position(const struct sset
*set
, uint32_t *bucketp
, uint32_t *offsetp
)
268 struct hmap_node
*hmap_node
;
270 hmap_node
= hmap_at_position(&set
->map
, bucketp
, offsetp
);
271 return SSET_NODE_FROM_HMAP_NODE(hmap_node
);