1 /* -*- mode: C -*- */
2 /*
3 IGraph library.
4 Copyright (C) 2006-2012 Gabor Csardi <csardi.gabor@gmail.com>
5 334 Harvard street, Cambridge, MA 02139 USA
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA
21
22 */
23
24 #include "igraph_types.h"
25 #include "igraph_memory.h"
26 #include "igraph_error.h"
27
28 #include "core/set.h"
29
30 #include <string.h> /* memmove */
31
32 #define SET(s) ((s).stor_begin)
33
34 /**
35 * \ingroup set
36 * \function igraph_set_init
37 * \brief Initializes a set.
38 *
39 * \param set pointer to the set to be initialized
40 * \param size the expected number of elements in the set
41 *
42 * \return error code:
43 * \c IGRAPH_ENOMEM if there is not enough memory.
44 *
45 * Time complexity: operating system dependent, should be around
46 * O(n), n is the expected size of the set.
47 */
igraph_set_init(igraph_set_t * set,int long size)48 int igraph_set_init(igraph_set_t *set, int long size) {
49 long int alloc_size;
50
51 if (size < 0) {
52 size = 0;
53 }
54 alloc_size = size > 0 ? size : 1;
55 set->stor_begin = IGRAPH_CALLOC(alloc_size, igraph_integer_t);
56 set->stor_end = set->stor_begin + alloc_size;
57 set->end = set->stor_begin;
58
59 return 0;
60 }
61
62 /**
63 * \ingroup set
64 * \function igraph_set_destroy
65 * \brief Destroys a set object.
66 *
67 * \param set pointer to the set to be destroyed
68 *
69 * Time complexity: operating system dependent.
70 */
igraph_set_destroy(igraph_set_t * set)71 void igraph_set_destroy(igraph_set_t* set) {
72 IGRAPH_ASSERT(set != 0);
73 if (set->stor_begin != 0) {
74 IGRAPH_FREE(set->stor_begin);
75 set->stor_begin = NULL;
76 }
77 }
78
79 /**
80 * \ingroup set
81 * \function igraph_set_inited
82 * \brief Determines whether a set is initialized or not.
83 *
84 * This function checks whether the internal storage for the members of the
85 * set has been allocated or not, and it assumes that the pointer for the
86 * internal storage area contains \c NULL if the area is not initialized yet.
87 * This only applies if you have allocated an array of sets with \c IGRAPH_CALLOC or
88 * if you used the \c IGRAPH_SET_NULL constant to initialize the set.
89 *
90 * \param set The set object.
91 *
92 * Time complexity: O(1)
93 */
igraph_set_inited(igraph_set_t * set)94 igraph_bool_t igraph_set_inited(igraph_set_t* set) {
95 return (set->stor_begin != 0);
96 }
97
98 /**
99 * \ingroup set
100 * \function igraph_set_reserve
101 * \brief Reserve memory for a set.
102 *
103 * \param set The set object.
104 * \param size the new \em allocated size of the set.
105 *
106 * Time complexity: operating system dependent, should be around
107 * O(n), n is the new allocated size of the set.
108 */
igraph_set_reserve(igraph_set_t * set,long int size)109 int igraph_set_reserve(igraph_set_t* set, long int size) {
110 long int actual_size = igraph_set_size(set);
111 igraph_integer_t *tmp;
112 IGRAPH_ASSERT(set != NULL);
113 IGRAPH_ASSERT(set->stor_begin != NULL);
114 if (size <= actual_size) {
115 return 0;
116 }
117
118 tmp = IGRAPH_REALLOC(set->stor_begin, (size_t) size, igraph_integer_t);
119 if (tmp == 0) {
120 IGRAPH_ERROR("cannot reserve space for set", IGRAPH_ENOMEM);
121 }
122 set->stor_begin = tmp;
123 set->stor_end = set->stor_begin + size;
124 set->end = set->stor_begin + actual_size;
125
126 return 0;
127 }
128
129 /**
130 * \ingroup set
131 * \function igraph_set_empty
132 * \brief Decides whether the size of the set is zero.
133 *
134 * \param set The set object.
135 * \return Non-zero number if the size of the set is not zero and
136 * zero otherwise.
137 *
138 * Time complexity: O(1).
139 */
igraph_set_empty(const igraph_set_t * set)140 igraph_bool_t igraph_set_empty(const igraph_set_t* set) {
141 IGRAPH_ASSERT(set != NULL);
142 IGRAPH_ASSERT(set->stor_begin != NULL);
143 return set->stor_begin == set->end;
144 }
145
146 /**
147 * \ingroup set
148 * \function igraph_set_clear
149 * \brief Removes all elements from a set.
150 *
151 * </para><para>
152 * This function simply sets the size of the set to zero, it does
153 * not free any allocated memory. For that you have to call
154 * \ref igraph_set_destroy().
155 * \param v The set object.
156 *
157 * Time complexity: O(1).
158 */
igraph_set_clear(igraph_set_t * set)159 void igraph_set_clear(igraph_set_t* set) {
160 IGRAPH_ASSERT(set != NULL);
161 IGRAPH_ASSERT(set->stor_begin != NULL);
162 set->end = set->stor_begin;
163 }
164
165
166 /**
167 * \ingroup set
168 * \function igraph_set_size
169 * \brief Gives the size (=length) of the set.
170 *
171 * \param v The set object
172 * \return The size of the set.
173 *
174 * Time complexity: O(1).
175 */
176
igraph_set_size(const igraph_set_t * set)177 long int igraph_set_size(const igraph_set_t* set) {
178 IGRAPH_ASSERT(set != NULL);
179 IGRAPH_ASSERT(set->stor_begin != NULL);
180 return set->end - set->stor_begin;
181 }
182
183
184 /**
185 * \ingroup set
186 * \function igraph_set_add
187 * \brief Adds an element to the set.
188 *
189 * \param set The set object.
190 * \param e The element to be added.
191 * \return Error code:
192 * \c IGRAPH_ENOMEM: not enough memory.
193 *
194 * Time complexity: O(log(n)), n is the number of elements in \p set.
195 */
igraph_set_add(igraph_set_t * set,igraph_integer_t e)196 int igraph_set_add(igraph_set_t* set, igraph_integer_t e) {
197 long int left, right, middle;
198 long int size;
199 IGRAPH_ASSERT(set != NULL);
200 IGRAPH_ASSERT(set->stor_begin != NULL);
201
202 size = igraph_set_size(set);
203
204 /* search where to insert the new element */
205 left = 0;
206 right = size - 1;
207 while (left < right - 1) {
208 middle = (left + right) / 2;
209 if (SET(*set)[middle] > e) {
210 right = middle;
211 } else if (SET(*set)[middle] < e) {
212 left = middle;
213 } else {
214 left = middle;
215 break;
216 }
217 }
218
219 if (right >= 0 && SET(*set)[left] != e && SET(*set)[right] == e) {
220 left = right;
221 }
222
223 while (left < size && set->stor_begin[left] < e) {
224 left++;
225 }
226 if (left >= size || set->stor_begin[left] != e) {
227 /* full, allocate more storage */
228 if (set->stor_end == set->end) {
229 long int new_size = size * 2;
230 if (new_size == 0) {
231 new_size = 1;
232 }
233 IGRAPH_CHECK(igraph_set_reserve(set, new_size));
234 }
235
236 /* Element should be inserted at position 'left' */
237 if (left < size)
238 memmove(set->stor_begin + left + 1, set->stor_begin + left,
239 (size_t) (size - left)*sizeof(set->stor_begin[0]));
240
241 set->stor_begin[left] = e;
242 set->end += 1;
243 }
244
245 return 0;
246 }
247
248 /**
249 * \ingroup set
250 * \function igraph_set_contains
251 * \brief Checks whether a given element is in the set or not.
252 *
253 * \param set The set object.
254 * \param e The element being sought.
255 * \return Positive integer (true) if \p e is found, zero (false) otherwise.
256 *
257 * Time complexity: O(log(n)), n is the number of elements in \p set.
258 */
igraph_set_contains(igraph_set_t * set,igraph_integer_t e)259 igraph_bool_t igraph_set_contains(igraph_set_t* set, igraph_integer_t e) {
260 long int left, right, middle;
261
262 IGRAPH_ASSERT(set != NULL);
263 IGRAPH_ASSERT(set->stor_begin != NULL);
264
265 left = 0;
266 right = igraph_set_size(set) - 1;
267
268 if (right == -1) {
269 return 0; /* the set is empty */
270 }
271
272 /* search for the new element */
273 while (left < right - 1) {
274 middle = (left + right) / 2;
275 if (SET(*set)[middle] > e) {
276 right = middle;
277 } else if (SET(*set)[middle] < e) {
278 left = middle;
279 } else {
280 return 1;
281 }
282 }
283
284 return SET(*set)[left] == e || SET(*set)[right] == e;
285 }
286
287 /**
288 * \ingroup set
289 * \function igraph_set_iterate
290 * \brief Iterates through the element to the set.
291 *
292 * Elements are returned in an arbitrary order.
293 *
294 * \param set The set object.
295 * \param state Internal state of the iteration.
296 * This should be a pointer to a \c long variable
297 * which must be zero for the first invocation.
298 * The object should not be adjusted and its value should
299 * not be used for anything during the iteration.
300 * \param element The next element or \c NULL (if the iteration
301 * has ended) is returned here.
302 *
303 * \return Nonzero if there are more elements, zero otherwise.
304 */
igraph_set_iterate(igraph_set_t * set,long int * state,igraph_integer_t * element)305 igraph_bool_t igraph_set_iterate(igraph_set_t* set, long int* state,
306 igraph_integer_t* element) {
307 IGRAPH_ASSERT(set != 0);
308 IGRAPH_ASSERT(set->stor_begin != 0);
309 IGRAPH_ASSERT(state != 0);
310 IGRAPH_ASSERT(element != 0);
311
312 if (*state < igraph_set_size(set)) {
313 *element = set->stor_begin[*state];
314 *state = *state + 1;
315 return 1;
316 } else {
317 *element = 0;
318 return 0;
319 }
320 }
321