/* ** Copyright (C) 2005-2006 by Carnegie Mellon University. ** ** @OPENSOURCE_HEADER_START@ ** ** Use of the SILK system and related source code is subject to the terms ** of the following licenses: ** ** GNU Public License (GPL) Rights pursuant to Version 2, June 1991 ** Government Purpose License Rights (GPLR) pursuant to DFARS 252.225-7013 ** ** NO WARRANTY ** ** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER ** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY ** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN ** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY ** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT ** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE, ** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE ** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT, ** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY ** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF ** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES. ** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF ** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON ** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE ** DELIVERABLES UNDER THIS LICENSE. ** ** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie ** Mellon University, its trustees, officers, employees, and agents from ** all claims or demands made against them (and any related losses, ** expenses, or attorney's fees) arising out of, or relating to Licensee's ** and/or its sub licensees' negligent use or willful misuse of or ** negligent conduct or willful misconduct regarding the Software, ** facilities, or other rights or assistance granted by Carnegie Mellon ** University under this License, including, but not limited to, any ** claims of product liability, personal injury, death, damage to ** property, or violation of any laws or regulations. ** ** Carnegie Mellon University Software Engineering Institute authored ** documents are sponsored by the U.S. Department of Defense under ** Contract F19628-00-C-0003. Carnegie Mellon University retains ** copyrights in all material produced under this contract. The U.S. ** Government retains a non-exclusive, royalty-free license to publish or ** reproduce these documents, or allow others to do so, for U.S. ** Government purposes only pursuant to the copyright license under the ** contract clause at 252.227.7013. ** ** @OPENSOURCE_HEADER_END@ */ /* ** A simple vector (grow-able array) type. ** */ #include "silk.h" RCSIDENT("$SiLK: skvector.c 5717 2006-11-16 14:04:15Z mthomas $"); #include "skvector.h" /* LOCAL DEFINES AND TYPEDEFS */ /* vector type */ struct _skvector { uint8_t *list; size_t element_size; size_t capacity; size_t count; }; /* mem-copy the contents of 'elem' to position 'pos' in the vector 'v' */ #define VA_SET(elem, v, pos) \ memcpy(&((v)->list[(pos)*(v)->element_size]), (elem), (v)->element_size) /* mem-copy the contents of position 'pos' in the vector 'v' to 'elem' */ #define VA_GET(elem, v, pos) \ memcpy((elem), &((v)->list[(pos)*(v)->element_size]), (v)->element_size) /* if caller does not set initial capacity, use this value */ #define SKVECTOR_INIT_CAPACITY 16 /* * status = skVectorAlloc(v, new_cap); * * Grow or shink the element list in 'v' to hold 'new_cap' * elements. */ static int skVectorAlloc(sk_vector_t *v, size_t new_cap) { size_t old_cap; uint8_t *old_list; assert(v); assert(new_cap); /* store current values in case the realloc fails */ old_cap = v->capacity; old_list = v->list; /* Allocate memory to grow or shink */ v->capacity = new_cap; if (old_cap == 0) { /* malloc new memory */ v->list = malloc(v->capacity * v->element_size); } else { /* realloc */ v->list = realloc(v->list, v->capacity * v->element_size); } /* handle failure */ if (!v->list) { v->capacity = old_cap; v->list = old_list; return -1; } /* if we grew, bzero the new memory */ if (old_cap < new_cap) { memset((v->list + (old_cap * v->element_size)), 0, ((new_cap - old_cap) * v->element_size)); } return 0; } /* * status = skVectorGrow(v); * * Grow the vector to hold more elements. If the current capacity * is zero, grow to SKVECTOR_INIT_CAPACITY elements; otherwise * double the current capacity. */ static int skVectorGrow(sk_vector_t *v) { size_t cap; assert(v); if (v->capacity == 0) { cap = SKVECTOR_INIT_CAPACITY; } else { cap = 2 * v->capacity; } return skVectorAlloc(v, cap); } sk_vector_t *skVectorNew(size_t element_size) { sk_vector_t *v; if (element_size == 0) { return NULL; } v = calloc(1, sizeof(sk_vector_t)); if (!v) { return NULL; } v->element_size = element_size; return v; } sk_vector_t *skVectorNewFromArray( size_t element_size, const void *array, size_t count) { sk_vector_t *v; /* create the new vector */ v = skVectorNew(element_size); if (v == NULL) { return NULL; } /* make certain we have data with which to fill it */ if (array == NULL || count == 0) { return v; } if (0 != skVectorAlloc(v, count)) { skVectorDestroy(v); return NULL; } v->count = count; memcpy(v->list, array, (v->count * v->element_size)); return v; } void skVectorDestroy(sk_vector_t *v) { if (v) { if (v->list) { free(v->list); v->list = NULL; } v->capacity = 0; v->count = 0; free(v); } } int skVectorSetCapacity(sk_vector_t *v, size_t capacity) { assert(v); /* Nothing to do when desired capacity is our capacity */ if (capacity == v->capacity) { return 0; } /* free the data if capacity is 0 */ if (capacity == 0) { free(v->list); v->list = NULL; v->capacity = 0; v->count = 0; return 0; } /* must realloc or malloc */ return skVectorAlloc(v, capacity); } void skVectorClear(sk_vector_t *v) { if (v) { v->count = 0; memset(v->list, 0, v->element_size * v->capacity); } } size_t skVectorGetElementSize(const sk_vector_t *v) { assert(v); return v->element_size; } size_t skVectorGetCapacity(const sk_vector_t *v) { assert(v); return v->capacity; } size_t skVectorGetCount(const sk_vector_t *v) { assert(v); return v->count; } int skVectorAppendValue(sk_vector_t *v, const void *value) { assert(v); if (v->capacity == v->count) { if (skVectorGrow(v) != 0) { return -1; } } VA_SET(value, v, v->count); ++v->count; return 0; } int skVectorAppendVector(sk_vector_t *dst, const sk_vector_t *src) { size_t total; assert(dst); assert(src); assert(dst->element_size == src->element_size); total = dst->count + src->count; if (dst->capacity <= total) { if (0 != skVectorAlloc(dst, total)) { return -1; } } memcpy(dst->list + dst->element_size * dst->count, src->list, src->element_size * src->count); dst->count += src->count; return 0; } int skVectorSetValue( sk_vector_t *v, size_t position, const void *value) { assert(v); if (position >= v->capacity) { return -1; } VA_SET(value, v, position); if (position >= v->count) { v->count = position+1; } return 0; } int skVectorGetValue( void *out_element, const sk_vector_t *v, size_t position) { assert(v); if (position >= v->count) { return -1; } VA_GET(out_element, v, position); return 0; } void skVectorToArray(void *out_array, const sk_vector_t *v) { assert(v); assert(out_array); if (v->count) { memcpy(out_array, v->list, (v->count*v->element_size)); } }