universe@103: /* universe@103: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. universe@103: * universe@334: * Copyright 2019 Mike Becker, Olaf Wintermann All rights reserved. universe@103: * universe@103: * Redistribution and use in source and binary forms, with or without universe@103: * modification, are permitted provided that the following conditions are met: universe@103: * universe@103: * 1. Redistributions of source code must retain the above copyright universe@103: * notice, this list of conditions and the following disclaimer. universe@103: * universe@103: * 2. Redistributions in binary form must reproduce the above copyright universe@103: * notice, this list of conditions and the following disclaimer in the universe@103: * documentation and/or other materials provided with the distribution. universe@103: * universe@103: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" universe@103: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE universe@103: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE universe@103: * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE universe@103: * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR universe@103: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF universe@103: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS universe@103: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN universe@103: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) universe@103: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE universe@103: * POSSIBILITY OF SUCH DAMAGE. universe@103: */ universe@103: universe@334: #include "ucx/array.h" universe@336: #include "ucx/utils.h" universe@4: universe@336: #include universe@334: universe@334: UcxArray ucx_array_new(size_t capacity, size_t elemsize) { universe@334: return ucx_array_new_a(capacity, elemsize, ucx_default_allocator()); universe@125: } universe@125: universe@334: UcxArray ucx_array_new_a(size_t capacity, size_t elemsize, universe@334: UcxAllocator* allocator) { universe@334: UcxArray array; universe@334: universe@336: array.allocator = allocator; universe@336: array.elemsize = elemsize; universe@336: array.size = 0; universe@336: array.data = alcalloc(allocator, capacity, elemsize); universe@336: universe@336: if (array.data) { universe@336: array.capacity = capacity; universe@336: } else { universe@336: array.capacity = 0; universe@336: } universe@336: universe@334: return array; universe@18: } universe@18: universe@334: UcxArray ucx_array_clone(UcxArray array) { universe@334: UcxArray clone; universe@18: universe@336: clone.allocator = array.allocator; universe@336: clone.elemsize = array.elemsize; universe@336: clone.size = array.size; universe@336: clone.data = alcalloc(array.allocator, array.capacity, array.elemsize); universe@336: universe@336: if (clone.data) { universe@336: clone.capacity = array.capacity; universe@336: memcpy(clone.data, array.data, array.size*array.elemsize); universe@336: } else { universe@336: clone.capacity = clone.size = 0; universe@336: } universe@336: universe@334: return clone; universe@18: } universe@18: universe@334: int ucx_array_equals(UcxArray array1, UcxArray array2, universe@334: cmp_func cmpfnc, void* data) { universe@334: universe@336: if (array1.size != array2.size || array1.elemsize != array2.elemsize) { universe@336: return 0; universe@336: } else { universe@336: if (array1.size == 0) universe@336: return 1; universe@336: universe@336: if (cmpfnc == NULL) { universe@336: cmpfnc = ucx_cmp_mem; universe@336: data = &array1.elemsize; universe@336: } universe@336: universe@336: for (size_t i = 0 ; i < array1.size ; i++) { universe@336: int r = cmpfnc( universe@336: ucx_array_at(array1, i), universe@336: ucx_array_at(array2, i), universe@336: data); universe@336: if (r != 0) universe@336: return 0; universe@336: } universe@336: return 1; universe@336: } universe@125: } universe@125: universe@334: void ucx_array_free(UcxArray *array) { universe@336: alfree(array->allocator, array->data); universe@336: array->data = NULL; universe@336: array->capacity = array->size = 0; universe@8: } universe@8: universe@334: int ucx_array_append(UcxArray *array, void *data) { universe@336: if (array->size == array->capacity) { universe@336: if (ucx_array_reserve(array, array->capacity*2)) { universe@336: return 1; universe@336: } universe@336: } universe@336: universe@336: void* dest = ucx_array_at(*array, array->size++); universe@336: if (data) { universe@336: memcpy(dest, data, array->elemsize); universe@336: } else { universe@336: memset(dest, 0, array->elemsize); universe@336: } universe@336: universe@336: return 0; universe@211: } universe@211: universe@334: int ucx_array_prepend(UcxArray *array, void *data) { universe@336: if (array->size == array->capacity) { universe@336: if (ucx_array_reserve(array, array->capacity*2)) { universe@336: return 1; universe@336: } universe@336: } universe@336: universe@336: array->size++; universe@336: universe@336: if (array->size > 1) { universe@336: void *dest = ucx_array_at(*array,1); universe@336: memmove(dest, array->data, array->elemsize*array->size); universe@336: } universe@336: universe@336: if (data) { universe@336: memcpy(array->data, data, array->elemsize); universe@336: } else { universe@336: memset(array->data, 0, array->elemsize); universe@336: } universe@336: universe@336: return 0; universe@125: } universe@125: universe@337: int ucx_array_set(UcxArray *array, size_t index, void *data) { universe@337: if (index >= array->size) { universe@337: if (ucx_array_reserve(array, index+1)) { universe@337: return 1; universe@337: } universe@337: array->size = index+1; universe@337: } universe@337: universe@337: void *dest = ucx_array_at(*array, index); universe@337: if (data) { universe@337: memcpy(dest, data, array->elemsize); universe@337: } else { universe@337: memset(dest, 0, array->elemsize); universe@337: } universe@337: universe@337: return 0; universe@337: } universe@337: universe@334: int ucx_array_concat(UcxArray *array1, const UcxArray *array2) { universe@336: universe@336: if (array1->elemsize != array2->elemsize) universe@336: return 1; universe@336: universe@336: size_t capacity = array1->capacity+array2->capacity; universe@336: universe@336: if (array1->capacity < capacity) { universe@336: if (ucx_array_reserve(array1, capacity)) { universe@336: return 1; universe@336: } universe@336: } universe@336: universe@336: void* dest = ucx_array_at(*array1, array1->size); universe@336: memcpy(dest, array2->data, array2->size*array2->elemsize); universe@336: universe@336: array1->size += array2->size; universe@336: universe@336: return 0; universe@7: } universe@7: universe@334: void *ucx_array_at(UcxArray array, size_t index) { universe@336: char* memory = array.data; universe@336: char* loc = memory + index*array.elemsize; universe@336: return loc; universe@125: } universe@125: universe@334: size_t ucx_array_find(UcxArray array, void *elem, cmp_func cmpfnc, void *data) { universe@7: universe@336: if (cmpfnc == NULL) { universe@336: cmpfnc = ucx_cmp_mem; universe@336: data = &array.elemsize; universe@336: } universe@336: universe@336: if (array.size > 0) { universe@336: for (size_t i = 0 ; i < array.size ; i++) { universe@336: void* ptr = ucx_array_at(array, i); universe@336: if (cmpfnc(ptr, elem, data) == 0) { universe@336: return i; universe@336: } universe@336: } universe@336: return array.size; universe@336: } else { universe@336: return 0; universe@336: } universe@7: } universe@7: universe@334: int ucx_array_contains(UcxArray array, void *elem, cmp_func cmpfnc, void *data) { universe@334: return ucx_array_find(array, elem, cmpfnc, data) != array.size; universe@7: } universe@7: universe@336: static void ucx_array_merge(UcxArray *array, cmp_func cmpfnc, void *data, universe@336: size_t start, size_t mid, size_t end) { universe@336: universe@336: size_t rightstart = mid + 1; universe@336: universe@336: if (cmpfnc(ucx_array_at(*array, mid), universe@336: ucx_array_at(*array, rightstart), data) <= 0) { universe@336: /* already sorted */ universe@336: return; universe@336: } universe@336: universe@336: // we need memory for one element universe@336: void *value = malloc(array->elemsize); universe@336: universe@336: while (start <= mid && rightstart <= end) { universe@336: if (cmpfnc(ucx_array_at(*array, start), universe@336: ucx_array_at(*array, rightstart), data) <= 0) { universe@336: start++; universe@336: } else { universe@336: // save the value from the right universe@336: memcpy(value, ucx_array_at(*array, rightstart), array->elemsize); universe@336: universe@336: // shift all left elements one element to the right universe@336: size_t shiftcount = rightstart-start; universe@336: void *startptr = ucx_array_at(*array, start); universe@336: void *dest = ucx_array_at(*array, start+1); universe@336: memmove(dest, startptr, shiftcount*array->elemsize); universe@336: universe@336: // bring the first value from the right to the left universe@336: memcpy(startptr, value, array->elemsize); universe@336: universe@336: start++; universe@336: mid++; universe@336: rightstart++; universe@336: } universe@336: } universe@336: universe@336: // free the temporary memory universe@336: free(value); universe@336: } universe@336: universe@336: static void ucx_array_mergesort(UcxArray *array, cmp_func cmpfnc, void *data, universe@336: size_t l, size_t r) { universe@336: if (l < r) { universe@336: size_t m = l + (r - l) / 2; universe@336: universe@336: ucx_array_mergesort(array, cmpfnc, data, l, m); universe@336: ucx_array_mergesort(array, cmpfnc, data, m + 1, r); universe@336: ucx_array_merge(array, cmpfnc, data, l, m, r); universe@336: } universe@336: } universe@336: universe@336: void ucx_array_sort(UcxArray array, cmp_func cmpfnc, void *data) { universe@336: ucx_array_mergesort(&array, cmpfnc, data, 0, array.size-1); universe@7: } universe@7: universe@334: void ucx_array_remove(UcxArray *array, size_t index) { universe@336: array->size--; universe@336: if (index < array->size) { universe@336: void* dest = ucx_array_at(*array, index); universe@336: void* src = ucx_array_at(*array, index+1); universe@336: memmove(dest, src, (array->size - index)*array->elemsize); universe@336: } universe@123: } universe@123: universe@334: void ucx_array_remove_fast(UcxArray *array, size_t index) { universe@336: array->size--; universe@336: if (index < array->size) { universe@336: void* dest = ucx_array_at(*array, index); universe@336: void* src = ucx_array_at(*array, array->size); universe@336: memcpy(dest, src, array->elemsize); universe@336: } universe@7: } universe@7: universe@334: int ucx_array_shrink(UcxArray* array) { universe@336: void* newptr = alrealloc(array->allocator, array->data, universe@336: array->size*array->elemsize); universe@336: if (newptr) { universe@336: array->data = newptr; universe@336: array->capacity = array->size; universe@336: return 0; universe@336: } else { universe@336: return 1; universe@336: } universe@123: } universe@123: universe@334: int ucx_array_resize(UcxArray* array, size_t capacity) { universe@336: if (array->capacity >= capacity) { universe@336: void* newptr = alrealloc(array->allocator, array->data, universe@336: capacity*array->elemsize); universe@336: if (newptr) { universe@336: array->data = newptr; universe@336: array->capacity = capacity; universe@336: if (array->size > array->capacity) { universe@336: array->size = array->capacity; universe@336: } universe@336: return 0; universe@336: } else { universe@336: return 1; universe@336: } universe@336: } else { universe@336: return ucx_array_reserve(array, capacity); universe@336: } universe@87: } universe@87: universe@334: int ucx_array_reserve(UcxArray* array, size_t capacity) { universe@336: if (array->capacity > capacity) { universe@336: return 0; universe@336: } else { universe@336: void* newptr = alrealloc(array->allocator, array->data, universe@336: capacity*array->elemsize); universe@336: if (newptr) { universe@336: array->data = newptr; universe@336: array->capacity = capacity; universe@336: return 0; universe@336: } else { universe@336: return 1; universe@336: } universe@336: } universe@7: }