Mercurial > code
view array.c @ 25:e09000fc013a
Switch to void * thus the user do not need to cast
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 15 Sep 2011 17:53:43 +0200 |
parents | 216b6e6a539c |
children | 4fd9ecbbb143 |
line wrap: on
line source
/* * array.c -- manipulate dynamic arrays * * Copyright (c) 2011, David Demelier <markand@malikania.fr> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include "array.h" #define SIZE(x) (arr->unit * (x)) static int array_grow(struct array *); struct array * array_new(const void *data, size_t unit, size_t bsize, int flags) { struct array *arr; if (unit == 0 || !(arr = malloc(sizeof (struct array)))) return NULL; arr->tmp = NULL; arr->length = 0; arr->flags = flags; arr->bsize = (bsize == 0) ? ARRAY_DEFAULT_BSIZE : bsize; arr->unit = unit; arr->size = SIZE(arr->bsize); if (!(arr->data = malloc(arr->size))) { free(arr); return NULL; } if (data) memcpy(arr->data, data, arr->unit); return arr; } /* * Add to the head of array. NOTE: this may be very slow when adding a lot * of object (about 100000). If you need to add a lot of data please consider * using linked list instead or use array_append and then use reverse foreach * functions. */ int array_push(struct array *arr, const void *data) { if (array_grow(arr) < 0) return -1; memmove((char *) arr->data + arr->unit, arr->data, SIZE(arr->length++)); memcpy((char *) arr->data, data, arr->unit); return 0; } /* * Insert the data to the specified index. The function returns -1 on * allocation failure if the array need to grow or when the index is out * of bounds otherwise 0 is returned. */ int array_insert(struct array *arr, const void *data, int index) { if (index > arr->length - 1 || index < 0 || array_grow(arr) < 0) return -1; memmove((char *) arr->data + SIZE(index + 1), (char *) arr->data + SIZE(index), SIZE(arr->length++ - index)); memcpy((char *) arr->data + SIZE(index), data, arr->unit); return 0; } /* * Append the data to the end of array. */ int array_append(struct array *arr, const void *data) { if (array_grow(arr) < 0) return -1; memcpy((char *) arr->data + SIZE(arr->length++), data, arr->unit); return 0; } /* * Remove the array's head and return the object or NULL if * the array is empty. */ void * array_pop(struct array *arr) { void *data; if (arr->length == 0) return NULL; data = arr->data; memmove((char *) arr->data, (char *) arr->data + SIZE(1), SIZE(arr->length)); memset((char *) arr->data + SIZE(--arr->length), 0, arr->unit); return data; } /* * Remove the array's queue and return the object or NULL * if the array is empty. */ void * array_unqueue(struct array *arr) { void *data; if (arr->length == 0) return NULL; data = (char *) arr->data + SIZE(--arr->length); memset((char *) arr->data + SIZE(arr->length), 0, arr->unit); return data; } /* * Remove the entry at the specified index and return it. If the index is out of * bounds or the list is empty the functions returns NULL. */ void * array_remove(struct array *arr, int index) { void *data; if (arr->length == 0 || index < 0 || index > arr->length - 1) return NULL; data = (char *) arr->data + SIZE(index); memmove((char *) arr->data + SIZE(index), (char *) arr->data + SIZE(index + 1), SIZE(arr->length - index)); memset((char *) arr->data + SIZE(--arr->length), 0, arr->unit); return data; } /* * Swap the two elements referenced by index `i1' and `i2'. This function needs * to allocate data to swap elements thus if the functions fails it returns -1 * otherwise 0 is returned. */ int array_swap(struct array *arr, int i1, int i2) { /* Out of bounds */ if (i1 > arr->length - 1|| i1 < 0 || i2 > arr->length - 1|| i2 < 0) return -1; /* * Only allocate at this time, the user may do not want to use this * function. */ if (!arr->tmp && !(arr->tmp = malloc(arr->unit))) return -1; memcpy((char *) arr->tmp, (char *) arr->data + SIZE(i1), arr->unit); memcpy((char *) arr->data + SIZE(i1), (char *) arr->data + SIZE(i2), arr->unit); memcpy((char *) arr->data + SIZE(i2), (char *) arr->tmp, arr->unit); return 0; } /* * Apply the function `fn' on each object and give the optional `udata' * argument to the function too. */ void array_map(struct array *arr, void (*fn)(void *, void *), void *udata) { int i; for (i = 0; i < arr->length; ++i) fn((char *) arr->data + SIZE(i), udata); } /* * Compare each object with the user supplied function. If the `fn' function * returns 1 then the data is returned. Optional idx argument can be set to * indicate the data position. If the data was not found the function returns * NULL. */ void * array_find(struct array *arr, int (*fn)(void *, void *), int *idx, void *udata) { int st, i; void *data; for (i = st = 0; i < arr->length && !st; ++i) st = fn((char *) arr->data + SIZE(i), udata); if (st) { data = (char *) arr->data + SIZE(--i); if (idx) *idx = i; } else data = NULL; return data; } /* * Reset the array, if the trash argument is set it will free the object * too, otherwise the array is just truncated to 0 length. */ void array_clear(struct array *arr) { memset(arr->data, 0, arr->size); arr->length = 0; } /* * Same as array_clear except it also free the array object. */ void array_free(struct array *arr) { array_clear(arr); if (arr->data) free(arr->data); if (arr->tmp) free(arr->tmp); free(arr); } /* * Increate the array storage when it is full. If the buffer is fixed size * it returns -1 on full buffer otherwise 0 is returned if allocation * succeeded. */ static int array_grow(struct array *arr) { if ((arr->size / arr->unit) > (size_t) arr->length) return 0; if (arr->flags & ARRAY_AUTO) { if (!(arr->data = realloc(arr->data, arr->size + SIZE(arr->bsize)))) return -1; arr->size += SIZE(arr->bsize); } else return ((arr->size / arr->unit) <= (size_t) arr->length) ? -1 : 0; return 0; }