blob: c9be886e6c40c5ea7324065025c8141575423c9b [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
33 LY_CHECK_ARG_RET(NULL, set,);
34
35 if (destructor) {
36 for (u = 0; u < set->count; ++u) {
37 destructor(set->objs[u]);
38 }
39 }
40 set->count = 0;
41}
42
43API void
44ly_set_erase(struct ly_set *set, void (*destructor)(void *obj))
Radek Krejci5aeea3a2018-09-05 13:29:36 +020045{
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020046 LY_CHECK_ARG_RET(NULL, set,);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020047
Radek Krejcia40f21b2018-09-18 10:42:08 +020048 ly_set_clean(set, destructor);
49
Radek Krejci5aeea3a2018-09-05 13:29:36 +020050 free(set->objs);
Radek Krejcia40f21b2018-09-18 10:42:08 +020051 set->size = 0;
52 set->objs = NULL;
53}
54
55API void
56ly_set_free(struct ly_set *set, void (*destructor)(void *obj))
57{
58 LY_CHECK_ARG_RET(NULL, set,);
59
60 ly_set_erase(set, destructor);
61
Radek Krejci5aeea3a2018-09-05 13:29:36 +020062 free(set);
63}
64
65API int
66ly_set_contains(const struct ly_set *set, void *object)
67{
68 unsigned int i;
69
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020070 LY_CHECK_ARG_RET(NULL, set, -1);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020071
Michal Vaskob34480a2018-09-17 10:34:45 +020072 for (i = 0; i < set->count; i++) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +020073 if (set->objs[i] == object) {
74 /* object found */
75 return i;
76 }
77 }
78
79 /* object not found */
80 return -1;
81}
82
83API struct ly_set *
84ly_set_dup(const struct ly_set *set)
85{
86 struct ly_set *new;
87
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020088 LY_CHECK_ARG_RET(NULL, set, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020089
90 new = malloc(sizeof *new);
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020091 LY_CHECK_ERR_RET(!new, LOGMEM(NULL), NULL);
Michal Vaskob34480a2018-09-17 10:34:45 +020092 new->count = set->count;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020093 new->size = set->size;
94 new->objs = malloc(new->size * sizeof *(new->objs));
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020095 LY_CHECK_ERR_RET(!new->objs, LOGMEM(NULL); free(new), NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020096 memcpy(new->objs, set->objs, new->size * sizeof *(new->objs));
97
98 return new;
99}
100
101API int
102ly_set_add(struct ly_set *set, void *object, int options)
103{
104 unsigned int i;
105 void **new;
106
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200107 LY_CHECK_ARG_RET(NULL, set, object, -1);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200108
109 if (!(options & LY_SET_OPT_USEASLIST)) {
110 /* search for duplication */
Michal Vaskob34480a2018-09-17 10:34:45 +0200111 for (i = 0; i < set->count; i++) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200112 if (set->objs[i] == object) {
113 /* already in set */
114 return i;
115 }
116 }
117 }
118
Michal Vaskob34480a2018-09-17 10:34:45 +0200119 if (set->size == set->count) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200120 new = realloc(set->objs, (set->size + 8) * sizeof *(set->objs));
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200121 LY_CHECK_ERR_RET(!new, LOGMEM(NULL), -1);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200122 set->size += 8;
123 set->objs = new;
124 }
125
Michal Vaskob34480a2018-09-17 10:34:45 +0200126 set->objs[set->count++] = object;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200127
Michal Vaskob34480a2018-09-17 10:34:45 +0200128 return set->count - 1;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200129}
130
131API int
132ly_set_merge(struct ly_set *trg, struct ly_set *src, int options)
133{
134 unsigned int i, ret;
135 void **new;
136
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200137 LY_CHECK_ARG_RET(NULL, trg, -1);
138 LY_CHECK_ARG_RET(NULL, src, 0);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200139
140 if (!(options & LY_SET_OPT_USEASLIST)) {
141 /* remove duplicates */
142 i = 0;
Michal Vaskob34480a2018-09-17 10:34:45 +0200143 while (i < src->count) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200144 if (ly_set_contains(trg, src->objs[i]) > -1) {
145 ly_set_rm_index(src, i);
146 } else {
147 ++i;
148 }
149 }
150 }
151
152 /* allocate more memory if needed */
Michal Vaskob34480a2018-09-17 10:34:45 +0200153 if (trg->size < trg->count + src->count) {
154 new = realloc(trg->objs, (trg->count + src->count) * sizeof *(trg->objs));
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200155 LY_CHECK_ERR_RET(!new, LOGMEM(NULL), -1);
Michal Vaskob34480a2018-09-17 10:34:45 +0200156 trg->size = trg->count + src->count;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200157 trg->objs = new;
158 }
159
160 /* copy contents from src into trg */
Michal Vaskob34480a2018-09-17 10:34:45 +0200161 memcpy(trg->objs + trg->count, src->objs, src->count * sizeof *(src->objs));
162 ret = src->count;
163 trg->count += ret;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200164
165 /* cleanup */
Radek Krejcia40f21b2018-09-18 10:42:08 +0200166 ly_set_free(src, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200167 return ret;
168}
169
170API LY_ERR
171ly_set_rm_index(struct ly_set *set, unsigned int index)
172{
Radek Krejci13246392018-09-07 14:57:41 +0200173 LY_CHECK_ARG_RET(NULL, set, LY_EINVAL);
Michal Vaskob34480a2018-09-17 10:34:45 +0200174 LY_CHECK_ERR_RET(((index + 1) > set->count), LOGARG(NULL, set), LY_EINVAL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200175
Michal Vaskob34480a2018-09-17 10:34:45 +0200176 if (index == set->count - 1) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200177 /* removing last item in set */
178 set->objs[index] = NULL;
179 } else {
180 /* removing item somewhere in a middle, so put there the last item */
Michal Vaskob34480a2018-09-17 10:34:45 +0200181 set->objs[index] = set->objs[set->count - 1];
182 set->objs[set->count - 1] = NULL;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200183 }
Michal Vaskob34480a2018-09-17 10:34:45 +0200184 set->count--;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200185
186 return LY_SUCCESS;
187}
188
189API LY_ERR
190ly_set_rm(struct ly_set *set, void *object)
191{
192 unsigned int i;
193
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200194 LY_CHECK_ARG_RET(NULL, set, object, LY_EINVAL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200195
196 /* get index */
Michal Vaskob34480a2018-09-17 10:34:45 +0200197 for (i = 0; i < set->count; i++) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200198 if (set->objs[i] == object) {
199 break;
200 }
201 }
Michal Vaskob34480a2018-09-17 10:34:45 +0200202 LY_CHECK_ERR_RET((i == set->count), LOGARG(NULL, set), LY_EINVAL); /* object is not in set */
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200203
204 return ly_set_rm_index(set, i);
205}
206