libamxc  1.10.3
C Generic Data Containers
amxc_array.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 
55 #include <stdlib.h>
56 #include <string.h>
57 
58 #include <amxc/amxc_array.h>
59 #include <amxc/amxc_macros.h>
60 
61 #define AMXC_ARRAY_AUTO_GROW_ITEMS 3
62 #define AMXC_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
63 
70 static void amxc_array_initialize_items(amxc_array_t* array, const size_t start_pos) {
71  amxc_array_it_t* it = NULL;
72 
73  for(size_t index = start_pos; index < array->items; index++) {
74  it = &(array->buffer[index]);
75  it->array = array;
76  it->data = NULL;
77  }
78 }
79 
81  const size_t start_pos,
82  const size_t items,
84  amxc_array_it_t* it = NULL;
85  for(unsigned int index = start_pos; index < start_pos + items; index++) {
86  it = &(array->buffer[index]);
87  if(it->data != NULL) {
88  if(func != NULL) {
89  func(it);
90  }
91  it->data = NULL;
92  }
93  }
94 
95  return;
96 }
97 
98 static int amxc_array_realloc(amxc_array_t* array, const size_t items) {
99  int retval = -1;
100  amxc_array_it_t* buffer = NULL;
101 
102  if(array->buffer != NULL) {
103  buffer = (amxc_array_it_t*) realloc(array->buffer, sizeof(amxc_array_it_t) * items);
104  } else {
105  buffer = (amxc_array_it_t*) calloc(items, sizeof(amxc_array_it_t));
106  }
107  if(buffer != NULL) {
108  array->buffer = buffer;
109  array->items = items;
110  retval = 0;
111  }
112 
113  return retval;
114 }
115 
117  const size_t start) {
118  size_t index = start;
119  while(index > 0 && array->buffer[index].data == NULL) {
120  index--;
121  }
122 
123  return index;
124 }
125 
127  const size_t start) {
128  size_t index = start;
129  while(index < array->items && array->buffer[index].data == NULL) {
130  index++;
131  }
132 
133  return (index == array->items) ? 0 : index;
134 }
135 
138  int32_t lo,
139  int32_t high) {
140  int retval = 0;
141  int32_t i = lo + 1;
142  int32_t j = high;
143 
144  while(i <= j) {
145  while(i <= high &&
146  cmp(&array->buffer[i], &array->buffer[lo]) <= 0 &&
147  i <= j) {
148  i++;
149  }
150  while(j >= lo &&
151  cmp(&array->buffer[j], &array->buffer[lo]) > 0 &&
152  i <= j) {
153  j--;
154  }
155  if(i <= j) {
156  amxc_array_it_swap(&array->buffer[i], &array->buffer[j]);
157  }
158  }
159  amxc_array_it_swap(&array->buffer[lo], &array->buffer[j]);
160 
161  if(j - 1 - lo > 1) {
162  amxc_array_sort_internal(array, cmp, lo, j - 1);
163  } else {
164  if(cmp(&array->buffer[lo], &array->buffer[lo + 1]) > 0) {
165  amxc_array_it_swap(&array->buffer[lo], &array->buffer[lo + 1]);
166  }
167  }
168  if(high - (j + 1) > 1) {
169  amxc_array_sort_internal(array, cmp, j + 1, high);
170  } else {
171  if(cmp(&array->buffer[high - 1], &array->buffer[high]) > 0) {
172  amxc_array_it_swap(&array->buffer[high - 1], &array->buffer[high]);
173  }
174  }
175 
176  return retval;
177 }
178 
179 int8_t amxc_array_new(amxc_array_t** array, const size_t items) {
180  int8_t retval = -1;
181  when_null(array, exit);
182 
183  /* allocate the array structure */
184  *array = (amxc_array_t*) calloc(1, sizeof(amxc_array_t));
185  when_null(*array, exit);
186 
187  /* set the number of items in the array */
188  (*array)->items = items;
189  (*array)->first_used = 0;
190  (*array)->last_used = 0;
191 
192  /* if no items need to be pre-allocated, leave */
193  if(items == 0) {
194  retval = 0;
195  goto exit;
196  }
197 
198  /* allocate the buffer */
199  amxc_array_realloc(*array, items);
200  if((*array)->buffer == NULL) {
201  free(*array);
202  *array = NULL;
203  goto exit;
204  }
206 
207  retval = 0;
208 
209 exit:
210  return retval;
211 }
212 
214  when_null(array, exit);
215  when_null(*array, exit);
216 
217  if(func != NULL) {
218  // When no delete callback function is given,
219  // it is not needed to call the clean items.
220  amxc_array_clean_items(*array, 0, (*array)->items, func);
221  }
222 
223  free((*array)->buffer);
224  free(*array);
225  *array = NULL;
226 
227 exit:
228  return;
229 }
230 
231 int amxc_array_init(amxc_array_t* const array, const size_t items) {
232  int retval = -1;
233  when_null(array, exit);
234 
235  // initialize array data
236  array->items = 0;
237  array->buffer = NULL;
238  array->first_used = 0;
239  array->last_used = 0;
240 
241  // if no items need to be pre-allocated, leave
242  if(items == 0) {
243  retval = 0;
244  goto exit;
245  }
246 
247  // allocate the buffer
248  amxc_array_realloc(array, items);
249  when_null(array->buffer, exit);
250 
251  // set the allocated size
252  array->items = items;
254 
255  retval = 0;
256 
257 exit:
258  return retval;
259 }
260 
262  when_null(array, exit);
263 
264  if(func != NULL) {
265  // When no delete callback function is given,
266  // it is not needed to call the clean items.
267  amxc_array_clean_items(array, 0, array->items, func);
268  }
269 
270  free(array->buffer);
271  array->buffer = NULL;
272  array->items = 0;
273  array->first_used = 0;
274  array->last_used = 0;
275 
276 exit:
277  return;
278 }
279 
280 int amxc_array_grow(amxc_array_t* const array, const size_t items) {
281  int retval = -1;
282  size_t old_items = 0;
283  when_null(array, exit);
284 
285  if(items == 0) {
286  retval = 0;
287  goto exit;
288  }
289 
290  old_items = array->items;
291  retval = amxc_array_realloc(array, array->items + items);
293 
294 exit:
295  return retval;
296 }
297 
299  const size_t items,
300  amxc_array_it_delete_t func) {
301  int retval = -1;
302  when_null(array, exit);
303  when_true(items > array->items, exit); // out of range
304 
305  if(items == array->items) {
306  amxc_array_clean(array, func);
307 
308  retval = 0;
309  goto exit;
310  }
311 
312  amxc_array_clean_items(array, array->items - items, items, func);
313  retval = amxc_array_realloc(array, array->items - items);
314  array->last_used = amxc_array_calculate_last_used(array, array->items - 1);
315  if(array->first_used > array->items - 1) {
316  array->first_used = 0;
317  }
318 
319 exit:
320  return retval;
321 }
322 
324  const size_t items,
325  amxc_array_it_delete_t func) {
326  int retval = -1;
327  amxc_array_it_t* src = NULL;
328  amxc_array_it_t* dst = NULL;
329  size_t len = 0;
330  when_null(array, exit);
331  when_true(items > array->items, exit);
332 
333  if(!items) {
334  retval = 0;
335  goto exit;
336  }
337 
338  if(items == array->items) {
339  amxc_array_clean_items(array, 0, array->items, func);
340  array->last_used = 0;
341  array->first_used = 0;
342  retval = 0;
343  goto exit;
344  }
345 
346  src = array->buffer;
347  dst = &array->buffer[items];
348  len = (array->items - items) * sizeof(amxc_array_it_t);
349 
350  memmove(dst, src, len);
351  amxc_array_clean_items(array, 0, items, func);
352  array->first_used = amxc_array_calculate_first_used(array, items);
353  array->last_used = amxc_array_calculate_last_used(array, array->items - 1);
354 
355  retval = 0;
356 
357 exit:
358  return retval;
359 }
360 
362  const size_t items,
363  amxc_array_it_delete_t func) {
364  int retval = -1;
365  amxc_array_it_t* src = NULL;
366  amxc_array_it_t* dst = NULL;
367  size_t len = 0;
368  when_null(array, exit);
369  when_true(items > array->items, exit);
370 
371  if(!items) {
372  retval = 0;
373  goto exit;
374  }
375 
376  if(items == array->items) {
377  amxc_array_clean_items(array, 0, array->items, func);
378  retval = 0;
379  array->last_used = 0;
380  array->first_used = 0;
381  goto exit;
382  }
383 
384  src = &array->buffer[items];
385  dst = array->buffer;
386  len = (array->items - items) * sizeof(amxc_array_it_t);
387 
388  memmove(dst, src, len);
389  amxc_array_clean_items(array, array->items - items, items, func);
390  array->first_used = amxc_array_calculate_first_used(array, 0);
391  array->last_used = amxc_array_calculate_last_used(array, array->items - items);
392 
393  retval = 0;
394 
395 exit:
396  return retval;
397 }
398 
400  bool retval = true;
401  when_null(array, exit);
402 
403  if(array->last_used != 0) {
404  retval = false;
405  }
406 
407  if((array->buffer != NULL) && (array->buffer[0].data != NULL)) {
408  retval = false;
409  }
410 
411 exit:
412  return retval;
413 }
414 
415 size_t amxc_array_size(const amxc_array_t* const array) {
416  size_t retval = 0;
417  when_null(array, exit);
418 
419  for(size_t index = 0; index < array->items; index++) {
420  if(array->buffer[index].data != NULL) {
421  retval++;
422  }
423  }
424 
425 exit:
426  return retval;
427 }
428 
430  amxc_array_it_t* it = NULL;
431  size_t index = 0;
432  when_null(array, exit);
433  when_null(data, exit);
434 
435  if(!amxc_array_is_empty(array)) {
436  index = array->last_used + 1;
437  }
438 
439  if(index >= array->items) {
441  }
442 
443  it = amxc_array_set_data_at(array, index, data);
444 
445 exit:
446  return it;
447 }
448 
450  amxc_array_it_t* it = NULL;
451  size_t index = 0;
452  bool grow = false;
453  when_null(array, exit);
454  when_null(data, exit);
455 
456  grow = ((!amxc_array_is_empty(array) && array->first_used == 0) ||
457  (array->buffer == NULL));
458 
459  if(grow) {
462  }
463 
464  if(!amxc_array_is_empty(array)) {
465  index = array->first_used - 1;
466  }
467 
468  it = amxc_array_set_data_at(array, index, data);
469 
470 exit:
471  return it;
472 }
473 
475  const unsigned int index,
476  void* data) {
478  when_null(it, exit);
479 
480  if(data != NULL) {
482  array->last_used = index;
483  array->first_used = index;
484  } else {
485  array->last_used = (array->last_used < index) ? index : array->last_used;
486  array->first_used = (array->first_used > index) ? index : array->first_used;
487  }
488  it->data = data;
489  } else {
490  void* tmp = it->data;
491  it->data = data;
492  if((tmp != NULL) && (index == array->last_used)) {
493  array->last_used = amxc_array_calculate_last_used(array, array->last_used);
494  }
495  if((tmp != NULL) && (index == array->first_used)) {
496  array->first_used = amxc_array_calculate_first_used(array, array->first_used);
497  }
498  }
499 
500 exit:
501  return it;
502 }
503 
505  const unsigned int index) {
506  amxc_array_it_t* it = NULL;
507  when_null(array, exit);
508  when_null(array->buffer, exit);
509  when_true(index >= array->items, exit);
510 
511  it = &array->buffer[index];
512 
513 exit:
514  return it;
515 }
516 
518  amxc_array_it_t* it = NULL;
519  when_null(array, exit);
520 
521  if(!amxc_array_is_empty(array)) {
522  it = &array->buffer[array->first_used];
523  }
524 
525 exit:
526  return it;
527 }
528 
530  amxc_array_it_t* it = NULL;
531  size_t index = 0;
532  when_null(array, exit);
533 
534  while(index < array->items && array->buffer[index].data != NULL) {
535  index++;
536  }
537 
538  if(index < array->items) {
539  it = &array->buffer[index];
540  }
541 
542 exit:
543  return it;
544 }
545 
547  amxc_array_it_t* it = NULL;
548  when_null(array, exit);
549 
550  if(!amxc_array_is_empty(array)) {
551  it = &array->buffer[array->last_used];
552  }
553 
554 exit:
555  return it;
556 }
557 
559  amxc_array_it_t* it = NULL;
560  size_t index = 0;
561  when_null(array, exit);
562 
563  index = array->items;
564  while(index > 0 && array->buffer[index - 1].data != NULL) {
565  index--;
566  }
567 
568  if(index > 0) {
569  it = &array->buffer[index - 1];
570  }
571 
572 exit:
573  return it;
574 }
575 
577  void* data = NULL;
579  if(it != NULL) {
580  data = it->data;
582  }
583  return data;
584 }
585 
587  void* data = NULL;
589  if(it != NULL) {
590  data = it->data;
592  }
593  return data;
594 }
595 
597  int retval = -1;
598  size_t i = 0;
599  when_null(array, exit);
600  when_null(cmp, exit);
601 
602  if(array->last_used == 0) {
603  retval = 0;
604  goto exit;
605  }
606  i = array->last_used;
607  do {
608  i--;
609  if(array->buffer[i].data == NULL) {
610  amxc_array_it_swap(&array->buffer[i],
611  &array->buffer[array->last_used]);
612  array->last_used--;
613  }
614  } while(i != 0);
615 
616  retval = amxc_array_sort_internal(array, cmp, 0, array->last_used);
617 
618 exit:
619  return retval;
620 }
static size_t amxc_array_calculate_first_used(amxc_array_t *array, const size_t start)
Definition: amxc_array.c:126
static void amxc_array_initialize_items(amxc_array_t *array, const size_t start_pos)
Definition: amxc_array.c:70
static void amxc_array_clean_items(amxc_array_t *array, const size_t start_pos, const size_t items, amxc_array_it_delete_t func)
Definition: amxc_array.c:80
static size_t amxc_array_calculate_last_used(amxc_array_t *array, const size_t start)
Definition: amxc_array.c:116
#define AMXC_ARRAY_AUTO_GROW_ITEMS
Definition: amxc_array.c:61
static int amxc_array_sort_internal(amxc_array_t *const array, amxc_array_it_cmp_t cmp, int32_t lo, int32_t high)
Definition: amxc_array.c:136
static int amxc_array_realloc(amxc_array_t *array, const size_t items)
Definition: amxc_array.c:98
Ambiorix array API header file.
#define when_failed(x, l)
Definition: amxc_macros.h:142
#define when_true(x, l)
Definition: amxc_macros.h:134
#define when_null(x, l)
Definition: amxc_macros.h:126
int(* amxc_array_it_cmp_t)(amxc_array_it_t *it1, amxc_array_it_t *it2)
Type definition of an array iterator compare callback function.
Definition: amxc_array.h:213
unsigned int amxc_array_it_index(const amxc_array_it_t *const it)
Gets the index of the iterator in the array.
int amxc_array_it_swap(amxc_array_it_t *const it1, amxc_array_it_t *const it2)
Swaps the content of the two array iterators.
amxc_array_it_t * amxc_array_get_last(const amxc_array_t *const array)
Gets the item iterator of the last used item in the array.
Definition: amxc_array.c:546
int amxc_array_shift_right(amxc_array_t *const array, const size_t items, amxc_array_it_delete_t func)
Shift all items to the right in the array.
Definition: amxc_array.c:323
amxc_array_it_t * amxc_array_set_data_at(amxc_array_t *const array, const unsigned int index, void *data)
Sets data at the given index.
Definition: amxc_array.c:474
void * amxc_array_take_first_data(amxc_array_t *const array)
Takes the data pointer from the first used item in the array.
Definition: amxc_array.c:576
size_t amxc_array_size(const amxc_array_t *const array)
Calculates the number of used items in the array.
Definition: amxc_array.c:415
amxc_array_it_t * amxc_array_get_last_free(const amxc_array_t *const array)
Gets the last free position in the array.
Definition: amxc_array.c:558
int amxc_array_shift_left(amxc_array_t *const array, const size_t items, amxc_array_it_delete_t func)
Shift all items to the left in the array.
Definition: amxc_array.c:361
void * amxc_array_take_last_data(amxc_array_t *const array)
Takes the data pointer from the last used item in the array.
Definition: amxc_array.c:586
int amxc_array_init(amxc_array_t *const array, const size_t items)
Initializes an array.
Definition: amxc_array.c:231
amxc_array_it_t * amxc_array_get_at(const amxc_array_t *const array, const unsigned int index)
Gets the item iterator for the given index.
Definition: amxc_array.c:504
int amxc_array_shrink(amxc_array_t *const array, const size_t items, amxc_array_it_delete_t func)
Shrinks the array.
Definition: amxc_array.c:298
amxc_array_it_t * amxc_array_get_first(const amxc_array_t *const array)
Gets the item iterator of the first used item in the array.
Definition: amxc_array.c:517
amxc_array_it_t * amxc_array_prepend_data(amxc_array_t *const array, void *data)
Adds an item before the first used item in the array.
Definition: amxc_array.c:449
bool amxc_array_is_empty(const amxc_array_t *const array)
Checks that the array is empty.
Definition: amxc_array.c:399
int8_t amxc_array_new(amxc_array_t **array, const size_t items)
Allocates an array.
Definition: amxc_array.c:179
void amxc_array_clean(amxc_array_t *const array, amxc_array_it_delete_t func)
Removes all items from the array.
Definition: amxc_array.c:261
amxc_array_it_t * amxc_array_get_first_free(const amxc_array_t *const array)
Gets the first free position in the array.
Definition: amxc_array.c:529
void(* amxc_array_it_delete_t)(amxc_array_it_t *it)
Definition of the array item delete callback function.
Definition: amxc_array.h:194
amxc_array_it_t * amxc_array_append_data(amxc_array_t *const array, void *data)
Adds an item after the last used item in the array.
Definition: amxc_array.c:429
int amxc_array_sort(amxc_array_t *const array, amxc_array_it_cmp_t cmp)
Sorts the content of the array.
Definition: amxc_array.c:596
int amxc_array_grow(amxc_array_t *const array, const size_t items)
Expands the array.
Definition: amxc_array.c:280
void amxc_array_delete(amxc_array_t **array, amxc_array_it_delete_t func)
Frees the previously allocated array.
Definition: amxc_array.c:213
The array iterator structure.
Definition: amxc_array.h:174
The array structure.
Definition: amxc_array.h:162
char data[]
static unsigned int array[2006]
static amxc_htable_it_t it[2000]