blob: 3b7f0788071d422327de3243fb65e0d056313eae [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
Radek Krejci5aeea3a2018-09-05 13:29:36 +020015#include "common.h"
16
Radek Krejcie7b95092019-05-15 11:03:07 +020017#include <stdlib.h>
18#include <string.h>
19
20#include "log.h"
21#include "set.h"
22
Radek Krejci5aeea3a2018-09-05 13:29:36 +020023API struct ly_set *
24ly_set_new(void)
25{
26 struct ly_set *new;
27
28 new = calloc(1, sizeof(struct ly_set));
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020029 LY_CHECK_ERR_RET(!new, LOGMEM(NULL), NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020030 return new;
31}
32
33API void
Radek Krejcia40f21b2018-09-18 10:42:08 +020034ly_set_clean(struct ly_set *set, void (*destructor)(void *obj))
35{
36 unsigned int u;
37
Radek Krejci0bfec162019-05-02 09:54:25 +020038 if (!set) {
39 return;
40 }
Radek Krejcia40f21b2018-09-18 10:42:08 +020041
42 if (destructor) {
43 for (u = 0; u < set->count; ++u) {
44 destructor(set->objs[u]);
45 }
46 }
47 set->count = 0;
48}
49
50API void
51ly_set_erase(struct ly_set *set, void (*destructor)(void *obj))
Radek Krejci5aeea3a2018-09-05 13:29:36 +020052{
Radek Krejci0bfec162019-05-02 09:54:25 +020053 if (!set) {
54 return;
55 }
Radek Krejci5aeea3a2018-09-05 13:29:36 +020056
Radek Krejcia40f21b2018-09-18 10:42:08 +020057 ly_set_clean(set, destructor);
58
Radek Krejci5aeea3a2018-09-05 13:29:36 +020059 free(set->objs);
Radek Krejcia40f21b2018-09-18 10:42:08 +020060 set->size = 0;
61 set->objs = NULL;
62}
63
64API void
65ly_set_free(struct ly_set *set, void (*destructor)(void *obj))
66{
Radek Krejci0bfec162019-05-02 09:54:25 +020067 if (!set) {
68 return;
69 }
Radek Krejcia40f21b2018-09-18 10:42:08 +020070
71 ly_set_erase(set, destructor);
72
Radek Krejci5aeea3a2018-09-05 13:29:36 +020073 free(set);
74}
75
76API int
77ly_set_contains(const struct ly_set *set, void *object)
78{
79 unsigned int i;
80
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020081 LY_CHECK_ARG_RET(NULL, set, -1);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020082
Michal Vaskob34480a2018-09-17 10:34:45 +020083 for (i = 0; i < set->count; i++) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +020084 if (set->objs[i] == object) {
85 /* object found */
86 return i;
87 }
88 }
89
90 /* object not found */
91 return -1;
92}
93
94API struct ly_set *
Radek Krejci2f2bd902018-09-18 17:04:24 +020095ly_set_dup(const struct ly_set *set, void *(*duplicator)(void *obj))
Radek Krejci5aeea3a2018-09-05 13:29:36 +020096{
97 struct ly_set *new;
Radek Krejci2f2bd902018-09-18 17:04:24 +020098 unsigned int u;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020099
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200100 LY_CHECK_ARG_RET(NULL, set, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200101
102 new = malloc(sizeof *new);
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200103 LY_CHECK_ERR_RET(!new, LOGMEM(NULL), NULL);
Michal Vaskob34480a2018-09-17 10:34:45 +0200104 new->count = set->count;
Radek Krejci94955072019-05-22 15:28:29 +0200105 new->size = set->count; /* optimize the size */
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200106 new->objs = malloc(new->size * sizeof *(new->objs));
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200107 LY_CHECK_ERR_RET(!new->objs, LOGMEM(NULL); free(new), NULL);
Radek Krejci2f2bd902018-09-18 17:04:24 +0200108 if (duplicator) {
109 for (u = 0; u < set->count; ++u) {
110 new->objs[u] = duplicator(set->objs[u]);
111 }
112 } else {
113 memcpy(new->objs, set->objs, new->size * sizeof *(new->objs));
114 }
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200115
116 return new;
117}
118
119API int
120ly_set_add(struct ly_set *set, void *object, int options)
121{
122 unsigned int i;
123 void **new;
124
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200125 LY_CHECK_ARG_RET(NULL, set, object, -1);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200126
127 if (!(options & LY_SET_OPT_USEASLIST)) {
128 /* search for duplication */
Michal Vaskob34480a2018-09-17 10:34:45 +0200129 for (i = 0; i < set->count; i++) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200130 if (set->objs[i] == object) {
131 /* already in set */
132 return i;
133 }
134 }
135 }
136
Michal Vaskob34480a2018-09-17 10:34:45 +0200137 if (set->size == set->count) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200138 new = realloc(set->objs, (set->size + 8) * sizeof *(set->objs));
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200139 LY_CHECK_ERR_RET(!new, LOGMEM(NULL), -1);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200140 set->size += 8;
141 set->objs = new;
142 }
143
Michal Vaskob34480a2018-09-17 10:34:45 +0200144 set->objs[set->count++] = object;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200145
Michal Vaskob34480a2018-09-17 10:34:45 +0200146 return set->count - 1;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200147}
148
149API int
Radek Krejci2f2bd902018-09-18 17:04:24 +0200150ly_set_merge(struct ly_set *trg, struct ly_set *src, int options, void *(*duplicator)(void *obj))
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200151{
Radek Krejci2f2bd902018-09-18 17:04:24 +0200152 unsigned int u, c, ret = 0;
153 int i;
154 void *obj;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200155
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200156 LY_CHECK_ARG_RET(NULL, trg, -1);
157 LY_CHECK_ARG_RET(NULL, src, 0);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200158
Radek Krejci2f2bd902018-09-18 17:04:24 +0200159 for (u = 0; u < src->count; ++u) {
160 if (duplicator) {
161 obj = duplicator(src->objs[u]);
162 } else {
163 obj = src->objs[u];
164 }
165 c = trg->count;
166 i = ly_set_add(trg, obj, options);
167 if (i > 0 && (unsigned int)i == c) {
168 ++ret;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200169 }
170 }
171
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200172 return ret;
173}
174
175API LY_ERR
Radek Krejci820d2262018-09-20 12:15:31 +0200176ly_set_rm_index(struct ly_set *set, unsigned int index, void (*destructor)(void *obj))
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200177{
Radek Krejci13246392018-09-07 14:57:41 +0200178 LY_CHECK_ARG_RET(NULL, set, LY_EINVAL);
Radek Krejci820d2262018-09-20 12:15:31 +0200179 LY_CHECK_ERR_RET(index >= set->count, LOGARG(NULL, index), LY_EINVAL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200180
Radek Krejci820d2262018-09-20 12:15:31 +0200181 if (destructor) {
182 destructor(set->objs[index]);
183 }
Michal Vaskob34480a2018-09-17 10:34:45 +0200184 if (index == set->count - 1) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200185 /* removing last item in set */
186 set->objs[index] = NULL;
187 } else {
188 /* removing item somewhere in a middle, so put there the last item */
Michal Vaskob34480a2018-09-17 10:34:45 +0200189 set->objs[index] = set->objs[set->count - 1];
190 set->objs[set->count - 1] = NULL;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200191 }
Michal Vaskob34480a2018-09-17 10:34:45 +0200192 set->count--;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200193
194 return LY_SUCCESS;
195}
196
197API LY_ERR
Radek Krejci820d2262018-09-20 12:15:31 +0200198ly_set_rm(struct ly_set *set, void *object, void (*destructor)(void *obj))
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200199{
200 unsigned int i;
201
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200202 LY_CHECK_ARG_RET(NULL, set, object, LY_EINVAL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200203
204 /* get index */
Michal Vaskob34480a2018-09-17 10:34:45 +0200205 for (i = 0; i < set->count; i++) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200206 if (set->objs[i] == object) {
207 break;
208 }
209 }
Radek Krejci56616162018-09-18 14:11:00 +0200210 LY_CHECK_ERR_RET((i == set->count), LOGARG(NULL, object), LY_EINVAL); /* object is not in set */
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200211
Radek Krejci820d2262018-09-20 12:15:31 +0200212 return ly_set_rm_index(set, i, destructor);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200213}
214