Coverage Report

Created: 2026-02-21 06:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libyang/src/set.c
Line
Count
Source
1
/**
2
 * @file set.c
3
 * @author Radek Krejci <rkrejci@cesnet.cz>
4
 * @brief Generic set routines implementations
5
 *
6
 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
7
 *
8
 * This source code is licensed under BSD 3-Clause License (the "License").
9
 * You may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     https://opensource.org/licenses/BSD-3-Clause
13
 */
14
15
#include "common.h"
16
17
#include <stdint.h>
18
#include <stdlib.h>
19
#include <string.h>
20
21
#include "log.h"
22
#include "set.h"
23
24
API LY_ERR
25
ly_set_new(struct ly_set **set_p)
26
0
{
27
0
    LY_CHECK_ARG_RET(NULL, set_p, LY_EINVAL);
28
29
0
    *set_p = calloc(1, sizeof **set_p);
30
0
    LY_CHECK_ERR_RET(!(*set_p), LOGMEM(NULL), LY_EMEM);
31
32
0
    return LY_SUCCESS;
33
0
}
34
35
API void
36
ly_set_clean(struct ly_set *set, void (*destructor)(void *obj))
37
0
{
38
0
    uint32_t u;
39
40
0
    if (!set) {
41
0
        return;
42
0
    }
43
44
0
    if (destructor) {
45
0
        for (u = 0; u < set->count; ++u) {
46
0
            destructor(set->objs[u]);
47
0
        }
48
0
    }
49
0
    set->count = 0;
50
0
}
51
52
API void
53
ly_set_erase(struct ly_set *set, void (*destructor)(void *obj))
54
0
{
55
0
    if (!set) {
56
0
        return;
57
0
    }
58
59
0
    ly_set_clean(set, destructor);
60
61
0
    free(set->objs);
62
0
    set->size = 0;
63
0
    set->objs = NULL;
64
0
}
65
66
API void
67
ly_set_free(struct ly_set *set, void (*destructor)(void *obj))
68
0
{
69
0
    if (!set) {
70
0
        return;
71
0
    }
72
73
0
    ly_set_erase(set, destructor);
74
75
0
    free(set);
76
0
}
77
78
API ly_bool
79
ly_set_contains(const struct ly_set *set, void *object, uint32_t *index_p)
80
0
{
81
0
    LY_CHECK_ARG_RET(NULL, set, 0);
82
83
0
    for (uint32_t i = 0; i < set->count; i++) {
84
0
        if (set->objs[i] == object) {
85
            /* object found */
86
0
            if (index_p) {
87
0
                *index_p = i;
88
0
            }
89
0
            return 1;
90
0
        }
91
0
    }
92
93
    /* object not found */
94
0
    return 0;
95
0
}
96
97
API LY_ERR
98
ly_set_dup(const struct ly_set *set, void *(*duplicator)(void *obj), struct ly_set **newset_p)
99
0
{
100
0
    struct ly_set *newset;
101
0
    uint32_t u;
102
103
0
    LY_CHECK_ARG_RET(NULL, set, newset_p, LY_EINVAL);
104
105
0
    newset = malloc(sizeof *newset);
106
0
    LY_CHECK_ERR_RET(!newset, LOGMEM(NULL), LY_EMEM);
107
0
    newset->count = set->count;
108
0
    newset->size = set->count; /* optimize the size */
109
0
    newset->objs = malloc(newset->size * sizeof *(newset->objs));
110
0
    LY_CHECK_ERR_RET(!newset->objs, LOGMEM(NULL); free(newset), LY_EMEM);
111
0
    if (duplicator) {
112
0
        for (u = 0; u < set->count; ++u) {
113
0
            newset->objs[u] = duplicator(set->objs[u]);
114
0
        }
115
0
    } else {
116
0
        memcpy(newset->objs, set->objs, newset->size * sizeof *(newset->objs));
117
0
    }
118
119
0
    *newset_p = newset;
120
0
    return LY_SUCCESS;
121
0
}
122
123
API LY_ERR
124
ly_set_add(struct ly_set *set, void *object, ly_bool list, uint32_t *index_p)
125
0
{
126
0
    void **new;
127
128
0
    LY_CHECK_ARG_RET(NULL, set, LY_EINVAL);
129
130
0
    if (!list) {
131
        /* search for duplication */
132
0
        for (uint32_t i = 0; i < set->count; i++) {
133
0
            if (set->objs[i] == object) {
134
                /* already in set */
135
0
                if (index_p) {
136
0
                    *index_p = i;
137
0
                }
138
0
                return LY_SUCCESS;
139
0
            }
140
0
        }
141
0
    }
142
143
0
    if (set->size == set->count) {
144
0
#define SET_SIZE_STEP 8
145
0
        new = realloc(set->objs, (set->size + SET_SIZE_STEP) * sizeof *(set->objs));
146
0
        LY_CHECK_ERR_RET(!new, LOGMEM(NULL), LY_EMEM);
147
0
        set->size += SET_SIZE_STEP;
148
0
        set->objs = new;
149
0
#undef SET_SIZE_STEP
150
0
    }
151
152
0
    if (index_p) {
153
0
        *index_p = set->count;
154
0
    }
155
0
    set->objs[set->count++] = object;
156
157
0
    return LY_SUCCESS;
158
0
}
159
160
API LY_ERR
161
ly_set_merge(struct ly_set *trg, const struct ly_set *src, ly_bool list, void *(*duplicator)(void *obj))
162
0
{
163
0
    uint32_t u;
164
0
    void *obj;
165
166
0
    LY_CHECK_ARG_RET(NULL, trg, LY_EINVAL);
167
168
0
    if (!src) {
169
        /* nothing to do */
170
0
        return LY_SUCCESS;
171
0
    }
172
173
0
    for (u = 0; u < src->count; ++u) {
174
0
        if (duplicator) {
175
0
            obj = duplicator(src->objs[u]);
176
0
        } else {
177
0
            obj = src->objs[u];
178
0
        }
179
0
        LY_CHECK_RET(ly_set_add(trg, obj, list, NULL));
180
0
    }
181
182
0
    return LY_SUCCESS;
183
0
}
184
185
API LY_ERR
186
ly_set_rm_index(struct ly_set *set, uint32_t index, void (*destructor)(void *obj))
187
0
{
188
0
    LY_CHECK_ARG_RET(NULL, set, LY_EINVAL);
189
0
    LY_CHECK_ERR_RET(index >= set->count, LOGARG(NULL, index), LY_EINVAL);
190
191
0
    if (destructor) {
192
0
        destructor(set->objs[index]);
193
0
    }
194
0
    if (index == set->count - 1) {
195
        /* removing last item in set */
196
0
        set->objs[index] = NULL;
197
0
    } else {
198
        /* removing item somewhere in a middle, so put there the last item */
199
0
        set->objs[index] = set->objs[set->count - 1];
200
0
        set->objs[set->count - 1] = NULL;
201
0
    }
202
0
    set->count--;
203
204
0
    return LY_SUCCESS;
205
0
}
206
207
API LY_ERR
208
ly_set_rm(struct ly_set *set, void *object, void (*destructor)(void *obj))
209
0
{
210
0
    uint32_t i;
211
212
0
    LY_CHECK_ARG_RET(NULL, set, object, LY_EINVAL);
213
214
    /* get index */
215
0
    for (i = 0; i < set->count; i++) {
216
0
        if (set->objs[i] == object) {
217
0
            break;
218
0
        }
219
0
    }
220
0
    LY_CHECK_ERR_RET((i == set->count), LOGARG(NULL, object), LY_EINVAL); /* object is not in set */
221
222
0
    return ly_set_rm_index(set, i, destructor);
223
0
}