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