src/array_list.c

Thu, 17 Nov 2022 18:55:14 +0100

author
Mike Becker <universe@uap-core.de>
date
Thu, 17 Nov 2022 18:55:14 +0100
changeset 615
b52b66dcd44b
parent 614
7aaec630cf15
child 616
af7d8a29fbc5
permissions
-rw-r--r--

#219 array list: implement sort

universe@606 1 /*
universe@606 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
universe@606 3 *
universe@606 4 * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
universe@606 5 *
universe@606 6 * Redistribution and use in source and binary forms, with or without
universe@606 7 * modification, are permitted provided that the following conditions are met:
universe@606 8 *
universe@606 9 * 1. Redistributions of source code must retain the above copyright
universe@606 10 * notice, this list of conditions and the following disclaimer.
universe@606 11 *
universe@606 12 * 2. Redistributions in binary form must reproduce the above copyright
universe@606 13 * notice, this list of conditions and the following disclaimer in the
universe@606 14 * documentation and/or other materials provided with the distribution.
universe@606 15 *
universe@606 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
universe@606 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
universe@606 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
universe@606 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
universe@606 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
universe@606 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
universe@606 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
universe@606 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
universe@606 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
universe@606 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
universe@606 26 * POSSIBILITY OF SUCH DAMAGE.
universe@606 27 */
universe@606 28
universe@606 29 #include "cx/array_list.h"
universe@610 30 #include <assert.h>
universe@610 31 #include <string.h>
universe@611 32 #include <stdint.h>
universe@606 33
universe@607 34 /* LOW LEVEL ARRAY LIST FUNCTIONS */
universe@607 35
universe@612 36 enum cx_array_copy_result cx_array_copy(
universe@610 37 void **target,
universe@610 38 size_t *size,
universe@610 39 size_t *capacity,
universe@610 40 size_t index,
universe@610 41 void const *src,
universe@610 42 size_t elem_size,
universe@610 43 size_t elem_count,
universe@610 44 struct cx_array_reallocator_s *reallocator
universe@610 45 ) {
universe@610 46 /* assert pointers */
universe@610 47 assert(target != NULL);
universe@610 48 assert(size != NULL);
universe@610 49 assert(src != NULL);
universe@607 50
universe@610 51 /* determine capacity */
universe@610 52 size_t cap = capacity == NULL ? *size : *capacity;
universe@610 53
universe@610 54 /* check if resize is required */
universe@610 55 size_t newsize = index + elem_count;
universe@610 56 bool needrealloc = newsize > cap;
universe@610 57
universe@610 58 /* reallocate if possible */
universe@610 59 if (needrealloc) {
universe@610 60 /* a reallocator and a capacity variable must be available */
universe@610 61 if (reallocator == NULL || capacity == NULL) {
universe@610 62 return CX_ARRAY_COPY_REALLOC_NOT_SUPPORTED;
universe@610 63 }
universe@610 64
universe@611 65 /* check, if we need to repair the src pointer */
universe@611 66 uintptr_t targetaddr = (uintptr_t) *target;
universe@611 67 uintptr_t srcaddr = (uintptr_t) src;
universe@611 68 bool repairsrc = targetaddr <= srcaddr
universe@611 69 && srcaddr < targetaddr + cap * elem_size;
universe@611 70
universe@610 71 /* increase capacity linearly */
universe@610 72 cap += 16;
universe@610 73
universe@610 74 /* perform reallocation */
universe@610 75 void *newmem = reallocator->realloc(
universe@610 76 *target, cap, elem_size, reallocator
universe@610 77 );
universe@610 78 if (newmem == NULL) {
universe@610 79 return CX_ARRAY_COPY_REALLOC_FAILED;
universe@610 80 }
universe@610 81
universe@611 82 /* repair src pointer, if necessary */
universe@611 83 if (repairsrc) {
universe@611 84 src = ((char *) newmem) + (srcaddr - targetaddr);
universe@611 85 }
universe@611 86
universe@610 87 /* store new pointer and capacity */
universe@610 88 *target = newmem;
universe@610 89 *capacity = cap;
universe@610 90 }
universe@610 91
universe@610 92 /* determine target pointer */
universe@610 93 char *start = *target;
universe@610 94 start += index * elem_size;
universe@610 95
universe@610 96 /* copy elements and set new size */
universe@611 97 memmove(start, src, elem_count * elem_size);
universe@610 98 *size = newsize;
universe@610 99
universe@610 100 /* return successfully */
universe@610 101 return CX_ARRAY_COPY_SUCCESS;
universe@610 102 }
universe@607 103
universe@607 104 /* HIGH LEVEL ARRAY LIST FUNCTIONS */
universe@607 105
universe@607 106 typedef struct {
universe@607 107 struct cx_list_s base;
universe@607 108 void *data;
universe@610 109 struct cx_array_reallocator_s reallocator;
universe@607 110 } cx_array_list;
universe@607 111
universe@610 112 static void *cx_arl_realloc(
universe@610 113 void *array,
universe@610 114 size_t capacity,
universe@610 115 size_t elem_size,
universe@610 116 struct cx_array_reallocator_s *alloc
universe@610 117 ) {
universe@610 118 /* retrieve the pointer to the list allocator */
universe@610 119 CxAllocator const *al = alloc->ptr1;
universe@610 120
universe@610 121 /* use the list allocator to reallocate the memory */
universe@610 122 return cxRealloc(al, array, capacity * elem_size);
universe@610 123 }
universe@610 124
universe@607 125 static void cx_arl_destructor(struct cx_list_s *list) {
universe@610 126 cx_array_list *arl = (cx_array_list *) list;
universe@607 127 cxFree(list->allocator, arl->data);
universe@607 128 }
universe@607 129
universe@607 130 static int cx_arl_add(
universe@607 131 struct cx_list_s *list,
universe@607 132 void const *elem
universe@607 133 ) {
universe@610 134 cx_array_list *arl = (cx_array_list *) list;
universe@610 135 return cx_array_copy(
universe@610 136 &arl->data,
universe@610 137 &list->size,
universe@610 138 &list->capacity,
universe@610 139 list->size,
universe@610 140 elem,
universe@610 141 list->itemsize,
universe@610 142 1,
universe@610 143 &arl->reallocator
universe@610 144 );
universe@607 145 }
universe@607 146
universe@607 147 static int cx_arl_insert(
universe@607 148 struct cx_list_s *list,
universe@607 149 size_t index,
universe@607 150 void const *elem
universe@607 151 ) {
universe@611 152 if (index > list->size) {
universe@611 153 return 1;
universe@611 154 } else if (index == list->size) {
universe@611 155 return cx_arl_add(list, elem);
universe@611 156 } else {
universe@611 157 cx_array_list *arl = (cx_array_list *) list;
universe@611 158
universe@611 159 /* move elements starting at index to the right */
universe@611 160 if (cx_array_copy(
universe@611 161 &arl->data,
universe@611 162 &list->size,
universe@611 163 &list->capacity,
universe@611 164 index + 1,
universe@611 165 ((char *) arl->data) + index * list->itemsize,
universe@611 166 list->itemsize,
universe@611 167 list->size - index,
universe@611 168 &arl->reallocator
universe@611 169 )) {
universe@611 170 return 1;
universe@611 171 }
universe@611 172
universe@611 173 /* place the element */
universe@611 174 memcpy(((char *) arl->data) + index * list->itemsize,
universe@611 175 elem, list->itemsize);
universe@611 176
universe@611 177 return 0;
universe@611 178 }
universe@607 179 }
universe@607 180
universe@607 181 static int cx_arl_insert_iter(
universe@607 182 struct cx_iterator_s *iter,
universe@607 183 void const *elem,
universe@607 184 int prepend
universe@607 185 ) {
universe@607 186 return 1;
universe@607 187 }
universe@607 188
universe@607 189 static int cx_arl_remove(
universe@607 190 struct cx_list_s *list,
universe@607 191 size_t index
universe@607 192 ) {
universe@613 193 /* out-of-bounds check */
universe@613 194 if (index >= list->size) {
universe@613 195 return 1;
universe@613 196 }
universe@613 197
universe@613 198 cx_array_list *arl = (cx_array_list *) list;
universe@613 199
universe@613 200 /* just move the elements starting at index to the left */
universe@613 201 int result = cx_array_copy(
universe@613 202 &arl->data,
universe@613 203 &list->size,
universe@613 204 &list->capacity,
universe@613 205 index,
universe@613 206 ((char *) arl->data) + (index + 1) * list->itemsize,
universe@613 207 list->itemsize,
universe@613 208 list->size - index,
universe@613 209 &arl->reallocator
universe@613 210 );
universe@613 211 if (result == 0) {
universe@613 212 /* decrease the size */
universe@613 213 list->size--;
universe@613 214 }
universe@613 215 return result;
universe@607 216 }
universe@607 217
universe@610 218 static void *cx_arl_at(
universe@607 219 struct cx_list_s const *list,
universe@607 220 size_t index
universe@607 221 ) {
universe@610 222 if (index < list->size) {
universe@610 223 cx_array_list const *arl = (cx_array_list const *) list;
universe@610 224 char *space = arl->data;
universe@610 225 return space + index * list->itemsize;
universe@610 226 } else {
universe@610 227 return NULL;
universe@610 228 }
universe@607 229 }
universe@607 230
universe@607 231 static size_t cx_arl_find(
universe@607 232 struct cx_list_s const *list,
universe@607 233 void const *elem
universe@607 234 ) {
universe@614 235 char *cur = ((cx_array_list const *) list)->data;
universe@614 236
universe@614 237 for (size_t i = 0; i < list->size; i++) {
universe@614 238 if (0 == list->cmpfunc(elem, cur)) {
universe@614 239 return i;
universe@614 240 }
universe@614 241 cur += list->itemsize;
universe@614 242 }
universe@614 243
universe@614 244 return list->size;
universe@607 245 }
universe@607 246
universe@607 247 static void cx_arl_sort(struct cx_list_s *list) {
universe@615 248 qsort(((cx_array_list *) list)->data,
universe@615 249 list->size,
universe@615 250 list->itemsize,
universe@615 251 list->cmpfunc
universe@615 252 );
universe@607 253 }
universe@607 254
universe@607 255 static int cx_arl_compare(
universe@607 256 struct cx_list_s const *list,
universe@607 257 struct cx_list_s const *other
universe@607 258 ) {
universe@607 259
universe@607 260 }
universe@607 261
universe@607 262 static void cx_arl_reverse(struct cx_list_s *list) {
universe@607 263
universe@607 264 }
universe@607 265
universe@607 266 static struct cx_iterator_s cx_arl_iterator(
universe@607 267 struct cx_list_s *list,
universe@607 268 size_t index
universe@607 269 ) {
universe@607 270 struct cx_iterator_s iter;
universe@607 271
universe@607 272 return iter;
universe@607 273 }
universe@607 274
universe@607 275 static cx_list_class cx_array_list_class = {
universe@607 276 cx_arl_destructor,
universe@607 277 cx_arl_add,
universe@607 278 cx_arl_insert,
universe@607 279 cx_arl_insert_iter,
universe@607 280 cx_arl_remove,
universe@607 281 cx_arl_at,
universe@607 282 cx_arl_find,
universe@607 283 cx_arl_sort,
universe@607 284 cx_arl_compare,
universe@607 285 cx_arl_reverse,
universe@607 286 cx_arl_iterator,
universe@607 287 };
universe@607 288
universe@606 289 CxList *cxArrayListCreate(
universe@606 290 CxAllocator const *allocator,
universe@606 291 CxListComparator comparator,
universe@606 292 size_t item_size,
universe@606 293 size_t initial_capacity
universe@606 294 ) {
universe@607 295 cx_array_list *list = cxCalloc(allocator, 1, sizeof(cx_array_list));
universe@607 296 if (list == NULL) return NULL;
universe@607 297
universe@607 298 list->data = cxCalloc(allocator, initial_capacity, item_size);
universe@607 299 if (list->data == NULL) {
universe@607 300 cxFree(allocator, list);
universe@607 301 return NULL;
universe@607 302 }
universe@607 303
universe@607 304 list->base.cl = &cx_array_list_class;
universe@607 305 list->base.allocator = allocator;
universe@607 306 list->base.cmpfunc = comparator;
universe@607 307 list->base.itemsize = item_size;
universe@607 308 list->base.capacity = initial_capacity;
universe@607 309
universe@610 310 /* configure the reallocator */
universe@610 311 list->reallocator.realloc = cx_arl_realloc;
universe@610 312 list->reallocator.ptr1 = (void *) allocator;
universe@610 313
universe@607 314 return (CxList *) list;
universe@606 315 }

mercurial