blob: 6c8271007d2968c2acbae8a4c75bcfa25ca7a428 [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>
Michal Vasko52927e22020-03-16 17:26:14 +010019#include <stdint.h>
Radek Krejcie7b95092019-05-15 11:03:07 +020020
21#include "log.h"
22#include "set.h"
23
Radek Krejci5aeea3a2018-09-05 13:29:36 +020024API struct ly_set *
25ly_set_new(void)
26{
27 struct ly_set *new;
28
29 new = calloc(1, sizeof(struct ly_set));
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020030 LY_CHECK_ERR_RET(!new, LOGMEM(NULL), NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020031 return new;
32}
33
34API void
Radek Krejcia40f21b2018-09-18 10:42:08 +020035ly_set_clean(struct ly_set *set, void (*destructor)(void *obj))
36{
Michal Vasko52927e22020-03-16 17:26:14 +010037 uint32_t u;
Radek Krejcia40f21b2018-09-18 10:42:08 +020038
Radek Krejci0bfec162019-05-02 09:54:25 +020039 if (!set) {
40 return;
41 }
Radek Krejcia40f21b2018-09-18 10:42:08 +020042
43 if (destructor) {
44 for (u = 0; u < set->count; ++u) {
45 destructor(set->objs[u]);
46 }
47 }
48 set->count = 0;
49}
50
51API void
52ly_set_erase(struct ly_set *set, void (*destructor)(void *obj))
Radek Krejci5aeea3a2018-09-05 13:29:36 +020053{
Radek Krejci0bfec162019-05-02 09:54:25 +020054 if (!set) {
55 return;
56 }
Radek Krejci5aeea3a2018-09-05 13:29:36 +020057
Radek Krejcia40f21b2018-09-18 10:42:08 +020058 ly_set_clean(set, destructor);
59
Radek Krejci5aeea3a2018-09-05 13:29:36 +020060 free(set->objs);
Radek Krejcia40f21b2018-09-18 10:42:08 +020061 set->size = 0;
62 set->objs = NULL;
63}
64
65API void
66ly_set_free(struct ly_set *set, void (*destructor)(void *obj))
67{
Radek Krejci0bfec162019-05-02 09:54:25 +020068 if (!set) {
69 return;
70 }
Radek Krejcia40f21b2018-09-18 10:42:08 +020071
72 ly_set_erase(set, destructor);
73
Radek Krejci5aeea3a2018-09-05 13:29:36 +020074 free(set);
75}
76
77API int
78ly_set_contains(const struct ly_set *set, void *object)
79{
Michal Vasko52927e22020-03-16 17:26:14 +010080 uint32_t i;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020081
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020082 LY_CHECK_ARG_RET(NULL, set, -1);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020083
Michal Vaskob34480a2018-09-17 10:34:45 +020084 for (i = 0; i < set->count; i++) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +020085 if (set->objs[i] == object) {
86 /* object found */
87 return i;
88 }
89 }
90
91 /* object not found */
92 return -1;
93}
94
95API struct ly_set *
Radek Krejci2f2bd902018-09-18 17:04:24 +020096ly_set_dup(const struct ly_set *set, void *(*duplicator)(void *obj))
Radek Krejci5aeea3a2018-09-05 13:29:36 +020097{
98 struct ly_set *new;
Michal Vasko52927e22020-03-16 17:26:14 +010099 uint32_t u;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200100
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200101 LY_CHECK_ARG_RET(NULL, set, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200102
103 new = malloc(sizeof *new);
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200104 LY_CHECK_ERR_RET(!new, LOGMEM(NULL), NULL);
Michal Vaskob34480a2018-09-17 10:34:45 +0200105 new->count = set->count;
Radek Krejci94955072019-05-22 15:28:29 +0200106 new->size = set->count; /* optimize the size */
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200107 new->objs = malloc(new->size * sizeof *(new->objs));
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200108 LY_CHECK_ERR_RET(!new->objs, LOGMEM(NULL); free(new), NULL);
Radek Krejci2f2bd902018-09-18 17:04:24 +0200109 if (duplicator) {
110 for (u = 0; u < set->count; ++u) {
111 new->objs[u] = duplicator(set->objs[u]);
112 }
113 } else {
114 memcpy(new->objs, set->objs, new->size * sizeof *(new->objs));
115 }
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200116
117 return new;
118}
119
120API int
Radek Krejci1deb5be2020-08-26 16:43:36 +0200121ly_set_add(struct ly_set *set, void *object, uint32_t options)
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200122{
Michal Vasko52927e22020-03-16 17:26:14 +0100123 uint32_t i;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200124 void **new;
125
Michal Vasko52927e22020-03-16 17:26:14 +0100126 LY_CHECK_ARG_RET(NULL, set, -1);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200127
128 if (!(options & LY_SET_OPT_USEASLIST)) {
129 /* search for duplication */
Michal Vaskob34480a2018-09-17 10:34:45 +0200130 for (i = 0; i < set->count; i++) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200131 if (set->objs[i] == object) {
132 /* already in set */
133 return i;
134 }
135 }
136 }
137
Michal Vaskob34480a2018-09-17 10:34:45 +0200138 if (set->size == set->count) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200139 new = realloc(set->objs, (set->size + 8) * sizeof *(set->objs));
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200140 LY_CHECK_ERR_RET(!new, LOGMEM(NULL), -1);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200141 set->size += 8;
142 set->objs = new;
143 }
144
Michal Vaskob34480a2018-09-17 10:34:45 +0200145 set->objs[set->count++] = object;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200146
Michal Vaskob34480a2018-09-17 10:34:45 +0200147 return set->count - 1;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200148}
149
150API int
Radek Krejci1deb5be2020-08-26 16:43:36 +0200151ly_set_merge(struct ly_set *trg, struct ly_set *src, uint32_t options, void *(*duplicator)(void *obj))
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200152{
Michal Vasko52927e22020-03-16 17:26:14 +0100153 uint32_t u, c, ret = 0;
Radek Krejci2f2bd902018-09-18 17:04:24 +0200154 int i;
155 void *obj;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200156
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200157 LY_CHECK_ARG_RET(NULL, trg, -1);
158 LY_CHECK_ARG_RET(NULL, src, 0);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200159
Radek Krejci2f2bd902018-09-18 17:04:24 +0200160 for (u = 0; u < src->count; ++u) {
161 if (duplicator) {
162 obj = duplicator(src->objs[u]);
163 } else {
164 obj = src->objs[u];
165 }
166 c = trg->count;
167 i = ly_set_add(trg, obj, options);
Michal Vasko52927e22020-03-16 17:26:14 +0100168 if (i > 0 && (unsigned)i == c) {
Radek Krejci2f2bd902018-09-18 17:04:24 +0200169 ++ret;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200170 }
171 }
172
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200173 return ret;
174}
175
176API LY_ERR
Michal Vasko52927e22020-03-16 17:26:14 +0100177ly_set_rm_index(struct ly_set *set, uint32_t index, void (*destructor)(void *obj))
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200178{
Radek Krejci13246392018-09-07 14:57:41 +0200179 LY_CHECK_ARG_RET(NULL, set, LY_EINVAL);
Radek Krejci820d2262018-09-20 12:15:31 +0200180 LY_CHECK_ERR_RET(index >= set->count, LOGARG(NULL, index), LY_EINVAL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200181
Radek Krejci820d2262018-09-20 12:15:31 +0200182 if (destructor) {
183 destructor(set->objs[index]);
184 }
Michal Vaskob34480a2018-09-17 10:34:45 +0200185 if (index == set->count - 1) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200186 /* removing last item in set */
187 set->objs[index] = NULL;
188 } else {
189 /* removing item somewhere in a middle, so put there the last item */
Michal Vaskob34480a2018-09-17 10:34:45 +0200190 set->objs[index] = set->objs[set->count - 1];
191 set->objs[set->count - 1] = NULL;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200192 }
Michal Vaskob34480a2018-09-17 10:34:45 +0200193 set->count--;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200194
195 return LY_SUCCESS;
196}
197
198API LY_ERR
Radek Krejci820d2262018-09-20 12:15:31 +0200199ly_set_rm(struct ly_set *set, void *object, void (*destructor)(void *obj))
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200200{
Michal Vasko52927e22020-03-16 17:26:14 +0100201 uint32_t i;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200202
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200203 LY_CHECK_ARG_RET(NULL, set, object, LY_EINVAL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200204
205 /* get index */
Michal Vaskob34480a2018-09-17 10:34:45 +0200206 for (i = 0; i < set->count; i++) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200207 if (set->objs[i] == object) {
208 break;
209 }
210 }
Radek Krejci56616162018-09-18 14:11:00 +0200211 LY_CHECK_ERR_RET((i == set->count), LOGARG(NULL, object), LY_EINVAL); /* object is not in set */
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200212
Radek Krejci820d2262018-09-20 12:15:31 +0200213 return ly_set_rm_index(set, i, destructor);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200214}