Coverage Report

Created: 2025-07-01 07:02

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