Sat, 25 Feb 2023 11:38:33 +0100
update ldflags
436 | 1 | /* |
2 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. | |
3 | * | |
4 | * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. | |
5 | * | |
6 | * Redistribution and use in source and binary forms, with or without | |
7 | * modification, are permitted provided that the following conditions are met: | |
8 | * | |
9 | * 1. Redistributions of source code must retain the above copyright | |
10 | * notice, this list of conditions and the following disclaimer. | |
11 | * | |
12 | * 2. Redistributions in binary form must reproduce the above copyright | |
13 | * notice, this list of conditions and the following disclaimer in the | |
14 | * documentation and/or other materials provided with the distribution. | |
15 | * | |
16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
19 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | |
20 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
21 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
22 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
23 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
24 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
25 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
26 | * POSSIBILITY OF SUCH DAMAGE. | |
27 | */ | |
28 | ||
29 | #include "cx/array_list.h" | |
30 | #include <assert.h> | |
31 | #include <string.h> | |
32 | #include <stdint.h> | |
33 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
34 | // LOW LEVEL ARRAY LIST FUNCTIONS |
436 | 35 | |
36 | enum cx_array_copy_result cx_array_copy( | |
37 | void **target, | |
38 | size_t *size, | |
39 | size_t *capacity, | |
40 | size_t index, | |
41 | void const *src, | |
42 | size_t elem_size, | |
43 | size_t elem_count, | |
44 | struct cx_array_reallocator_s *reallocator | |
45 | ) { | |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
46 | // assert pointers |
436 | 47 | assert(target != NULL); |
48 | assert(size != NULL); | |
49 | assert(src != NULL); | |
50 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
51 | // determine capacity |
436 | 52 | size_t cap = capacity == NULL ? *size : *capacity; |
53 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
54 | // check if resize is required |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
55 | size_t minsize = index + elem_count; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
56 | size_t newsize = *size < minsize ? minsize : *size; |
436 | 57 | bool needrealloc = newsize > cap; |
58 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
59 | // reallocate if possible |
436 | 60 | if (needrealloc) { |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
61 | // a reallocator and a capacity variable must be available |
436 | 62 | if (reallocator == NULL || capacity == NULL) { |
63 | return CX_ARRAY_COPY_REALLOC_NOT_SUPPORTED; | |
64 | } | |
65 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
66 | // check, if we need to repair the src pointer |
436 | 67 | uintptr_t targetaddr = (uintptr_t) *target; |
68 | uintptr_t srcaddr = (uintptr_t) src; | |
69 | bool repairsrc = targetaddr <= srcaddr | |
70 | && srcaddr < targetaddr + cap * elem_size; | |
71 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
72 | // calculate new capacity (next number divisible by 16) |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
73 | cap = newsize - (newsize % 16) + 16; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
74 | assert(cap > newsize); |
436 | 75 | |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
76 | // perform reallocation |
436 | 77 | void *newmem = reallocator->realloc( |
78 | *target, cap, elem_size, reallocator | |
79 | ); | |
80 | if (newmem == NULL) { | |
81 | return CX_ARRAY_COPY_REALLOC_FAILED; | |
82 | } | |
83 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
84 | // repair src pointer, if necessary |
436 | 85 | if (repairsrc) { |
86 | src = ((char *) newmem) + (srcaddr - targetaddr); | |
87 | } | |
88 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
89 | // store new pointer and capacity |
436 | 90 | *target = newmem; |
91 | *capacity = cap; | |
92 | } | |
93 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
94 | // determine target pointer |
436 | 95 | char *start = *target; |
96 | start += index * elem_size; | |
97 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
98 | // copy elements and set new size |
436 | 99 | memmove(start, src, elem_count * elem_size); |
100 | *size = newsize; | |
101 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
102 | // return successfully |
436 | 103 | return CX_ARRAY_COPY_SUCCESS; |
104 | } | |
105 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
106 | #define CX_ARRAY_SWAP_SBO_SIZE 512 |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
107 | |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
108 | void cx_array_swap( |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
109 | void *arr, |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
110 | size_t elem_size, |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
111 | size_t idx1, |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
112 | size_t idx2 |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
113 | ) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
114 | // short circuit |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
115 | if (idx1 == idx2) return; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
116 | |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
117 | char sbo_mem[CX_ARRAY_SWAP_SBO_SIZE]; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
118 | void *tmp; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
119 | |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
120 | // decide if we can use the local buffer |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
121 | if (elem_size > CX_ARRAY_SWAP_SBO_SIZE) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
122 | tmp = malloc(elem_size); |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
123 | // we don't want to enforce error handling |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
124 | if (tmp == NULL) abort(); |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
125 | } else { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
126 | tmp = sbo_mem; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
127 | } |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
128 | |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
129 | // calculate memory locations |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
130 | char *left = arr, *right = arr; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
131 | left += idx1 * elem_size; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
132 | right += idx2 * elem_size; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
133 | |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
134 | // three-way swap |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
135 | memcpy(tmp, left, elem_size); |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
136 | memcpy(left, right, elem_size); |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
137 | memcpy(right, tmp, elem_size); |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
138 | |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
139 | // free dynamic memory, if it was needed |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
140 | if (tmp != sbo_mem) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
141 | free(tmp); |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
142 | } |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
143 | } |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
144 | |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
145 | // HIGH LEVEL ARRAY LIST FUNCTIONS |
436 | 146 | |
147 | typedef struct { | |
148 | struct cx_list_s base; | |
149 | void *data; | |
150 | struct cx_array_reallocator_s reallocator; | |
151 | } cx_array_list; | |
152 | ||
153 | static void *cx_arl_realloc( | |
154 | void *array, | |
155 | size_t capacity, | |
156 | size_t elem_size, | |
157 | struct cx_array_reallocator_s *alloc | |
158 | ) { | |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
159 | // retrieve the pointer to the list allocator |
436 | 160 | CxAllocator const *al = alloc->ptr1; |
161 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
162 | // use the list allocator to reallocate the memory |
436 | 163 | return cxRealloc(al, array, capacity * elem_size); |
164 | } | |
165 | ||
166 | static void cx_arl_destructor(struct cx_list_s *list) { | |
167 | cx_array_list *arl = (cx_array_list *) list; | |
168 | cxFree(list->allocator, arl->data); | |
169 | } | |
170 | ||
171 | static int cx_arl_add( | |
172 | struct cx_list_s *list, | |
173 | void const *elem | |
174 | ) { | |
175 | cx_array_list *arl = (cx_array_list *) list; | |
176 | return cx_array_copy( | |
177 | &arl->data, | |
178 | &list->size, | |
179 | &list->capacity, | |
180 | list->size, | |
181 | elem, | |
182 | list->itemsize, | |
183 | 1, | |
184 | &arl->reallocator | |
185 | ); | |
186 | } | |
187 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
188 | static size_t cx_arl_add_array( |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
189 | struct cx_list_s *list, |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
190 | void const *array, |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
191 | size_t n |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
192 | ) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
193 | cx_array_list *arl = (cx_array_list *) list; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
194 | if (CX_ARRAY_COPY_SUCCESS == cx_array_copy( |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
195 | &arl->data, |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
196 | &list->size, |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
197 | &list->capacity, |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
198 | list->size, |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
199 | array, |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
200 | list->itemsize, |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
201 | n, |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
202 | &arl->reallocator |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
203 | )) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
204 | return n; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
205 | } else { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
206 | // array list implementation is "all or nothing" |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
207 | return 0; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
208 | } |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
209 | } |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
210 | |
436 | 211 | static int cx_arl_insert( |
212 | struct cx_list_s *list, | |
213 | size_t index, | |
214 | void const *elem | |
215 | ) { | |
216 | if (index > list->size) { | |
217 | return 1; | |
218 | } else if (index == list->size) { | |
219 | return cx_arl_add(list, elem); | |
220 | } else { | |
221 | cx_array_list *arl = (cx_array_list *) list; | |
222 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
223 | // move elements starting at index to the right |
436 | 224 | if (cx_array_copy( |
225 | &arl->data, | |
226 | &list->size, | |
227 | &list->capacity, | |
228 | index + 1, | |
229 | ((char *) arl->data) + index * list->itemsize, | |
230 | list->itemsize, | |
231 | list->size - index, | |
232 | &arl->reallocator | |
233 | )) { | |
234 | return 1; | |
235 | } | |
236 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
237 | // place the element |
436 | 238 | memcpy(((char *) arl->data) + index * list->itemsize, |
239 | elem, list->itemsize); | |
240 | ||
241 | return 0; | |
242 | } | |
243 | } | |
244 | ||
245 | static int cx_arl_insert_iter( | |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
246 | struct cx_mut_iterator_s *iter, |
436 | 247 | void const *elem, |
248 | int prepend | |
249 | ) { | |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
250 | struct cx_list_s *list = iter->src_handle; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
251 | if (iter->index < list->size) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
252 | int result = cx_arl_insert( |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
253 | list, |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
254 | iter->index + 1 - prepend, |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
255 | elem |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
256 | ); |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
257 | if (result == 0 && prepend != 0) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
258 | iter->index++; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
259 | iter->elem_handle = ((char *) iter->elem_handle) + list->itemsize; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
260 | } |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
261 | return result; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
262 | } else { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
263 | int result = cx_arl_add(list, elem); |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
264 | iter->index = list->size; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
265 | return result; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
266 | } |
436 | 267 | } |
268 | ||
269 | static int cx_arl_remove( | |
270 | struct cx_list_s *list, | |
271 | size_t index | |
272 | ) { | |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
273 | // out-of-bounds check |
436 | 274 | if (index >= list->size) { |
275 | return 1; | |
276 | } | |
277 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
278 | // short-circuit removal of last element |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
279 | if (index == list->size - 1) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
280 | list->size--; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
281 | return 0; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
282 | } |
436 | 283 | |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
284 | // just move the elements starting at index to the left |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
285 | cx_array_list *arl = (cx_array_list *) list; |
436 | 286 | int result = cx_array_copy( |
287 | &arl->data, | |
288 | &list->size, | |
289 | &list->capacity, | |
290 | index, | |
291 | ((char *) arl->data) + (index + 1) * list->itemsize, | |
292 | list->itemsize, | |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
293 | list->size - index - 1, |
436 | 294 | &arl->reallocator |
295 | ); | |
296 | if (result == 0) { | |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
297 | // decrease the size |
436 | 298 | list->size--; |
299 | } | |
300 | return result; | |
301 | } | |
302 | ||
303 | static void *cx_arl_at( | |
304 | struct cx_list_s const *list, | |
305 | size_t index | |
306 | ) { | |
307 | if (index < list->size) { | |
308 | cx_array_list const *arl = (cx_array_list const *) list; | |
309 | char *space = arl->data; | |
310 | return space + index * list->itemsize; | |
311 | } else { | |
312 | return NULL; | |
313 | } | |
314 | } | |
315 | ||
316 | static size_t cx_arl_find( | |
317 | struct cx_list_s const *list, | |
318 | void const *elem | |
319 | ) { | |
320 | char *cur = ((cx_array_list const *) list)->data; | |
321 | ||
322 | for (size_t i = 0; i < list->size; i++) { | |
323 | if (0 == list->cmpfunc(elem, cur)) { | |
324 | return i; | |
325 | } | |
326 | cur += list->itemsize; | |
327 | } | |
328 | ||
329 | return list->size; | |
330 | } | |
331 | ||
332 | static void cx_arl_sort(struct cx_list_s *list) { | |
333 | qsort(((cx_array_list *) list)->data, | |
334 | list->size, | |
335 | list->itemsize, | |
336 | list->cmpfunc | |
337 | ); | |
338 | } | |
339 | ||
340 | static int cx_arl_compare( | |
341 | struct cx_list_s const *list, | |
342 | struct cx_list_s const *other | |
343 | ) { | |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
344 | if (list->size == other->size) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
345 | char const *left = ((cx_array_list const *) list)->data; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
346 | char const *right = ((cx_array_list const *) other)->data; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
347 | for (size_t i = 0; i < list->size; i++) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
348 | int d = list->cmpfunc(left, right); |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
349 | if (d != 0) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
350 | return d; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
351 | } |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
352 | left += list->itemsize; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
353 | right += other->itemsize; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
354 | } |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
355 | return 0; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
356 | } else { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
357 | return list->size < other->size ? -1 : 1; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
358 | } |
436 | 359 | } |
360 | ||
361 | static void cx_arl_reverse(struct cx_list_s *list) { | |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
362 | if (list->size < 2) return; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
363 | void *data = ((cx_array_list const *) list)->data; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
364 | size_t half = list->size / 2; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
365 | for (size_t i = 0; i < half; i++) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
366 | cx_array_swap(data, list->itemsize, i, list->size - 1 - i); |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
367 | } |
436 | 368 | } |
369 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
370 | static bool cx_arl_iter_valid(void const *it) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
371 | struct cx_iterator_s const *iter = it; |
436 | 372 | struct cx_list_s const *list = iter->src_handle; |
373 | return iter->index < list->size; | |
374 | } | |
375 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
376 | static void *cx_arl_iter_current(void const *it) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
377 | struct cx_iterator_s const *iter = it; |
436 | 378 | return iter->elem_handle; |
379 | } | |
380 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
381 | static void cx_arl_iter_next(void *it) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
382 | struct cx_iterator_base_s *itbase = it; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
383 | if (itbase->remove) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
384 | struct cx_mut_iterator_s *iter = it; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
385 | itbase->remove = false; |
436 | 386 | cx_arl_remove(iter->src_handle, iter->index); |
387 | } else { | |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
388 | struct cx_iterator_s *iter = it; |
436 | 389 | iter->index++; |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
390 | iter->elem_handle = |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
391 | ((char *) iter->elem_handle) |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
392 | + ((struct cx_list_s const *) iter->src_handle)->itemsize; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
393 | } |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
394 | } |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
395 | |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
396 | static bool cx_arl_iter_flag_rm(void *it) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
397 | struct cx_iterator_base_s *iter = it; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
398 | if (iter->mutating) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
399 | iter->remove = true; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
400 | return true; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
401 | } else { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
402 | return false; |
436 | 403 | } |
404 | } | |
405 | ||
406 | static struct cx_iterator_s cx_arl_iterator( | |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
407 | struct cx_list_s const *list, |
436 | 408 | size_t index |
409 | ) { | |
410 | struct cx_iterator_s iter; | |
411 | ||
412 | iter.index = index; | |
413 | iter.src_handle = list; | |
414 | iter.elem_handle = cx_arl_at(list, index); | |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
415 | iter.base.valid = cx_arl_iter_valid; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
416 | iter.base.current = cx_arl_iter_current; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
417 | iter.base.next = cx_arl_iter_next; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
418 | iter.base.flag_removal = cx_arl_iter_flag_rm; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
419 | iter.base.remove = false; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
420 | iter.base.mutating = false; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
421 | |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
422 | return iter; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
423 | } |
436 | 424 | |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
425 | static struct cx_mut_iterator_s cx_arl_mut_iterator( |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
426 | struct cx_list_s *list, |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
427 | size_t index |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
428 | ) { |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
429 | CxIterator it = cx_arl_iterator(list, index); |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
430 | it.base.mutating = true; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
431 | |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
432 | // we know the iterators share the same memory layout |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
433 | CxMutIterator iter; |
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
434 | memcpy(&iter, &it, sizeof(CxMutIterator)); |
436 | 435 | return iter; |
436 | } | |
437 | ||
438 | static cx_list_class cx_array_list_class = { | |
439 | cx_arl_destructor, | |
440 | cx_arl_add, | |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
441 | cx_arl_add_array, |
436 | 442 | cx_arl_insert, |
443 | cx_arl_insert_iter, | |
444 | cx_arl_remove, | |
445 | cx_arl_at, | |
446 | cx_arl_find, | |
447 | cx_arl_sort, | |
448 | cx_arl_compare, | |
449 | cx_arl_reverse, | |
450 | cx_arl_iterator, | |
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
451 | cx_arl_mut_iterator, |
436 | 452 | }; |
453 | ||
454 | CxList *cxArrayListCreate( | |
455 | CxAllocator const *allocator, | |
456 | CxListComparator comparator, | |
457 | size_t item_size, | |
458 | size_t initial_capacity | |
459 | ) { | |
460 | cx_array_list *list = cxCalloc(allocator, 1, sizeof(cx_array_list)); | |
461 | if (list == NULL) return NULL; | |
462 | ||
463 | list->data = cxCalloc(allocator, initial_capacity, item_size); | |
464 | if (list->data == NULL) { | |
465 | cxFree(allocator, list); | |
466 | return NULL; | |
467 | } | |
468 | ||
469 | list->base.cl = &cx_array_list_class; | |
470 | list->base.allocator = allocator; | |
471 | list->base.cmpfunc = comparator; | |
472 | list->base.itemsize = item_size; | |
473 | list->base.capacity = initial_capacity; | |
474 | ||
438
22eca559aded
refactore http listener creation
Olaf Wintermann <olaf.wintermann@gmail.com>
parents:
436
diff
changeset
|
475 | // configure the reallocator |
436 | 476 | list->reallocator.realloc = cx_arl_realloc; |
477 | list->reallocator.ptr1 = (void *) allocator; | |
478 | ||
479 | return (CxList *) list; | |
480 | } |