libamxc  1.10.3
C Generic Data Containers
amxc_set.c
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** SPDX-License-Identifier: BSD-2-Clause-Patent
4 **
5 ** SPDX-FileCopyrightText: Copyright (c) 2023 SoftAtHome
6 **
7 ** Redistribution and use in source and binary forms, with or without modification,
8 ** are permitted provided that the following conditions are met:
9 **
10 ** 1. Redistributions of source code must retain the above copyright notice,
11 ** this list of conditions and the following disclaimer.
12 **
13 ** 2. Redistributions in binary form must reproduce the above copyright notice,
14 ** this list of conditions and the following disclaimer in the documentation
15 ** and/or other materials provided with the distribution.
16 **
17 ** Subject to the terms and conditions of this license, each copyright holder
18 ** and contributor hereby grants to those receiving rights under this license
19 ** a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable
20 ** (except for failure to satisfy the conditions of this license) patent license
21 ** to make, have made, use, offer to sell, sell, import, and otherwise transfer
22 ** this software, where such license applies only to those patent claims, already
23 ** acquired or hereafter acquired, licensable by such copyright holder or contributor
24 ** that are necessarily infringed by:
25 **
26 ** (a) their Contribution(s) (the licensed copyrights of copyright holders and
27 ** non-copyrightable additions of contributors, in source or binary form) alone;
28 ** or
29 **
30 ** (b) combination of their Contribution(s) with the work of authorship to which
31 ** such Contribution(s) was added by such copyright holder or contributor, if,
32 ** at the time the Contribution is added, such addition causes such combination
33 ** to be necessarily infringed. The patent license shall not apply to any other
34 ** combinations which include the Contribution.
35 **
36 ** Except as expressly stated above, no rights or licenses from any copyright
37 ** holder or contributor is granted under this license, whether expressly, by
38 ** implication, estoppel or otherwise.
39 **
40 ** DISCLAIMER
41 **
42 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
43 ** AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 ** ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
46 ** LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
48 ** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
49 ** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
50 ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
51 ** USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
52 **
53 ****************************************************************************/
54 #ifndef _GNU_SOURCE
55 #define _GNU_SOURCE
56 #endif
57 
58 #include <stdlib.h>
59 #include <string.h>
60 #include <ctype.h>
61 #include <stdio.h>
62 
63 #include <amxc/amxc_set.h>
64 #include <amxc/amxc_macros.h>
65 
68  free(flag->flag);
69  free(flag);
70 }
71 
72 static amxc_flag_t* amxc_set_flag_find(const amxc_set_t* const set, const char* flag) {
73  amxc_flag_t* f = NULL;
74  amxc_llist_iterate(it, &set->list) {
76  if(strcmp(f->flag, flag) == 0) {
77  break;
78  }
79  f = NULL;
80  }
81  return f;
82 }
83 
84 static void amxc_set_flag_add(amxc_set_t* set,
85  const char* flag,
86  int flaglen,
87  int count) {
88  amxc_flag_t* f = NULL;
89  char* str = NULL;
90 
91  if(flaglen != 0) {
92  str = (char*) calloc(flaglen + 1, 1);
93  when_null(str, exit);
94  strncpy(str, flag, flaglen);
95  } else {
96  str = strdup(flag);
97  when_null(str, exit);
98  }
99 
100  f = amxc_set_flag_find(set, str);
101  if(f != NULL) {
102  if(set->counted) {
103  f->count += count;
104  set->count += count;
105  }
106  free(str);
107  goto exit;
108  }
109 
110  f = (amxc_flag_t*) calloc(1, sizeof(amxc_flag_t));
111  if(f == NULL) {
112  free(str);
113  goto exit;
114  }
115  f->flag = str;
116 
117  amxc_llist_append(&set->list, &f->it);
118  f->count = count;
119  set->count += count;
120  if(set->alert_handler) {
121  set->alert_handler(set, f->flag, true, set->priv);
122  }
123 
124 exit:
125  return;
126 }
127 
131  set->count -= flag->count;
132  if(set->alert_handler != NULL) {
133  set->alert_handler(set, flag->flag, false, set->priv);
134  }
136 }
137 
138 int amxc_set_new(amxc_set_t** set, bool counted) {
139  int retval = -1;
140 
141  when_null(set, exit);
142 
143  *set = (amxc_set_t*) calloc(1, sizeof(amxc_set_t));
144  when_null(*set, exit);
145  retval = amxc_set_init(*set, counted);
146 
147 exit:
148  return retval;
149 }
150 
152  when_null(set, exit);
153 
154  amxc_set_clean(*set);
155  free(*set);
156  *set = NULL;
157 
158 exit:
159  return;
160 }
161 
162 int amxc_set_init(amxc_set_t* const set, bool counted) {
163  int retval = -1;
164 
165  when_null(set, exit);
166  amxc_llist_init(&set->list);
167  set->alert_handler = NULL;
168  set->counted = counted;
169  set->count = 0;
170  set->priv = NULL;
171  retval = 0;
172 
173 exit:
174  return retval;
175 }
176 
177 void amxc_set_clean(amxc_set_t* const set) {
178  when_null(set, exit);
179 
181  set->count = 0;
182 
183 exit:
184  return;
185 }
186 
187 amxc_set_t* amxc_set_copy(const amxc_set_t* const set) {
188  amxc_set_t* copy = NULL;
189 
190  when_null(set, exit);
191  when_failed(amxc_set_new(&copy, set->counted), exit);
192 
193  amxc_set_union(copy, set);
194 
195 exit:
196  return copy;
197 }
198 
200  when_null(set, exit);
201 
202  amxc_llist_for_each(it, &set->list) {
203  amxc_set_flag_delete(set, it);
204  }
205 
206 exit:
207  return;
208 }
209 
210 int amxc_set_parse(amxc_set_t* set, const char* str) {
211  int retval = -1;
212  amxc_set_t newset;
213 
214  when_null(set, exit);
215  amxc_set_init(&newset, set->counted);
216 
217  if((str != NULL) && (*str != 0)) {
218  const char* strptr = str;
219  char* newstr = NULL;
220  int count = 0;
221  do {
222  if(!((*str == '\0') || (isspace(*str) != 0) || (*str == ':'))) {
223  continue;
224  }
225  if(str > strptr) {
226  if(*str == ':') {
227  count = strtol(str + 1, &newstr, 0);
228  if((*newstr != '\0') && (isspace(*newstr) == 0)) {
229  goto exit_clean;
230  }
231  if(count > 0) {
232  amxc_set_flag_add(&newset, strptr, str - strptr, set->counted ? count : 1);
233  }
234  str = newstr;
235  } else {
236  amxc_set_flag_add(&newset, strptr, str - strptr, 1);
237  }
238  }
239  strptr = str + 1;
240  } while(*str++);
241  }
242  // intersect + union instead of simply overwrite to avoid that unchanged flags are cleared and set again
243  amxc_set_intersect(set, &newset);
244  amxc_set_union(set, &newset);
245  if(set->counted) {
246  set->count = 0;
247  amxc_llist_iterate(it, &set->list) {
249  amxc_flag_t* new_flag = amxc_set_flag_find(&newset, flag->flag);
250  if((flag != NULL) && (new_flag != NULL)) {
251  flag->count = new_flag->count;
252  set->count += flag->count;
253  }
254  }
255  }
256  retval = 0;
257 
258 exit_clean:
259  amxc_set_clean(&newset);
260 exit:
261  return retval;
262 }
263 
264 char* amxc_set_to_string_sep(const amxc_set_t* const set, const char* sep) {
265  int n = 0;
266  char* buf = NULL;
267  char* bufptr = NULL;
268  char countbuf[16];
269  int started = 0;
270 
271  when_null(set, exit);
272  when_null(sep, exit);
273 
274  amxc_llist_iterate(it, &set->list) {
276  n += strlen(f->flag) + started;
277  if((f->count != 1) && set->counted) {
278  n += sprintf(countbuf, ":%d", f->count);
279  }
280  started = 1;
281  }
282  buf = (char*) calloc(n + 1, 1);
283  bufptr = buf;
284  when_null(buf, exit);
285 
286  started = 0;
287  amxc_llist_iterate(it, &set->list) {
289  if((f->count != 1) && set->counted) {
290  bufptr += sprintf(bufptr, "%s%s:%d", started ? sep : "", f->flag, f->count);
291  } else {
292  bufptr += sprintf(bufptr, "%s%s", started ? sep : "", f->flag);
293  }
294  started = 1;
295  }
296 
297 exit:
298  return buf;
299 }
300 
301 char* amxc_set_to_string(const amxc_set_t* const set) {
302  return amxc_set_to_string_sep(set, " ");
303 }
304 
305 void amxc_set_add_flag(amxc_set_t* set, const char* flag) {
306  when_null(set, exit);
307  when_str_empty(flag, exit);
308 
309  amxc_set_flag_add(set, flag, 0, 1);
310 
311 exit:
312  return;
313 }
314 
315 void amxc_set_remove_flag(amxc_set_t* set, const char* flag) {
316  amxc_flag_t* f = NULL;
317 
318  when_null(set, exit);
319  when_str_empty(flag, exit);
320 
321  f = amxc_set_flag_find(set, flag);
322  if(f == NULL) {
323  goto exit;
324  }
325 
326  if(set->counted && (f->count > 1)) {
327  f->count--;
328  set->count--;
329  } else {
330  amxc_set_flag_delete(set, &f->it);
331  }
332 
333 exit:
334  return;
335 }
336 
337 bool amxc_set_has_flag(const amxc_set_t* const set, const char* flag) {
338  bool retval = false;
339 
340  when_null(set, exit);
341  when_str_empty(flag, exit);
342 
343  retval = amxc_set_flag_find(set, flag) ? true : false;
344 
345 exit:
346  return retval;
347 }
348 
349 uint32_t amxc_set_get_count(const amxc_set_t* const set, const char* flag) {
350  uint32_t retval = 0;
351 
352  when_null(set, exit);
353 
354  if((flag != NULL) && (*flag != 0)) {
355  amxc_flag_t* f = amxc_set_flag_find(set, flag);
356  retval = f != NULL ? f->count : 0;
357  } else {
358  return set->count;
359  }
360 
361 exit:
362  return retval;
363 }
364 
365 void amxc_set_union(amxc_set_t* const set, const amxc_set_t* const operand) {
366  when_null(set, exit);
367  when_null(operand, exit);
368 
369  amxc_llist_iterate(it, &operand->list) {
371  amxc_flag_t* f = amxc_set_flag_find(set, fo->flag);
372  if(f == NULL) {
373  amxc_set_flag_add(set, fo->flag, 0, set->counted ? fo->count : 1);
374  } else if(set->counted) {
375  set->count += fo->count;
376  f->count += fo->count;
377  }
378  }
379 
380 exit:
381  return;
382 }
383 
384 void amxc_set_intersect(amxc_set_t* const set, const amxc_set_t* const operand) {
385  when_null(set, exit);
386 
387  if(operand == NULL) {
388  amxc_set_reset(set);
389  goto exit;
390  }
391 
392  amxc_llist_for_each(it, &set->list) {
394  amxc_flag_t* fo = amxc_set_flag_find(operand, f->flag);
395 
396  if(fo == NULL) {
397  amxc_set_flag_delete(set, &f->it);
398  } else if(set->counted && (fo->count < f->count)) {
399  set->count += fo->count - f->count;
400  f->count = fo->count;
401  }
402  }
403 
404 exit:
405  return;
406 }
407 
408 void amxc_set_subtract(amxc_set_t* const set, const amxc_set_t* const operand) {
409  when_null(set, exit);
410  when_null(operand, exit);
411 
412  amxc_llist_iterate(it, &operand->list) {
414  amxc_flag_t* f = amxc_set_flag_find(set, fo->flag);
415  if(f == NULL) {
416  continue;
417  }
418  if(set->counted && (f->count > fo->count)) {
419  set->count -= fo->count;
420  f->count -= fo->count;
421  } else {
422  amxc_set_flag_delete(set, &f->it);
423  }
424  }
425 
426 exit:
427  return;
428 }
429 
430 bool amxc_set_is_equal(const amxc_set_t* const set1,
431  const amxc_set_t* const set2) {
432  if(set1 != NULL) {
433  amxc_llist_iterate(it, &set1->list) {
435  if(amxc_set_get_count(set2, f->flag) != f->count) {
436  return false;
437  }
438  }
439  }
440 
441  if(set2 != NULL) {
442  amxc_llist_iterate(it, &set2->list) {
444  if(amxc_set_get_count(set1, f->flag) != f->count) {
445  return false;
446  }
447  }
448  }
449 
450  return true;
451 }
452 
453 void amxc_set_alert_cb(amxc_set_t* set, amxc_set_alert_t handler, void* priv) {
454  when_null(set, exit);
455 
456  set->alert_handler = handler;
457  set->priv = priv;
458 
459 exit:
460  return;
461 }
462 
464  const amxc_set_t* const operand) {
465  amxc_set_t* tmp = NULL;
466 
467  when_null(set, exit);
468  when_null(operand, exit);
469 
470  tmp = amxc_set_copy(operand);
471  when_null(tmp, exit);
472 
473  amxc_set_subtract(tmp, set);
474  amxc_set_subtract(set, operand);
475  amxc_set_union(set, tmp);
476 
477  amxc_set_delete(&tmp);
478 exit:
479  return;
480 }
#define when_failed(x, l)
Definition: amxc_macros.h:142
#define when_null(x, l)
Definition: amxc_macros.h:126
#define when_str_empty(x, l)
Definition: amxc_macros.h:146
static amxc_flag_t * amxc_set_flag_find(const amxc_set_t *const set, const char *flag)
Definition: amxc_set.c:72
static void amxc_set_flag_delete(amxc_set_t *set, amxc_llist_it_t *it)
Definition: amxc_set.c:128
static void amxc_set_flag_free(amxc_llist_it_t *it)
Definition: amxc_set.c:66
static void amxc_set_flag_add(amxc_set_t *set, const char *flag, int flaglen, int count)
Definition: amxc_set.c:84
Ambiorix set API header file.
void(* amxc_set_alert_t)(amxc_set_t *set, const char *flag, bool value, void *priv)
Flag set alert handler type.
Definition: amxc_set.h:107
#define amxc_container_of(addr, type, member)
Calculates the address of the containing structure.
Definition: amxc_common.h:83
void amxc_llist_it_take(amxc_llist_it_t *const it)
Removes the iterator from the list.
int amxc_llist_append(amxc_llist_t *const llist, amxc_llist_it_t *const it)
Adds an item to the end of the linked list.
Definition: amxc_llist.c:169
#define amxc_llist_iterate(it, list)
Loops over the list from head to tail.
Definition: amxc_llist.h:270
int amxc_llist_init(amxc_llist_t *const llist)
Initializes a linked list.
Definition: amxc_llist.c:111
void amxc_llist_clean(amxc_llist_t *const llist, amxc_llist_it_delete_t func)
Removes all items from the linked list.
Definition: amxc_llist.c:124
#define amxc_llist_for_each(it, list)
Loops over the list from head to tail.
Definition: amxc_llist.h:253
void amxc_set_remove_flag(amxc_set_t *set, const char *flag)
Removes a flag from a set or decreases the flag counter.
Definition: amxc_set.c:315
char * amxc_set_to_string_sep(const amxc_set_t *const set, const char *sep)
Converts a set to a separated string of flags.
Definition: amxc_set.c:264
int amxc_set_new(amxc_set_t **set, bool counted)
Allocates a set.
Definition: amxc_set.c:138
void amxc_set_reset(amxc_set_t *set)
Reset or empty a set, i.e. clear all flags.
Definition: amxc_set.c:199
amxc_set_t * amxc_set_copy(const amxc_set_t *const set)
Copies a set.
Definition: amxc_set.c:187
void amxc_set_intersect(amxc_set_t *const set, const amxc_set_t *const operand)
Intersect a set with another set.
Definition: amxc_set.c:384
bool amxc_set_is_equal(const amxc_set_t *const set1, const amxc_set_t *const set2)
Compare two sets.
Definition: amxc_set.c:430
void amxc_set_add_flag(amxc_set_t *set, const char *flag)
Adds a flag to a set, or increases the flag counter.
Definition: amxc_set.c:305
void amxc_set_delete(amxc_set_t **set)
Frees a set.
Definition: amxc_set.c:151
void amxc_set_symmetric_difference(amxc_set_t *const set, const amxc_set_t *const operand)
Calculates the symmetric difference of two sets.
Definition: amxc_set.c:463
int amxc_set_init(amxc_set_t *const set, bool counted)
Initializes a set.
Definition: amxc_set.c:162
char * amxc_set_to_string(const amxc_set_t *const set)
Converts a set to a space-separated string of flags.
Definition: amxc_set.c:301
uint32_t amxc_set_get_count(const amxc_set_t *const set, const char *flag)
Get a flag counter.
Definition: amxc_set.c:349
int amxc_set_parse(amxc_set_t *set, const char *str)
Parses a space-separated string of flags and adds them to the set.
Definition: amxc_set.c:210
void amxc_set_clean(amxc_set_t *const set)
Cleans a set.
Definition: amxc_set.c:177
void amxc_set_union(amxc_set_t *const set, const amxc_set_t *const operand)
Joins two sets.
Definition: amxc_set.c:365
bool amxc_set_has_flag(const amxc_set_t *const set, const char *flag)
Check if a set contains a flag.
Definition: amxc_set.c:337
void amxc_set_alert_cb(amxc_set_t *set, amxc_set_alert_t handler, void *priv)
Install a set alert callback function.
Definition: amxc_set.c:453
void amxc_set_subtract(amxc_set_t *const set, const amxc_set_t *const operand)
Subtract a set from another set.
Definition: amxc_set.c:408
The linked list iterator structure.
Definition: amxc_llist.h:215
The flag structure.
Definition: amxc_set.h:118
uint32_t count
Definition: amxc_set.h:121
char * flag
Definition: amxc_set.h:120
amxc_llist_it_t it
Definition: amxc_set.h:119
The set structure.
Definition: amxc_set.h:129
bool counted
Definition: amxc_set.h:134
amxc_set_alert_t alert_handler
Definition: amxc_set.h:131
int count
Definition: amxc_set.h:135
amxc_llist_t list
Definition: amxc_set.h:130
void * priv
Definition: amxc_set.h:133
static amxc_htable_it_t it[2000]