blob: 97691458d5dde1615387958c5c78837b96f75ceb [file] [log] [blame]
Radek Krejci5aeea3a2018-09-05 13:29:36 +02001/**
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 "libyang.h"
16#include "common.h"
17
18API struct ly_set *
19ly_set_new(void)
20{
21 struct ly_set *new;
22
23 new = calloc(1, sizeof(struct ly_set));
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020024 LY_CHECK_ERR_RET(!new, LOGMEM(NULL), NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020025 return new;
26}
27
28API void
Radek Krejcia40f21b2018-09-18 10:42:08 +020029ly_set_clean(struct ly_set *set, void (*destructor)(void *obj))
30{
31 unsigned int u;
32
Radek Krejci0bfec162019-05-02 09:54:25 +020033 if (!set) {
34 return;
35 }
Radek Krejcia40f21b2018-09-18 10:42:08 +020036
37 if (destructor) {
38 for (u = 0; u < set->count; ++u) {
39 destructor(set->objs[u]);
40 }
41 }
42 set->count = 0;
43}
44
45API void
46ly_set_erase(struct ly_set *set, void (*destructor)(void *obj))
Radek Krejci5aeea3a2018-09-05 13:29:36 +020047{
Radek Krejci0bfec162019-05-02 09:54:25 +020048 if (!set) {
49 return;
50 }
Radek Krejci5aeea3a2018-09-05 13:29:36 +020051
Radek Krejcia40f21b2018-09-18 10:42:08 +020052 ly_set_clean(set, destructor);
53
Radek Krejci5aeea3a2018-09-05 13:29:36 +020054 free(set->objs);
Radek Krejcia40f21b2018-09-18 10:42:08 +020055 set->size = 0;
56 set->objs = NULL;
57}
58
59API void
60ly_set_free(struct ly_set *set, void (*destructor)(void *obj))
61{
Radek Krejci0bfec162019-05-02 09:54:25 +020062 if (!set) {
63 return;
64 }
Radek Krejcia40f21b2018-09-18 10:42:08 +020065
66 ly_set_erase(set, destructor);
67
Radek Krejci5aeea3a2018-09-05 13:29:36 +020068 free(set);
69}
70
71API int
72ly_set_contains(const struct ly_set *set, void *object)
73{
74 unsigned int i;
75
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020076 LY_CHECK_ARG_RET(NULL, set, -1);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020077
Michal Vaskob34480a2018-09-17 10:34:45 +020078 for (i = 0; i < set->count; i++) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +020079 if (set->objs[i] == object) {
80 /* object found */
81 return i;
82 }
83 }
84
85 /* object not found */
86 return -1;
87}
88
89API struct ly_set *
Radek Krejci2f2bd902018-09-18 17:04:24 +020090ly_set_dup(const struct ly_set *set, void *(*duplicator)(void *obj))
Radek Krejci5aeea3a2018-09-05 13:29:36 +020091{
92 struct ly_set *new;
Radek Krejci2f2bd902018-09-18 17:04:24 +020093 unsigned int u;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020094
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020095 LY_CHECK_ARG_RET(NULL, set, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020096
97 new = malloc(sizeof *new);
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020098 LY_CHECK_ERR_RET(!new, LOGMEM(NULL), NULL);
Michal Vaskob34480a2018-09-17 10:34:45 +020099 new->count = set->count;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200100 new->size = set->size;
101 new->objs = malloc(new->size * sizeof *(new->objs));
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200102 LY_CHECK_ERR_RET(!new->objs, LOGMEM(NULL); free(new), NULL);
Radek Krejci2f2bd902018-09-18 17:04:24 +0200103 if (duplicator) {
104 for (u = 0; u < set->count; ++u) {
105 new->objs[u] = duplicator(set->objs[u]);
106 }
107 } else {
108 memcpy(new->objs, set->objs, new->size * sizeof *(new->objs));
109 }
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200110
111 return new;
112}
113
114API int
115ly_set_add(struct ly_set *set, void *object, int options)
116{
117 unsigned int i;
118 void **new;
119
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200120 LY_CHECK_ARG_RET(NULL, set, object, -1);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200121
122 if (!(options & LY_SET_OPT_USEASLIST)) {
123 /* search for duplication */
Michal Vaskob34480a2018-09-17 10:34:45 +0200124 for (i = 0; i < set->count; i++) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200125 if (set->objs[i] == object) {
126 /* already in set */
127 return i;
128 }
129 }
130 }
131
Michal Vaskob34480a2018-09-17 10:34:45 +0200132 if (set->size == set->count) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200133 new = realloc(set->objs, (set->size + 8) * sizeof *(set->objs));
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200134 LY_CHECK_ERR_RET(!new, LOGMEM(NULL), -1);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200135 set->size += 8;
136 set->objs = new;
137 }
138
Michal Vaskob34480a2018-09-17 10:34:45 +0200139 set->objs[set->count++] = object;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200140
Michal Vaskob34480a2018-09-17 10:34:45 +0200141 return set->count - 1;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200142}
143
144API int
Radek Krejci2f2bd902018-09-18 17:04:24 +0200145ly_set_merge(struct ly_set *trg, struct ly_set *src, int options, void *(*duplicator)(void *obj))
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200146{
Radek Krejci2f2bd902018-09-18 17:04:24 +0200147 unsigned int u, c, ret = 0;
148 int i;
149 void *obj;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200150
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200151 LY_CHECK_ARG_RET(NULL, trg, -1);
152 LY_CHECK_ARG_RET(NULL, src, 0);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200153
Radek Krejci2f2bd902018-09-18 17:04:24 +0200154 for (u = 0; u < src->count; ++u) {
155 if (duplicator) {
156 obj = duplicator(src->objs[u]);
157 } else {
158 obj = src->objs[u];
159 }
160 c = trg->count;
161 i = ly_set_add(trg, obj, options);
162 if (i > 0 && (unsigned int)i == c) {
163 ++ret;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200164 }
165 }
166
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200167 return ret;
168}
169
170API LY_ERR
Radek Krejci820d2262018-09-20 12:15:31 +0200171ly_set_rm_index(struct ly_set *set, unsigned int index, void (*destructor)(void *obj))
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200172{
Radek Krejci13246392018-09-07 14:57:41 +0200173 LY_CHECK_ARG_RET(NULL, set, LY_EINVAL);
Radek Krejci820d2262018-09-20 12:15:31 +0200174 LY_CHECK_ERR_RET(index >= set->count, LOGARG(NULL, index), LY_EINVAL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200175
Radek Krejci820d2262018-09-20 12:15:31 +0200176 if (destructor) {
177 destructor(set->objs[index]);
178 }
Michal Vaskob34480a2018-09-17 10:34:45 +0200179 if (index == set->count - 1) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200180 /* removing last item in set */
181 set->objs[index] = NULL;
182 } else {
183 /* removing item somewhere in a middle, so put there the last item */
Michal Vaskob34480a2018-09-17 10:34:45 +0200184 set->objs[index] = set->objs[set->count - 1];
185 set->objs[set->count - 1] = NULL;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200186 }
Michal Vaskob34480a2018-09-17 10:34:45 +0200187 set->count--;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200188
189 return LY_SUCCESS;
190}
191
192API LY_ERR
Radek Krejci820d2262018-09-20 12:15:31 +0200193ly_set_rm(struct ly_set *set, void *object, void (*destructor)(void *obj))
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200194{
195 unsigned int i;
196
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200197 LY_CHECK_ARG_RET(NULL, set, object, LY_EINVAL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200198
199 /* get index */
Michal Vaskob34480a2018-09-17 10:34:45 +0200200 for (i = 0; i < set->count; i++) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200201 if (set->objs[i] == object) {
202 break;
203 }
204 }
Radek Krejci56616162018-09-18 14:11:00 +0200205 LY_CHECK_ERR_RET((i == set->count), LOGARG(NULL, object), LY_EINVAL); /* object is not in set */
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200206
Radek Krejci820d2262018-09-20 12:15:31 +0200207 return ly_set_rm_index(set, i, destructor);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200208}
209