101e04c3fSmrg/************************************************************************** 201e04c3fSmrg * 301e04c3fSmrg * Copyright 2010 Luca Barbieri 401e04c3fSmrg * 501e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining 601e04c3fSmrg * a copy of this software and associated documentation files (the 701e04c3fSmrg * "Software"), to deal in the Software without restriction, including 801e04c3fSmrg * without limitation the rights to use, copy, modify, merge, publish, 901e04c3fSmrg * distribute, sublicense, and/or sell copies of the Software, and to 1001e04c3fSmrg * permit persons to whom the Software is furnished to do so, subject to 1101e04c3fSmrg * the following conditions: 1201e04c3fSmrg * 1301e04c3fSmrg * The above copyright notice and this permission notice (including the 1401e04c3fSmrg * next paragraph) shall be included in all copies or substantial 1501e04c3fSmrg * portions of the Software. 1601e04c3fSmrg * 1701e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 1801e04c3fSmrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1901e04c3fSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 2001e04c3fSmrg * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE 2101e04c3fSmrg * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 2201e04c3fSmrg * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 2301e04c3fSmrg * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2401e04c3fSmrg * 2501e04c3fSmrg **************************************************************************/ 2601e04c3fSmrg 2701e04c3fSmrg#ifndef U_DYNARRAY_H 2801e04c3fSmrg#define U_DYNARRAY_H 2901e04c3fSmrg 3001e04c3fSmrg#include <stdlib.h> 3101e04c3fSmrg#include <string.h> 327ec681f3Smrg#include <limits.h> 3301e04c3fSmrg#include "ralloc.h" 3401e04c3fSmrg 3501e04c3fSmrg#ifdef __cplusplus 3601e04c3fSmrgextern "C" { 3701e04c3fSmrg#endif 3801e04c3fSmrg 3901e04c3fSmrg/* A zero-initialized version of this is guaranteed to represent an 4001e04c3fSmrg * empty array. 4101e04c3fSmrg * 4201e04c3fSmrg * Also, size <= capacity and data != 0 if and only if capacity != 0 4301e04c3fSmrg * capacity will always be the allocation size of data 4401e04c3fSmrg */ 4501e04c3fSmrgstruct util_dynarray 4601e04c3fSmrg{ 4701e04c3fSmrg void *mem_ctx; 4801e04c3fSmrg void *data; 4901e04c3fSmrg unsigned size; 5001e04c3fSmrg unsigned capacity; 5101e04c3fSmrg}; 5201e04c3fSmrg 5301e04c3fSmrgstatic inline void 5401e04c3fSmrgutil_dynarray_init(struct util_dynarray *buf, void *mem_ctx) 5501e04c3fSmrg{ 5601e04c3fSmrg memset(buf, 0, sizeof(*buf)); 5701e04c3fSmrg buf->mem_ctx = mem_ctx; 5801e04c3fSmrg} 5901e04c3fSmrg 6001e04c3fSmrgstatic inline void 6101e04c3fSmrgutil_dynarray_fini(struct util_dynarray *buf) 6201e04c3fSmrg{ 6301e04c3fSmrg if (buf->data) { 6401e04c3fSmrg if (buf->mem_ctx) { 6501e04c3fSmrg ralloc_free(buf->data); 6601e04c3fSmrg } else { 6701e04c3fSmrg free(buf->data); 6801e04c3fSmrg } 6901e04c3fSmrg util_dynarray_init(buf, buf->mem_ctx); 7001e04c3fSmrg } 7101e04c3fSmrg} 7201e04c3fSmrg 7301e04c3fSmrgstatic inline void 7401e04c3fSmrgutil_dynarray_clear(struct util_dynarray *buf) 7501e04c3fSmrg{ 7601e04c3fSmrg buf->size = 0; 7701e04c3fSmrg} 7801e04c3fSmrg 7901e04c3fSmrg#define DYN_ARRAY_INITIAL_SIZE 64 8001e04c3fSmrg 817ec681f3SmrgMUST_CHECK static inline void * 828a1362adSmayautil_dynarray_ensure_cap(struct util_dynarray *buf, unsigned newcap) 8301e04c3fSmrg{ 848a1362adSmaya if (newcap > buf->capacity) { 857ec681f3Smrg unsigned capacity = MAX3(DYN_ARRAY_INITIAL_SIZE, buf->capacity * 2, newcap); 867ec681f3Smrg void *data; 8701e04c3fSmrg 8801e04c3fSmrg if (buf->mem_ctx) { 897ec681f3Smrg data = reralloc_size(buf->mem_ctx, buf->data, capacity); 9001e04c3fSmrg } else { 917ec681f3Smrg data = realloc(buf->data, capacity); 9201e04c3fSmrg } 937ec681f3Smrg if (!data) 947ec681f3Smrg return 0; 957ec681f3Smrg 967ec681f3Smrg buf->data = data; 977ec681f3Smrg buf->capacity = capacity; 9801e04c3fSmrg } 9901e04c3fSmrg 1008a1362adSmaya return (void *)((char *)buf->data + buf->size); 1018a1362adSmaya} 1028a1362adSmaya 1038a1362adSmaya/* use util_dynarray_trim to reduce the allocated storage */ 1047ec681f3SmrgMUST_CHECK static inline void * 1057ec681f3Smrgutil_dynarray_resize_bytes(struct util_dynarray *buf, unsigned nelts, size_t eltsize) 1068a1362adSmaya{ 1077ec681f3Smrg if (unlikely(nelts > UINT_MAX / eltsize)) 1087ec681f3Smrg return 0; 1097ec681f3Smrg 1107ec681f3Smrg unsigned newsize = nelts * eltsize; 1118a1362adSmaya void *p = util_dynarray_ensure_cap(buf, newsize); 1127ec681f3Smrg if (!p) 1137ec681f3Smrg return 0; 1147ec681f3Smrg 11501e04c3fSmrg buf->size = newsize; 11601e04c3fSmrg 11701e04c3fSmrg return p; 11801e04c3fSmrg} 11901e04c3fSmrg 12001e04c3fSmrgstatic inline void 12101e04c3fSmrgutil_dynarray_clone(struct util_dynarray *buf, void *mem_ctx, 12201e04c3fSmrg struct util_dynarray *from_buf) 12301e04c3fSmrg{ 12401e04c3fSmrg util_dynarray_init(buf, mem_ctx); 1257ec681f3Smrg if (util_dynarray_resize_bytes(buf, from_buf->size, 1)) 1267ec681f3Smrg memcpy(buf->data, from_buf->data, from_buf->size); 12701e04c3fSmrg} 12801e04c3fSmrg 1297ec681f3SmrgMUST_CHECK static inline void * 1307ec681f3Smrgutil_dynarray_grow_bytes(struct util_dynarray *buf, unsigned ngrow, size_t eltsize) 13101e04c3fSmrg{ 1327ec681f3Smrg unsigned growbytes = ngrow * eltsize; 1337ec681f3Smrg 1347ec681f3Smrg if (unlikely(ngrow > (UINT_MAX / eltsize) || 1357ec681f3Smrg growbytes > UINT_MAX - buf->size)) 1367ec681f3Smrg return 0; 1377ec681f3Smrg 1387ec681f3Smrg unsigned newsize = buf->size + growbytes; 1397ec681f3Smrg void *p = util_dynarray_ensure_cap(buf, newsize); 1407ec681f3Smrg if (!p) 1417ec681f3Smrg return 0; 1427ec681f3Smrg 1437ec681f3Smrg buf->size = newsize; 1447ec681f3Smrg 1457ec681f3Smrg return p; 14601e04c3fSmrg} 14701e04c3fSmrg 14801e04c3fSmrgstatic inline void 14901e04c3fSmrgutil_dynarray_trim(struct util_dynarray *buf) 15001e04c3fSmrg{ 15101e04c3fSmrg if (buf->size != buf->capacity) { 15201e04c3fSmrg if (buf->size) { 15301e04c3fSmrg if (buf->mem_ctx) { 15401e04c3fSmrg buf->data = reralloc_size(buf->mem_ctx, buf->data, buf->size); 15501e04c3fSmrg } else { 15601e04c3fSmrg buf->data = realloc(buf->data, buf->size); 15701e04c3fSmrg } 15801e04c3fSmrg buf->capacity = buf->size; 15901e04c3fSmrg } else { 16001e04c3fSmrg if (buf->mem_ctx) { 16101e04c3fSmrg ralloc_free(buf->data); 16201e04c3fSmrg } else { 16301e04c3fSmrg free(buf->data); 16401e04c3fSmrg } 16501e04c3fSmrg buf->data = NULL; 16601e04c3fSmrg buf->capacity = 0; 16701e04c3fSmrg } 16801e04c3fSmrg } 16901e04c3fSmrg} 17001e04c3fSmrg 1717ec681f3Smrg#define util_dynarray_append(buf, type, v) do {type __v = (v); memcpy(util_dynarray_grow_bytes((buf), 1, sizeof(type)), &__v, sizeof(type));} while(0) 1727ec681f3Smrg/* Returns a pointer to the space of the first new element (in case of growth) or NULL on failure. */ 1737ec681f3Smrg#define util_dynarray_resize(buf, type, nelts) util_dynarray_resize_bytes(buf, (nelts), sizeof(type)) 1747ec681f3Smrg#define util_dynarray_grow(buf, type, ngrow) util_dynarray_grow_bytes(buf, (ngrow), sizeof(type)) 17501e04c3fSmrg#define util_dynarray_top_ptr(buf, type) (type*)((char*)(buf)->data + (buf)->size - sizeof(type)) 17601e04c3fSmrg#define util_dynarray_top(buf, type) *util_dynarray_top_ptr(buf, type) 17701e04c3fSmrg#define util_dynarray_pop_ptr(buf, type) (type*)((char*)(buf)->data + ((buf)->size -= sizeof(type))) 17801e04c3fSmrg#define util_dynarray_pop(buf, type) *util_dynarray_pop_ptr(buf, type) 17901e04c3fSmrg#define util_dynarray_contains(buf, type) ((buf)->size >= sizeof(type)) 18001e04c3fSmrg#define util_dynarray_element(buf, type, idx) ((type*)(buf)->data + (idx)) 18101e04c3fSmrg#define util_dynarray_begin(buf) ((buf)->data) 18201e04c3fSmrg#define util_dynarray_end(buf) ((void*)util_dynarray_element((buf), char, (buf)->size)) 18301e04c3fSmrg#define util_dynarray_num_elements(buf, type) ((buf)->size / sizeof(type)) 18401e04c3fSmrg 18501e04c3fSmrg#define util_dynarray_foreach(buf, type, elem) \ 18601e04c3fSmrg for (type *elem = (type *)(buf)->data; \ 18701e04c3fSmrg elem < (type *)((char *)(buf)->data + (buf)->size); elem++) 18801e04c3fSmrg 18901e04c3fSmrg#define util_dynarray_foreach_reverse(buf, type, elem) \ 19001e04c3fSmrg if ((buf)->size > 0) \ 19101e04c3fSmrg for (type *elem = util_dynarray_top_ptr(buf, type); \ 19201e04c3fSmrg elem; \ 19301e04c3fSmrg elem = elem > (type *)(buf)->data ? elem - 1 : NULL) 19401e04c3fSmrg 19501e04c3fSmrg#define util_dynarray_delete_unordered(buf, type, v) \ 19601e04c3fSmrg do { \ 19701e04c3fSmrg unsigned num_elements = (buf)->size / sizeof(type); \ 19801e04c3fSmrg unsigned i; \ 19901e04c3fSmrg for (i = 0; i < num_elements; i++) { \ 20001e04c3fSmrg type __v = *util_dynarray_element((buf), type, (i)); \ 20101e04c3fSmrg if (v == __v) { \ 20201e04c3fSmrg memcpy(util_dynarray_element((buf), type, (i)), \ 20301e04c3fSmrg util_dynarray_pop_ptr((buf), type), sizeof(type)); \ 20401e04c3fSmrg break; \ 20501e04c3fSmrg } \ 20601e04c3fSmrg } \ 20701e04c3fSmrg } while (0) 20801e04c3fSmrg 20901e04c3fSmrg#ifdef __cplusplus 21001e04c3fSmrg} 21101e04c3fSmrg#endif 21201e04c3fSmrg 21301e04c3fSmrg#endif /* U_DYNARRAY_H */ 21401e04c3fSmrg 215