blob: 6cfc0afbeaf0b9b6d4490f585c07b6092da3318f [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
29ly_set_free(struct ly_set *set)
30{
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020031 LY_CHECK_ARG_RET(NULL, set,);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020032
33 free(set->objs);
34 free(set);
35}
36
37API int
38ly_set_contains(const struct ly_set *set, void *object)
39{
40 unsigned int i;
41
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020042 LY_CHECK_ARG_RET(NULL, set, -1);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020043
Michal Vaskob34480a2018-09-17 10:34:45 +020044 for (i = 0; i < set->count; i++) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +020045 if (set->objs[i] == object) {
46 /* object found */
47 return i;
48 }
49 }
50
51 /* object not found */
52 return -1;
53}
54
55API struct ly_set *
56ly_set_dup(const struct ly_set *set)
57{
58 struct ly_set *new;
59
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020060 LY_CHECK_ARG_RET(NULL, set, NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020061
62 new = malloc(sizeof *new);
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020063 LY_CHECK_ERR_RET(!new, LOGMEM(NULL), NULL);
Michal Vaskob34480a2018-09-17 10:34:45 +020064 new->count = set->count;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020065 new->size = set->size;
66 new->objs = malloc(new->size * sizeof *(new->objs));
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020067 LY_CHECK_ERR_RET(!new->objs, LOGMEM(NULL); free(new), NULL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020068 memcpy(new->objs, set->objs, new->size * sizeof *(new->objs));
69
70 return new;
71}
72
73API int
74ly_set_add(struct ly_set *set, void *object, int options)
75{
76 unsigned int i;
77 void **new;
78
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020079 LY_CHECK_ARG_RET(NULL, set, object, -1);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020080
81 if (!(options & LY_SET_OPT_USEASLIST)) {
82 /* search for duplication */
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 /* already in set */
86 return i;
87 }
88 }
89 }
90
Michal Vaskob34480a2018-09-17 10:34:45 +020091 if (set->size == set->count) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +020092 new = realloc(set->objs, (set->size + 8) * sizeof *(set->objs));
Michal Vaskob3d0d6b2018-09-07 10:17:33 +020093 LY_CHECK_ERR_RET(!new, LOGMEM(NULL), -1);
Radek Krejci5aeea3a2018-09-05 13:29:36 +020094 set->size += 8;
95 set->objs = new;
96 }
97
Michal Vaskob34480a2018-09-17 10:34:45 +020098 set->objs[set->count++] = object;
Radek Krejci5aeea3a2018-09-05 13:29:36 +020099
Michal Vaskob34480a2018-09-17 10:34:45 +0200100 return set->count - 1;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200101}
102
103API int
104ly_set_merge(struct ly_set *trg, struct ly_set *src, int options)
105{
106 unsigned int i, ret;
107 void **new;
108
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200109 LY_CHECK_ARG_RET(NULL, trg, -1);
110 LY_CHECK_ARG_RET(NULL, src, 0);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200111
112 if (!(options & LY_SET_OPT_USEASLIST)) {
113 /* remove duplicates */
114 i = 0;
Michal Vaskob34480a2018-09-17 10:34:45 +0200115 while (i < src->count) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200116 if (ly_set_contains(trg, src->objs[i]) > -1) {
117 ly_set_rm_index(src, i);
118 } else {
119 ++i;
120 }
121 }
122 }
123
124 /* allocate more memory if needed */
Michal Vaskob34480a2018-09-17 10:34:45 +0200125 if (trg->size < trg->count + src->count) {
126 new = realloc(trg->objs, (trg->count + src->count) * sizeof *(trg->objs));
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200127 LY_CHECK_ERR_RET(!new, LOGMEM(NULL), -1);
Michal Vaskob34480a2018-09-17 10:34:45 +0200128 trg->size = trg->count + src->count;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200129 trg->objs = new;
130 }
131
132 /* copy contents from src into trg */
Michal Vaskob34480a2018-09-17 10:34:45 +0200133 memcpy(trg->objs + trg->count, src->objs, src->count * sizeof *(src->objs));
134 ret = src->count;
135 trg->count += ret;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200136
137 /* cleanup */
138 ly_set_free(src);
139 return ret;
140}
141
142API LY_ERR
143ly_set_rm_index(struct ly_set *set, unsigned int index)
144{
Radek Krejci13246392018-09-07 14:57:41 +0200145 LY_CHECK_ARG_RET(NULL, set, LY_EINVAL);
Michal Vaskob34480a2018-09-17 10:34:45 +0200146 LY_CHECK_ERR_RET(((index + 1) > set->count), LOGARG(NULL, set), LY_EINVAL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200147
Michal Vaskob34480a2018-09-17 10:34:45 +0200148 if (index == set->count - 1) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200149 /* removing last item in set */
150 set->objs[index] = NULL;
151 } else {
152 /* removing item somewhere in a middle, so put there the last item */
Michal Vaskob34480a2018-09-17 10:34:45 +0200153 set->objs[index] = set->objs[set->count - 1];
154 set->objs[set->count - 1] = NULL;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200155 }
Michal Vaskob34480a2018-09-17 10:34:45 +0200156 set->count--;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200157
158 return LY_SUCCESS;
159}
160
161API LY_ERR
162ly_set_rm(struct ly_set *set, void *object)
163{
164 unsigned int i;
165
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200166 LY_CHECK_ARG_RET(NULL, set, object, LY_EINVAL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200167
168 /* get index */
Michal Vaskob34480a2018-09-17 10:34:45 +0200169 for (i = 0; i < set->count; i++) {
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200170 if (set->objs[i] == object) {
171 break;
172 }
173 }
Michal Vaskob34480a2018-09-17 10:34:45 +0200174 LY_CHECK_ERR_RET((i == set->count), LOGARG(NULL, set), LY_EINVAL); /* object is not in set */
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200175
176 return ly_set_rm_index(set, i);
177}
178
179API LY_ERR
180ly_set_clean(struct ly_set *set)
181{
Michal Vaskob3d0d6b2018-09-07 10:17:33 +0200182 LY_CHECK_ARG_RET(NULL, set, LY_EINVAL);
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200183
Michal Vaskob34480a2018-09-17 10:34:45 +0200184 set->count = 0;
Radek Krejci5aeea3a2018-09-05 13:29:36 +0200185 return LY_SUCCESS;
186}