src/array.c

changeset 390
d345541018fa
parent 389
92e482410453
child 391
f094a53c1178
     1.1 --- a/src/array.c	Mon Dec 30 09:54:10 2019 +0100
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,467 +0,0 @@
     1.4 -/*
     1.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     1.6 - *
     1.7 - * Copyright 2019 Mike Becker, Olaf Wintermann All rights reserved.
     1.8 - *
     1.9 - * Redistribution and use in source and binary forms, with or without
    1.10 - * modification, are permitted provided that the following conditions are met:
    1.11 - *
    1.12 - *   1. Redistributions of source code must retain the above copyright
    1.13 - *      notice, this list of conditions and the following disclaimer.
    1.14 - *
    1.15 - *   2. Redistributions in binary form must reproduce the above copyright
    1.16 - *      notice, this list of conditions and the following disclaimer in the
    1.17 - *      documentation and/or other materials provided with the distribution.
    1.18 - *
    1.19 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    1.20 - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    1.21 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    1.22 - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    1.23 - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    1.24 - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    1.25 - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    1.26 - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    1.27 - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    1.28 - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    1.29 - * POSSIBILITY OF SUCH DAMAGE.
    1.30 - */
    1.31 -
    1.32 -#define _GNU_SOURCE /* we want to use qsort_r(), if available */
    1.33 -#define __STDC_WANT_LIB_EXT1__ 1 /* use qsort_s, if available */
    1.34 -
    1.35 -
    1.36 -#include "ucx/array.h"
    1.37 -#include "ucx/utils.h"
    1.38 -
    1.39 -#include <string.h>
    1.40 -#include <stdlib.h>
    1.41 -#include <errno.h>
    1.42 -
    1.43 -#ifndef UCX_ARRAY_DISABLE_QSORT
    1.44 -#ifdef __GLIBC__
    1.45 -#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
    1.46 -#define ucx_array_sort_impl qsort_r
    1.47 -#endif /* glibc version >= 2.8 */
    1.48 -#elif /* not  __GLIBC__ */ defined(__APPLE__) || defined(__FreeBSD__)
    1.49 -#define ucx_array_sort_impl ucx_qsort_r
    1.50 -#define USE_UCX_QSORT_R
    1.51 -#elif /* not (__APPLE || __FreeBSD__) */ defined(__sun)
    1.52 -#if __STDC_VERSION__ >= 201112L
    1.53 -#define ucx_array_sort_impl qsort_s
    1.54 -#endif
    1.55 -#endif /* __GLIBC__, __APLE__, __FreeBSD__, __sun */
    1.56 -#endif /* UCX_ARRAY_DISABLE_QSORT */
    1.57 -
    1.58 -#ifndef ucx_array_sort_impl
    1.59 -#define ucx_array_sort_impl ucx_mergesort
    1.60 -#endif
    1.61 -
    1.62 -static int ucx_array_ensurecap(UcxArray *array, size_t reqcap) {
    1.63 -    size_t required_capacity = array->capacity;
    1.64 -    while (reqcap > required_capacity) {
    1.65 -        if (required_capacity * 2 < required_capacity)
    1.66 -            return 1;
    1.67 -        required_capacity <<= 1;
    1.68 -    }
    1.69 -    if (ucx_array_reserve(array, required_capacity)) {
    1.70 -        return 1;
    1.71 -    }
    1.72 -    return 0;
    1.73 -}
    1.74 -
    1.75 -int ucx_array_util_set_a(UcxAllocator* alloc, void** array, size_t* capacity,
    1.76 -    size_t elmsize, size_t index, void* data) {
    1.77 -    
    1.78 -    if(!alloc || !capacity || !array) {
    1.79 -        errno = EINVAL;
    1.80 -        return 1;
    1.81 -    }
    1.82 -    
    1.83 -    size_t newcapacity = *capacity;
    1.84 -    while(index >= newcapacity) {
    1.85 -        if(ucx_szmul(newcapacity, 2, &newcapacity)) {
    1.86 -            errno = EOVERFLOW;
    1.87 -            return 1;
    1.88 -        }        
    1.89 -    }
    1.90 -
    1.91 -    size_t memlen, offset;
    1.92 -    if(ucx_szmul(newcapacity, elmsize, &memlen)) {
    1.93 -        errno = EOVERFLOW;
    1.94 -        return 1;
    1.95 -    }
    1.96 -    /* we don't need to check index*elmsize - it is smaller than memlen */
    1.97 -    
    1.98 -    
    1.99 -    void* newptr = alrealloc(alloc, *array, memlen);
   1.100 -    if(newptr == NULL) {
   1.101 -        errno = ENOMEM; /* we cannot assume that every allocator sets this */
   1.102 -        return 1;
   1.103 -    }
   1.104 -    *array = newptr;
   1.105 -    *capacity = newcapacity;
   1.106 -    
   1.107 -    
   1.108 -    char* dest = *array;
   1.109 -    dest += elmsize*index;
   1.110 -    memcpy(dest, data, elmsize);
   1.111 -    
   1.112 -    return 0;
   1.113 -}
   1.114 -
   1.115 -int ucx_array_util_setptr_a(UcxAllocator* alloc, void** array, size_t* capacity,
   1.116 -    size_t index, void* data) {
   1.117 -    
   1.118 -    return ucx_array_util_set_a(alloc, array, capacity, sizeof(void*),
   1.119 -            index, &data);
   1.120 -}
   1.121 -
   1.122 -UcxArray* ucx_array_new(size_t capacity, size_t elemsize) {
   1.123 -    return ucx_array_new_a(capacity, elemsize, ucx_default_allocator());
   1.124 -}
   1.125 -
   1.126 -UcxArray* ucx_array_new_a(size_t capacity, size_t elemsize,
   1.127 -        UcxAllocator* allocator) {
   1.128 -    UcxArray* array = almalloc(allocator, sizeof(UcxArray));
   1.129 -    if(array) {
   1.130 -        ucx_array_init_a(array, capacity, elemsize, allocator);
   1.131 -    }
   1.132 -    return array;
   1.133 -}
   1.134 -
   1.135 -void ucx_array_init(UcxArray* array, size_t capacity, size_t elemsize) {
   1.136 -    ucx_array_init_a(array, capacity, elemsize, ucx_default_allocator());
   1.137 -}
   1.138 -
   1.139 -void ucx_array_init_a(UcxArray* array, size_t capacity, size_t elemsize,
   1.140 -        UcxAllocator* allocator) {
   1.141 -    
   1.142 -    array->allocator = allocator;
   1.143 -    array->elemsize = elemsize;
   1.144 -    array->size = 0;
   1.145 -    array->data = alcalloc(allocator, capacity, elemsize);
   1.146 -    
   1.147 -    if (array->data) {
   1.148 -        array->capacity = capacity;
   1.149 -    } else {
   1.150 -        array->capacity = 0;
   1.151 -    }
   1.152 -}
   1.153 -
   1.154 -int ucx_array_clone(UcxArray* dest, UcxArray const* src) {
   1.155 -    if (ucx_array_ensurecap(dest, src->capacity)) {
   1.156 -        return 1;
   1.157 -    }
   1.158 -    
   1.159 -    dest->elemsize = src->elemsize;
   1.160 -    dest->size = src->size;
   1.161 -    
   1.162 -    if (dest->data) {
   1.163 -        memcpy(dest->data, src->data, src->size*src->elemsize);
   1.164 -    }
   1.165 -    
   1.166 -    return 0;
   1.167 -}
   1.168 -
   1.169 -int ucx_array_equals(UcxArray const *array1, UcxArray const *array2,
   1.170 -        cmp_func cmpfnc, void* data) {
   1.171 -    
   1.172 -    if (array1->size != array2->size || array1->elemsize != array2->elemsize) {
   1.173 -        return 0;
   1.174 -    } else {
   1.175 -        if (array1->size == 0)
   1.176 -            return 1;
   1.177 -        
   1.178 -        size_t elemsize;
   1.179 -        if (cmpfnc == NULL) {
   1.180 -            cmpfnc = ucx_cmp_mem;
   1.181 -            elemsize = array1->elemsize;
   1.182 -            data = &elemsize;
   1.183 -        }
   1.184 -        
   1.185 -        for (size_t i = 0 ; i < array1->size ; i++) {
   1.186 -            int r = cmpfnc(
   1.187 -                    ucx_array_at(array1, i),
   1.188 -                    ucx_array_at(array2, i),
   1.189 -                    data);
   1.190 -            if (r != 0)
   1.191 -                return 0;
   1.192 -        }
   1.193 -        return 1;
   1.194 -    }
   1.195 -}
   1.196 -
   1.197 -void ucx_array_destroy(UcxArray *array) {
   1.198 -    if(array->data)
   1.199 -        alfree(array->allocator, array->data);
   1.200 -    array->data = NULL;
   1.201 -    array->capacity = array->size = 0;
   1.202 -}
   1.203 -
   1.204 -void ucx_array_free(UcxArray *array) {
   1.205 -    ucx_array_destroy(array);
   1.206 -    alfree(array->allocator, array);
   1.207 -}
   1.208 -
   1.209 -int ucx_array_append_from(UcxArray *array, void *data, size_t count) {
   1.210 -    if (ucx_array_ensurecap(array, array->size + count))
   1.211 -        return 1;
   1.212 -    
   1.213 -    void* dest = ucx_array_at(array, array->size);
   1.214 -    if (data) {
   1.215 -        memcpy(dest, data, array->elemsize*count);
   1.216 -    } else {
   1.217 -        memset(dest, 0, array->elemsize*count);
   1.218 -    }
   1.219 -    array->size += count;
   1.220 -    
   1.221 -    return 0;
   1.222 -}
   1.223 -
   1.224 -int ucx_array_prepend_from(UcxArray *array, void *data, size_t count) {
   1.225 -    if (ucx_array_ensurecap(array, array->size + count))
   1.226 -        return 1;
   1.227 -    
   1.228 -    if (array->size > 0) {
   1.229 -        void *dest = ucx_array_at(array, count);
   1.230 -        memmove(dest, array->data, array->elemsize*array->size);
   1.231 -    }
   1.232 -    
   1.233 -    if (data) {
   1.234 -        memcpy(array->data, data, array->elemsize*count);
   1.235 -    } else {
   1.236 -        memset(array->data, 0, array->elemsize*count);
   1.237 -    }
   1.238 -    array->size += count;
   1.239 -        
   1.240 -    return 0;
   1.241 -}
   1.242 -
   1.243 -int ucx_array_set_from(UcxArray *array, size_t index,
   1.244 -        void *data, size_t count) {
   1.245 -    if (ucx_array_ensurecap(array, index + count))
   1.246 -        return 1;
   1.247 -    
   1.248 -    if (index+count > array->size) {
   1.249 -        array->size = index+count;
   1.250 -    }
   1.251 -    
   1.252 -    void *dest = ucx_array_at(array, index);
   1.253 -    if (data) {
   1.254 -        memcpy(dest, data, array->elemsize*count);
   1.255 -    } else {
   1.256 -        memset(dest, 0, array->elemsize*count);
   1.257 -    }
   1.258 -    
   1.259 -    return 0;
   1.260 -}
   1.261 -
   1.262 -int ucx_array_concat(UcxArray *array1, const UcxArray *array2) {
   1.263 -    
   1.264 -    if (array1->elemsize != array2->elemsize)
   1.265 -        return 1;
   1.266 -    
   1.267 -    size_t capacity = array1->capacity+array2->capacity;
   1.268 -        
   1.269 -    if (array1->capacity < capacity) {
   1.270 -        if (ucx_array_reserve(array1, capacity)) {
   1.271 -            return 1;
   1.272 -        }
   1.273 -    }
   1.274 -    
   1.275 -    void* dest = ucx_array_at(array1, array1->size);
   1.276 -    memcpy(dest, array2->data, array2->size*array2->elemsize);
   1.277 -    
   1.278 -    array1->size += array2->size;
   1.279 -    
   1.280 -    return 0;
   1.281 -}
   1.282 -
   1.283 -void *ucx_array_at(UcxArray const *array, size_t index) {
   1.284 -    char* memory = array->data;
   1.285 -    char* loc = memory + index*array->elemsize;
   1.286 -    return loc;
   1.287 -}
   1.288 -
   1.289 -size_t ucx_array_find(UcxArray const *array, void *elem,
   1.290 -        cmp_func cmpfnc, void *data) {
   1.291 -    
   1.292 -    size_t elemsize;
   1.293 -    if (cmpfnc == NULL) {
   1.294 -        cmpfnc = ucx_cmp_mem;
   1.295 -        elemsize = array->elemsize;
   1.296 -        data = &elemsize;
   1.297 -    }
   1.298 -
   1.299 -    if (array->size > 0) {
   1.300 -        for (size_t i = 0 ; i < array->size ; i++) {
   1.301 -            void* ptr = ucx_array_at(array, i);
   1.302 -            if (cmpfnc(ptr, elem, data) == 0) {
   1.303 -                return i;
   1.304 -            }
   1.305 -        }
   1.306 -        return array->size;
   1.307 -    } else {
   1.308 -        return 0;
   1.309 -    }
   1.310 -}
   1.311 -
   1.312 -int ucx_array_contains(UcxArray const *array, void *elem,
   1.313 -        cmp_func cmpfnc, void *data) {
   1.314 -    return ucx_array_find(array, elem, cmpfnc, data) != array->size;
   1.315 -}
   1.316 -
   1.317 -static void ucx_mergesort_merge(void *arrdata,size_t elemsize,
   1.318 -        cmp_func cmpfnc, void *data,
   1.319 -        size_t start, size_t mid, size_t end) { 
   1.320 -    
   1.321 -    char* array = arrdata;
   1.322 -    
   1.323 -    size_t rightstart = mid + 1; 
   1.324 -  
   1.325 -    if (cmpfnc(array + mid*elemsize,
   1.326 -            array + rightstart*elemsize, data) <= 0) {
   1.327 -        /* already sorted */
   1.328 -        return;
   1.329 -    }
   1.330 -  
   1.331 -    /* we need memory for one element */
   1.332 -    void *value = malloc(elemsize);
   1.333 -    
   1.334 -    while (start <= mid && rightstart <= end) { 
   1.335 -        if (cmpfnc(array + start*elemsize,
   1.336 -                array + rightstart*elemsize, data) <= 0) { 
   1.337 -            start++; 
   1.338 -        } else {
   1.339 -            /* save the value from the right */
   1.340 -            memcpy(value, array + rightstart*elemsize, elemsize);
   1.341 -                        
   1.342 -            /* shift all left elements one element to the right */
   1.343 -            size_t shiftcount = rightstart-start;
   1.344 -            void *startptr = array + start*elemsize;
   1.345 -            void *dest = array + (start+1)*elemsize;
   1.346 -            memmove(dest, startptr, shiftcount*elemsize);
   1.347 -            
   1.348 -            /* bring the first value from the right to the left */
   1.349 -            memcpy(startptr, value, elemsize);
   1.350 -  
   1.351 -            start++; 
   1.352 -            mid++; 
   1.353 -            rightstart++; 
   1.354 -        }
   1.355 -    }
   1.356 -    
   1.357 -    /* free the temporary memory */
   1.358 -    free(value);
   1.359 -} 
   1.360 -  
   1.361 -static void ucx_mergesort_impl(void *arrdata, size_t elemsize,
   1.362 -        cmp_func cmpfnc, void *data, size_t l, size_t r) { 
   1.363 -    if (l < r) {
   1.364 -        size_t m = l + (r - l) / 2; 
   1.365 -  
   1.366 -        ucx_mergesort_impl(arrdata, elemsize, cmpfnc, data, l, m); 
   1.367 -        ucx_mergesort_impl(arrdata, elemsize, cmpfnc, data, m + 1, r); 
   1.368 -        ucx_mergesort_merge(arrdata, elemsize, cmpfnc, data, l, m, r);
   1.369 -    } 
   1.370 -}
   1.371 -
   1.372 -static void ucx_mergesort(void *arrdata, size_t count, size_t elemsize,
   1.373 -        cmp_func cmpfnc, void *data) {
   1.374 -    
   1.375 -    ucx_mergesort_impl(arrdata, elemsize, cmpfnc, data, 0, count-1);
   1.376 -}
   1.377 -
   1.378 -#ifdef USE_UCX_QSORT_R
   1.379 -struct cmpfnc_swapargs_info {
   1.380 -    cmp_func func;
   1.381 -    void *data;
   1.382 -};
   1.383 -
   1.384 -static int cmp_func_swap_args(void *data, const void *x, const void *y) {
   1.385 -    struct cmpfnc_swapargs_info* info = data;
   1.386 -    return info->func(x, y, info->data);
   1.387 -}
   1.388 -
   1.389 -static void ucx_qsort_r(void *array, size_t count, size_t elemsize,
   1.390 -		     cmp_func cmpfnc, void *data) {
   1.391 -    struct cmpfnc_swapargs_info info;
   1.392 -    info.func = cmpfnc;
   1.393 -    info.data = data;
   1.394 -    qsort_r(array, count, elemsize, &info, cmp_func_swap_args);
   1.395 -}
   1.396 -#endif /* USE_UCX_QSORT_R */
   1.397 -
   1.398 -void ucx_array_sort(UcxArray* array, cmp_func cmpfnc, void *data) {
   1.399 -    ucx_array_sort_impl(array->data, array->size, array->elemsize,
   1.400 -            cmpfnc, data);
   1.401 -}
   1.402 -
   1.403 -void ucx_array_remove(UcxArray *array, size_t index) {
   1.404 -    array->size--;
   1.405 -    if (index < array->size) {
   1.406 -        void* dest = ucx_array_at(array, index);
   1.407 -        void* src = ucx_array_at(array, index+1);
   1.408 -        memmove(dest, src, (array->size - index)*array->elemsize);
   1.409 -    }
   1.410 -}
   1.411 -
   1.412 -void ucx_array_remove_fast(UcxArray *array, size_t index) {
   1.413 -    array->size--;
   1.414 -    if (index < array->size) {       
   1.415 -        void* dest = ucx_array_at(array, index);
   1.416 -        void* src = ucx_array_at(array, array->size);
   1.417 -        memcpy(dest, src, array->elemsize);
   1.418 -    }
   1.419 -}
   1.420 -
   1.421 -int ucx_array_shrink(UcxArray* array) {
   1.422 -    void* newptr = alrealloc(array->allocator, array->data,
   1.423 -                array->size*array->elemsize);
   1.424 -    if (newptr) {
   1.425 -        array->data = newptr;
   1.426 -        array->capacity = array->size;
   1.427 -        return 0;
   1.428 -    } else {
   1.429 -        return 1;
   1.430 -    }
   1.431 -}
   1.432 -
   1.433 -int ucx_array_resize(UcxArray* array, size_t capacity) {
   1.434 -    if (array->capacity >= capacity) {
   1.435 -        void* newptr = alrealloc(array->allocator, array->data,
   1.436 -                capacity*array->elemsize);
   1.437 -        if (newptr) {
   1.438 -            array->data = newptr;
   1.439 -            array->capacity = capacity;
   1.440 -            if (array->size > array->capacity) {
   1.441 -                array->size = array->capacity;
   1.442 -            }
   1.443 -            return 0;
   1.444 -        } else {
   1.445 -            return 1;
   1.446 -        }
   1.447 -    } else {
   1.448 -        return ucx_array_reserve(array, capacity);
   1.449 -    }
   1.450 -}
   1.451 -
   1.452 -int ucx_array_reserve(UcxArray* array, size_t capacity) {
   1.453 -    if (array->capacity > capacity) {
   1.454 -        return 0;
   1.455 -    } else {
   1.456 -        void* newptr = alrealloc(array->allocator, array->data,
   1.457 -                capacity*array->elemsize);
   1.458 -        if (newptr) {
   1.459 -            array->data = newptr;
   1.460 -            array->capacity = capacity;
   1.461 -            return 0;
   1.462 -        } else {
   1.463 -            return 1;
   1.464 -        }
   1.465 -    }
   1.466 -}
   1.467 -
   1.468 -int ucx_array_grow(UcxArray* array, size_t count) {
   1.469 -    return ucx_array_reserve(array, array->size+count);
   1.470 -}

mercurial