u_dynarray.h revision 8a1362ad
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>
3201e04c3fSmrg#include "ralloc.h"
3301e04c3fSmrg
3401e04c3fSmrg#ifdef __cplusplus
3501e04c3fSmrgextern "C" {
3601e04c3fSmrg#endif
3701e04c3fSmrg
3801e04c3fSmrg/* A zero-initialized version of this is guaranteed to represent an
3901e04c3fSmrg * empty array.
4001e04c3fSmrg *
4101e04c3fSmrg * Also, size <= capacity and data != 0 if and only if capacity != 0
4201e04c3fSmrg * capacity will always be the allocation size of data
4301e04c3fSmrg */
4401e04c3fSmrgstruct util_dynarray
4501e04c3fSmrg{
4601e04c3fSmrg   void *mem_ctx;
4701e04c3fSmrg   void *data;
4801e04c3fSmrg   unsigned size;
4901e04c3fSmrg   unsigned capacity;
5001e04c3fSmrg};
5101e04c3fSmrg
5201e04c3fSmrgstatic inline void
5301e04c3fSmrgutil_dynarray_init(struct util_dynarray *buf, void *mem_ctx)
5401e04c3fSmrg{
5501e04c3fSmrg   memset(buf, 0, sizeof(*buf));
5601e04c3fSmrg   buf->mem_ctx = mem_ctx;
5701e04c3fSmrg}
5801e04c3fSmrg
5901e04c3fSmrgstatic inline void
6001e04c3fSmrgutil_dynarray_fini(struct util_dynarray *buf)
6101e04c3fSmrg{
6201e04c3fSmrg   if (buf->data) {
6301e04c3fSmrg      if (buf->mem_ctx) {
6401e04c3fSmrg         ralloc_free(buf->data);
6501e04c3fSmrg      } else {
6601e04c3fSmrg         free(buf->data);
6701e04c3fSmrg      }
6801e04c3fSmrg      util_dynarray_init(buf, buf->mem_ctx);
6901e04c3fSmrg   }
7001e04c3fSmrg}
7101e04c3fSmrg
7201e04c3fSmrgstatic inline void
7301e04c3fSmrgutil_dynarray_clear(struct util_dynarray *buf)
7401e04c3fSmrg{
7501e04c3fSmrg	buf->size = 0;
7601e04c3fSmrg}
7701e04c3fSmrg
7801e04c3fSmrg#define DYN_ARRAY_INITIAL_SIZE 64
7901e04c3fSmrg
8001e04c3fSmrgstatic inline void *
818a1362adSmayautil_dynarray_ensure_cap(struct util_dynarray *buf, unsigned newcap)
8201e04c3fSmrg{
838a1362adSmaya   if (newcap > buf->capacity) {
8401e04c3fSmrg      if (buf->capacity == 0)
8501e04c3fSmrg         buf->capacity = DYN_ARRAY_INITIAL_SIZE;
8601e04c3fSmrg
878a1362adSmaya      while (newcap > buf->capacity)
8801e04c3fSmrg         buf->capacity *= 2;
8901e04c3fSmrg
9001e04c3fSmrg      if (buf->mem_ctx) {
9101e04c3fSmrg         buf->data = reralloc_size(buf->mem_ctx, buf->data, buf->capacity);
9201e04c3fSmrg      } else {
9301e04c3fSmrg         buf->data = realloc(buf->data, buf->capacity);
9401e04c3fSmrg      }
9501e04c3fSmrg   }
9601e04c3fSmrg
978a1362adSmaya   return (void *)((char *)buf->data + buf->size);
988a1362adSmaya}
998a1362adSmaya
1008a1362adSmayastatic inline void *
1018a1362adSmayautil_dynarray_grow_cap(struct util_dynarray *buf, int diff)
1028a1362adSmaya{
1038a1362adSmaya   return util_dynarray_ensure_cap(buf, buf->size + diff);
1048a1362adSmaya}
1058a1362adSmaya
1068a1362adSmaya/* use util_dynarray_trim to reduce the allocated storage */
1078a1362adSmayastatic inline void *
1088a1362adSmayautil_dynarray_resize(struct util_dynarray *buf, unsigned newsize)
1098a1362adSmaya{
1108a1362adSmaya   void *p = util_dynarray_ensure_cap(buf, newsize);
11101e04c3fSmrg   buf->size = newsize;
11201e04c3fSmrg
11301e04c3fSmrg   return p;
11401e04c3fSmrg}
11501e04c3fSmrg
11601e04c3fSmrgstatic inline void
11701e04c3fSmrgutil_dynarray_clone(struct util_dynarray *buf, void *mem_ctx,
11801e04c3fSmrg                    struct util_dynarray *from_buf)
11901e04c3fSmrg{
12001e04c3fSmrg   util_dynarray_init(buf, mem_ctx);
12101e04c3fSmrg   util_dynarray_resize(buf, from_buf->size);
12201e04c3fSmrg   memcpy(buf->data, from_buf->data, from_buf->size);
12301e04c3fSmrg}
12401e04c3fSmrg
12501e04c3fSmrgstatic inline void *
12601e04c3fSmrgutil_dynarray_grow(struct util_dynarray *buf, int diff)
12701e04c3fSmrg{
12801e04c3fSmrg   return util_dynarray_resize(buf, buf->size + diff);
12901e04c3fSmrg}
13001e04c3fSmrg
13101e04c3fSmrgstatic inline void
13201e04c3fSmrgutil_dynarray_trim(struct util_dynarray *buf)
13301e04c3fSmrg{
13401e04c3fSmrg   if (buf->size != buf->capacity) {
13501e04c3fSmrg      if (buf->size) {
13601e04c3fSmrg         if (buf->mem_ctx) {
13701e04c3fSmrg            buf->data = reralloc_size(buf->mem_ctx, buf->data, buf->size);
13801e04c3fSmrg         } else {
13901e04c3fSmrg            buf->data = realloc(buf->data, buf->size);
14001e04c3fSmrg         }
14101e04c3fSmrg         buf->capacity = buf->size;
14201e04c3fSmrg      } else {
14301e04c3fSmrg         if (buf->mem_ctx) {
14401e04c3fSmrg            ralloc_free(buf->data);
14501e04c3fSmrg         } else {
14601e04c3fSmrg            free(buf->data);
14701e04c3fSmrg         }
14801e04c3fSmrg         buf->data = NULL;
14901e04c3fSmrg         buf->capacity = 0;
15001e04c3fSmrg      }
15101e04c3fSmrg   }
15201e04c3fSmrg}
15301e04c3fSmrg
15401e04c3fSmrg#define util_dynarray_append(buf, type, v) do {type __v = (v); memcpy(util_dynarray_grow((buf), sizeof(type)), &__v, sizeof(type));} while(0)
15501e04c3fSmrg#define util_dynarray_top_ptr(buf, type) (type*)((char*)(buf)->data + (buf)->size - sizeof(type))
15601e04c3fSmrg#define util_dynarray_top(buf, type) *util_dynarray_top_ptr(buf, type)
15701e04c3fSmrg#define util_dynarray_pop_ptr(buf, type) (type*)((char*)(buf)->data + ((buf)->size -= sizeof(type)))
15801e04c3fSmrg#define util_dynarray_pop(buf, type) *util_dynarray_pop_ptr(buf, type)
15901e04c3fSmrg#define util_dynarray_contains(buf, type) ((buf)->size >= sizeof(type))
16001e04c3fSmrg#define util_dynarray_element(buf, type, idx) ((type*)(buf)->data + (idx))
16101e04c3fSmrg#define util_dynarray_begin(buf) ((buf)->data)
16201e04c3fSmrg#define util_dynarray_end(buf) ((void*)util_dynarray_element((buf), char, (buf)->size))
16301e04c3fSmrg#define util_dynarray_num_elements(buf, type) ((buf)->size / sizeof(type))
16401e04c3fSmrg
16501e04c3fSmrg#define util_dynarray_foreach(buf, type, elem) \
16601e04c3fSmrg   for (type *elem = (type *)(buf)->data; \
16701e04c3fSmrg        elem < (type *)((char *)(buf)->data + (buf)->size); elem++)
16801e04c3fSmrg
16901e04c3fSmrg#define util_dynarray_foreach_reverse(buf, type, elem)          \
17001e04c3fSmrg   if ((buf)->size > 0)                                         \
17101e04c3fSmrg      for (type *elem = util_dynarray_top_ptr(buf, type);       \
17201e04c3fSmrg           elem;                                                \
17301e04c3fSmrg           elem = elem > (type *)(buf)->data ? elem - 1 : NULL)
17401e04c3fSmrg
17501e04c3fSmrg#define util_dynarray_delete_unordered(buf, type, v)                    \
17601e04c3fSmrg   do {                                                                 \
17701e04c3fSmrg      unsigned num_elements = (buf)->size / sizeof(type);               \
17801e04c3fSmrg      unsigned i;                                                       \
17901e04c3fSmrg      for (i = 0; i < num_elements; i++) {                              \
18001e04c3fSmrg         type __v = *util_dynarray_element((buf), type, (i));           \
18101e04c3fSmrg         if (v == __v) {                                                \
18201e04c3fSmrg            memcpy(util_dynarray_element((buf), type, (i)),             \
18301e04c3fSmrg                   util_dynarray_pop_ptr((buf), type), sizeof(type));   \
18401e04c3fSmrg            break;                                                      \
18501e04c3fSmrg         }                                                              \
18601e04c3fSmrg      }                                                                 \
18701e04c3fSmrg   } while (0)
18801e04c3fSmrg
18901e04c3fSmrg#ifdef __cplusplus
19001e04c3fSmrg}
19101e04c3fSmrg#endif
19201e04c3fSmrg
19301e04c3fSmrg#endif /* U_DYNARRAY_H */
19401e04c3fSmrg
195