utf8ify_rfc822_string() is in libcitadel now
[citadel.git] / libcitadel / lib / array.c
1 /*
2  * This is a quickly-hacked-together implementation of an elastic array class.  It includes constructor and destructor
3  * methods, append and access methods, and that's about it.  The memory allocation is very naive: whenever we are about
4  * to append beyond the size of the buffer, we double its size.
5  *
6  * Copyright (c) 2021 by Art Cancro
7  *
8  * This program is open source software.  Use, duplication, or disclosure
9  * is subject to the terms of the GNU General Public License, version 3.
10  */
11
12
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdio.h>
16 #include "libcitadel.h"
17
18 /*
19  * Constructor for elastic array
20  */
21 Array *array_new(size_t element_size) {
22         Array *newarr = malloc(sizeof(Array));
23         if (newarr) {
24                 memset(newarr, 0, sizeof(Array));
25         }
26         newarr->element_size = element_size;
27         return newarr;
28 }
29
30
31 /*
32  * Destructor for elastic array
33  */
34 void array_free(Array *arr) {
35         free(arr->the_elements);
36         free(arr);
37 }
38
39
40 /*
41  * Append an element to an array (we already know the element size because it's in the data type)
42  */
43 void array_append(Array *arr, void *new_element) {
44
45         if (!arr) {                                             // silently fail if they gave us a null array
46                 return;
47         }
48
49         if ( (arr->the_elements == NULL) || (arr->num_alloc == 0)) {
50                 arr->num_alloc = 1;
51                 arr->num_elements = 0;
52                 arr->the_elements = malloc(arr->element_size * arr->num_alloc);
53                 if (arr->the_elements == NULL) {
54                         abort();
55                 }
56         }
57
58         ++arr->num_elements;
59         if (arr->num_elements > arr->num_alloc) {
60                 arr->num_alloc = arr->num_alloc * 2;            // whenever we exceed the buffer size, we double it.
61                 arr->the_elements = realloc(arr->the_elements, (arr->element_size * arr->num_alloc));
62                 if (arr->the_elements == NULL) {
63                         abort();
64                 }
65         }
66
67         memcpy((arr->the_elements + ( (arr->num_elements-1) * arr->element_size )), new_element, arr->element_size);
68 }
69
70
71 /*
72  * Return the element in an array at the specified index
73  */
74 void *array_get_element_at(Array *arr, int index) {
75         return (arr->the_elements + ( index * arr->element_size ));
76 }
77
78
79 /*
80  * Return the number of elements in an array
81  */
82 int array_len(Array *arr) {
83         return arr->num_elements;
84 }
85
86
87 /*
88  * Sort an array.  We already know the element size and number of elements, so all we need is
89  * a sort function, which we will pass along to qsort().
90  */
91 void array_sort(Array *arr, int (*compar)(const void *, const void *)) {
92         qsort(arr->the_elements, arr->num_elements, arr->element_size, compar);
93 }
94
95
96 /*
97  * Delete an element from an array
98  */
99 void array_delete_element_at(Array *arr, int index) {
100
101         if (index >= arr->num_elements) {               // If the supplied index is out of bounds, return quietly.
102                 return;
103         }
104
105         if (index < 0) {                                // If the supplied index is invalid, return quietly.
106                 return;
107         }
108
109         --arr->num_elements;
110
111         if (index == arr->num_elements) {               // If we deleted the element at the end, there's no more to be done.
112                 return;
113         }
114
115         memcpy(
116                 (arr->the_elements + (index * arr->element_size)),
117                 arr->the_elements + ((index+1) * arr->element_size),
118                 (arr->num_elements - index) * arr->element_size
119         );
120 }