$darkmode
Libical API Documentation 4.0 STABLE VERSION Visit the v3.0 documentation
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 
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
32 
34 static void icalarray_expand(icalarray *array, size_t space_needed);
35 
36 icalarray *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 
59 static 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 
69 icalarray *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 
104 void 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  }
116  icalmemory_free_buffer(array);
117 }
118 
119 void 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 
135 void *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 
143 void 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 
148 void 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 
159 struct _icalarray_sort_context {
160  icalarray *array;
161  int (*compare)(const void *, const void *);
162 };
163 
164 static 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 
173 static 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 
182 void 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 
195 static 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_new(size_t element_size, size_t increment_size)
Definition: icalarray.c:36
void icalarray_free(icalarray *array)
Definition: icalarray.c:104
Common memory management routines.
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
void icalmemory_free_buffer(void *buf)
Releases a buffer.
Definition: icalmemory.c:355
icalarray * icalarray_copy(const icalarray *originalarray)
Definition: icalarray.c:69
void icalerror_set_errno(icalerrorenum x)
Sets the icalerrno to a given error.
Definition: icalerror.c:90
void icalarray_append(icalarray *array, const void *element)
Appends an element to an array.
Definition: icalarray.c:119
void * icalmemory_new_buffer(size_t size)
Creates new buffer with the specified size.
Definition: icalmemory.c:315
void * icalarray_element_at(icalarray *array, size_t position)
Access an array element.
Definition: icalarray.c:135
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_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.