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