Libical API Documentation 4.0 UNRELEASED Go to the stable 3.0 documentation
Loading...
Searching...
No Matches
icalarray.c
Go to the documentation of this file.
1/*======================================================================
2 FILE: icalarray.c
3 CREATOR: Damon Chaplin 07 March 2001
4
5 SPDX-FileCopyrightText: 2001, Ximian, Inc.
6 SPDX-License-Identifier: LGPL-2.1-only OR MPL-2.0
7======================================================================*/
8
15
16#ifdef HAVE_CONFIG_H
17#include <config.h>
18#endif
19
20#include "icalarray.h"
21#include "icalerror_p.h"
22#include "icalmemory.h"
23#include "qsort_gen.h"
24
25#include <stdlib.h>
26#include <string.h>
27
29#ifndef ICALARRAY_DEFAULT_INCREMENT_SIZE
30#define ICALARRAY_DEFAULT_INCREMENT_SIZE 4
31#endif
33
34static void icalarray_expand(icalarray *array, size_t space_needed);
35
36icalarray *icalarray_new(size_t element_size, size_t increment_size)
37{
38 icalarray *array;
39
40 array = (icalarray *)icalmemory_new_buffer(sizeof(icalarray));
41 if (!array) {
43 return NULL;
44 }
45
46 if (!increment_size) {
47 increment_size = ICALARRAY_DEFAULT_INCREMENT_SIZE;
48 }
49
50 array->element_size = element_size;
51 array->increment_size = increment_size;
52 array->num_elements = 0;
53 array->space_allocated = 0;
54 array->chunks = NULL;
55
56 return array;
57}
58
59static void *icalarray_alloc_chunk(const icalarray *array)
60{
61 void *chunk = icalmemory_new_buffer(array->element_size * array->increment_size);
62
63 if (!chunk) {
65 }
66 return chunk;
67}
68
69icalarray *icalarray_copy(const icalarray *originalarray)
70{
71 icalarray *array = icalarray_new(originalarray->element_size, originalarray->increment_size);
72 size_t chunks = originalarray->space_allocated / originalarray->increment_size;
73 if (!array) {
74 return NULL;
75 }
76
77 array->chunks = (void **)icalmemory_new_buffer(chunks * sizeof(void *));
78 if (array->chunks) {
79 for (size_t chunk = 0; chunk < chunks; chunk++) {
80 array->chunks[chunk] = icalarray_alloc_chunk(array);
81 if (array->chunks[chunk]) {
82 memcpy(array->chunks[chunk], originalarray->chunks[chunk],
83 array->increment_size * array->element_size);
84
85 array->space_allocated += array->increment_size;
86 } else {
88 icalarray_free(array);
89 return NULL;
90 }
91 }
92
93 } else {
95 icalarray_free(array);
96 return NULL;
97 }
98
99 array->num_elements = originalarray->num_elements;
100
101 return array;
102}
103
104void icalarray_free(icalarray *array)
105{
106 if (array->chunks) {
107 size_t chunks = array->space_allocated / array->increment_size;
108 size_t chunk;
109
110 for (chunk = 0; chunk < chunks; chunk++) {
111 icalmemory_free_buffer(array->chunks[chunk]);
112 }
113 icalmemory_free_buffer((void *)array->chunks);
114 array->chunks = 0;
115 }
117}
118
119void icalarray_append(icalarray *array, const void *element)
120{
121 size_t pos;
122
123 if (array->num_elements >= array->space_allocated) {
124 icalarray_expand(array, 1);
125 if (array->num_elements >= array->space_allocated) {
126 /* expansion failed. Error has already been set. */
127 return;
128 }
129 }
130
131 pos = array->num_elements++;
132 memcpy(icalarray_element_at(array, pos), element, array->element_size);
133}
134
135void *icalarray_element_at(icalarray *array, size_t position)
136{
137 size_t chunk = position / array->increment_size;
138 size_t offset = position % array->increment_size;
139
140 return (char *)(array->chunks[chunk]) + (offset * array->element_size);
141}
142
143void icalarray_set_element_at(icalarray *array, const void *element, size_t position)
144{
145 memcpy(icalarray_element_at(array, position), element, array->element_size);
146}
147
148void icalarray_remove_element_at(icalarray *array, size_t position)
149{
150 while (position < array->num_elements - 1) {
151 memmove(icalarray_element_at(array, position),
152 icalarray_element_at(array, position + 1), array->element_size);
153 position++;
154 }
155
156 array->num_elements--;
157}
158
159struct _icalarray_sort_context {
160 icalarray *array;
161 int (*compare)(const void *, const void *);
162};
163
164static int icalarray_fcompare(const void *context, size_t i, size_t j)
165{
166 struct _icalarray_sort_context *sort_context = (struct _icalarray_sort_context *)context;
167 void *pI = icalarray_element_at(sort_context->array, i);
168 void *pJ = icalarray_element_at(sort_context->array, j);
169
170 return sort_context->compare(pI, pJ);
171}
172
173static void icalarray_fswap(void *context, size_t i, size_t j)
174{
175 struct _icalarray_sort_context *sort_context = (struct _icalarray_sort_context *)context;
176 void *pI = icalarray_element_at(sort_context->array, i);
177 void *pJ = icalarray_element_at(sort_context->array, j);
178
179 qsort_gen_memswap(pI, pJ, sort_context->array->element_size);
180}
181
182void icalarray_sort(icalarray *array, int (*compare)(const void *, const void *))
183{
184 struct _icalarray_sort_context sort_context;
185 sort_context.array = array;
186 sort_context.compare = compare;
187
188 if (array->num_elements <= 1) {
189 return;
190 }
191
192 qsort_gen(&sort_context, array->num_elements, icalarray_fcompare, icalarray_fswap);
193}
194
195static void icalarray_expand(icalarray *array, size_t space_needed)
196{
197 size_t num_chunks = array->space_allocated / array->increment_size;
198 size_t num_new_chunks;
199 void **new_chunks;
200
201 num_new_chunks = (space_needed + array->increment_size - 1) / array->increment_size;
202 if (!num_new_chunks) {
203 num_new_chunks = 1;
204 }
205
206 new_chunks = (void **)icalmemory_new_buffer((num_chunks + num_new_chunks) * sizeof(void *));
207
208 if (new_chunks) {
209 if (array->chunks && num_chunks) {
210 memcpy((void *)new_chunks, (void *)array->chunks, num_chunks * sizeof(void *));
211 }
212 for (size_t c = 0; c < num_new_chunks; c++) {
213 new_chunks[c + num_chunks] = icalarray_alloc_chunk(array);
214 if (!new_chunks[c + num_chunks]) {
215 num_new_chunks = c;
216 break;
217 }
218 }
219 if (array->chunks) {
220 icalmemory_free_buffer((void *)array->chunks);
221 }
222 array->chunks = new_chunks;
223 array->space_allocated = array->space_allocated + num_new_chunks * array->increment_size;
224 } else {
226 }
227}
icalarray * icalarray_copy(const icalarray *originalarray)
Definition icalarray.c:69
void * icalarray_element_at(icalarray *array, size_t position)
Access an array element.
Definition icalarray.c:135
void icalarray_free(icalarray *array)
Definition icalarray.c:104
void icalarray_sort(icalarray *array, int(*compare)(const void *, const void *))
Sorts the elements of an icalarray using the given comparison function.
Definition icalarray.c:182
void icalarray_append(icalarray *array, const void *element)
Appends an element to an array.
Definition icalarray.c:119
void icalarray_set_element_at(icalarray *array, const void *element, size_t position)
Overwrites an existing element in an array with a new value.
Definition icalarray.c:143
icalarray * icalarray_new(size_t element_size, size_t increment_size)
Definition icalarray.c:36
void icalarray_remove_element_at(icalarray *array, size_t position)
Removes a given element from an array.
Definition icalarray.c:148
An array of arbitrarily-sized elements which grows dynamically as elements are added.
void icalerror_set_errno(icalerrorenum x)
Sets the icalerrno to a given error.
Definition icalerror.c:90
@ ICAL_NEWFAILED_ERROR
Definition icalerror.h:50
@ ICAL_ALLOCATION_ERROR
Definition icalerror.h:53
void icalmemory_free_buffer(void *buf)
Releases a buffer.
Definition icalmemory.c:353
void * icalmemory_new_buffer(size_t size)
Creates new buffer with the specified size.
Definition icalmemory.c:313
Common memory management routines.