1bf215546Sopenharmony_ci/**************************************************************************
2bf215546Sopenharmony_ci *
3bf215546Sopenharmony_ci * Copyright 2010 Luca Barbieri
4bf215546Sopenharmony_ci *
5bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining
6bf215546Sopenharmony_ci * a copy of this software and associated documentation files (the
7bf215546Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
8bf215546Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
9bf215546Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to
10bf215546Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
11bf215546Sopenharmony_ci * the following conditions:
12bf215546Sopenharmony_ci *
13bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the
14bf215546Sopenharmony_ci * next paragraph) shall be included in all copies or substantial
15bf215546Sopenharmony_ci * portions of the Software.
16bf215546Sopenharmony_ci *
17bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18bf215546Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19bf215546Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20bf215546Sopenharmony_ci * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
21bf215546Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22bf215546Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23bf215546Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24bf215546Sopenharmony_ci *
25bf215546Sopenharmony_ci **************************************************************************/
26bf215546Sopenharmony_ci
27bf215546Sopenharmony_ci#ifndef U_DYNARRAY_H
28bf215546Sopenharmony_ci#define U_DYNARRAY_H
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_ci#include <stdlib.h>
31bf215546Sopenharmony_ci#include <string.h>
32bf215546Sopenharmony_ci#include <limits.h>
33bf215546Sopenharmony_ci#include "ralloc.h"
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci#ifdef __cplusplus
36bf215546Sopenharmony_ciextern "C" {
37bf215546Sopenharmony_ci#endif
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_ci/* A zero-initialized version of this is guaranteed to represent an
40bf215546Sopenharmony_ci * empty array.
41bf215546Sopenharmony_ci *
42bf215546Sopenharmony_ci * Also, size <= capacity and data != 0 if and only if capacity != 0
43bf215546Sopenharmony_ci * capacity will always be the allocation size of data
44bf215546Sopenharmony_ci */
45bf215546Sopenharmony_cistruct util_dynarray
46bf215546Sopenharmony_ci{
47bf215546Sopenharmony_ci   void *mem_ctx;
48bf215546Sopenharmony_ci   void *data;
49bf215546Sopenharmony_ci   unsigned size;
50bf215546Sopenharmony_ci   unsigned capacity;
51bf215546Sopenharmony_ci};
52bf215546Sopenharmony_ci
53bf215546Sopenharmony_cistatic inline void
54bf215546Sopenharmony_ciutil_dynarray_init(struct util_dynarray *buf, void *mem_ctx)
55bf215546Sopenharmony_ci{
56bf215546Sopenharmony_ci   memset(buf, 0, sizeof(*buf));
57bf215546Sopenharmony_ci   buf->mem_ctx = mem_ctx;
58bf215546Sopenharmony_ci}
59bf215546Sopenharmony_ci
60bf215546Sopenharmony_cistatic inline void
61bf215546Sopenharmony_ciutil_dynarray_fini(struct util_dynarray *buf)
62bf215546Sopenharmony_ci{
63bf215546Sopenharmony_ci   if (buf->data) {
64bf215546Sopenharmony_ci      if (buf->mem_ctx) {
65bf215546Sopenharmony_ci         ralloc_free(buf->data);
66bf215546Sopenharmony_ci      } else {
67bf215546Sopenharmony_ci         free(buf->data);
68bf215546Sopenharmony_ci      }
69bf215546Sopenharmony_ci      util_dynarray_init(buf, buf->mem_ctx);
70bf215546Sopenharmony_ci   }
71bf215546Sopenharmony_ci}
72bf215546Sopenharmony_ci
73bf215546Sopenharmony_cistatic inline void
74bf215546Sopenharmony_ciutil_dynarray_clear(struct util_dynarray *buf)
75bf215546Sopenharmony_ci{
76bf215546Sopenharmony_ci	buf->size = 0;
77bf215546Sopenharmony_ci}
78bf215546Sopenharmony_ci
79bf215546Sopenharmony_ci#define DYN_ARRAY_INITIAL_SIZE 64
80bf215546Sopenharmony_ci
81bf215546Sopenharmony_ciMUST_CHECK static inline void *
82bf215546Sopenharmony_ciutil_dynarray_ensure_cap(struct util_dynarray *buf, unsigned newcap)
83bf215546Sopenharmony_ci{
84bf215546Sopenharmony_ci   if (newcap > buf->capacity) {
85bf215546Sopenharmony_ci      unsigned capacity = MAX3(DYN_ARRAY_INITIAL_SIZE, buf->capacity * 2, newcap);
86bf215546Sopenharmony_ci      void *data;
87bf215546Sopenharmony_ci
88bf215546Sopenharmony_ci      if (buf->mem_ctx) {
89bf215546Sopenharmony_ci         data = reralloc_size(buf->mem_ctx, buf->data, capacity);
90bf215546Sopenharmony_ci      } else {
91bf215546Sopenharmony_ci         data = realloc(buf->data, capacity);
92bf215546Sopenharmony_ci      }
93bf215546Sopenharmony_ci      if (!data)
94bf215546Sopenharmony_ci         return NULL;
95bf215546Sopenharmony_ci
96bf215546Sopenharmony_ci      buf->data = data;
97bf215546Sopenharmony_ci      buf->capacity = capacity;
98bf215546Sopenharmony_ci   }
99bf215546Sopenharmony_ci
100bf215546Sopenharmony_ci   return (void *)((char *)buf->data + buf->size);
101bf215546Sopenharmony_ci}
102bf215546Sopenharmony_ci
103bf215546Sopenharmony_ci/* use util_dynarray_trim to reduce the allocated storage */
104bf215546Sopenharmony_ciMUST_CHECK static inline void *
105bf215546Sopenharmony_ciutil_dynarray_resize_bytes(struct util_dynarray *buf, unsigned nelts, size_t eltsize)
106bf215546Sopenharmony_ci{
107bf215546Sopenharmony_ci   if (unlikely(nelts > UINT_MAX / eltsize))
108bf215546Sopenharmony_ci      return NULL;
109bf215546Sopenharmony_ci
110bf215546Sopenharmony_ci   unsigned newsize = nelts * eltsize;
111bf215546Sopenharmony_ci   void *p = util_dynarray_ensure_cap(buf, newsize);
112bf215546Sopenharmony_ci   if (!p)
113bf215546Sopenharmony_ci      return NULL;
114bf215546Sopenharmony_ci
115bf215546Sopenharmony_ci   buf->size = newsize;
116bf215546Sopenharmony_ci
117bf215546Sopenharmony_ci   return p;
118bf215546Sopenharmony_ci}
119bf215546Sopenharmony_ci
120bf215546Sopenharmony_cistatic inline void
121bf215546Sopenharmony_ciutil_dynarray_clone(struct util_dynarray *buf, void *mem_ctx,
122bf215546Sopenharmony_ci                    struct util_dynarray *from_buf)
123bf215546Sopenharmony_ci{
124bf215546Sopenharmony_ci   util_dynarray_init(buf, mem_ctx);
125bf215546Sopenharmony_ci   if (util_dynarray_resize_bytes(buf, from_buf->size, 1))
126bf215546Sopenharmony_ci      memcpy(buf->data, from_buf->data, from_buf->size);
127bf215546Sopenharmony_ci}
128bf215546Sopenharmony_ci
129bf215546Sopenharmony_ciMUST_CHECK static inline void *
130bf215546Sopenharmony_ciutil_dynarray_grow_bytes(struct util_dynarray *buf, unsigned ngrow, size_t eltsize)
131bf215546Sopenharmony_ci{
132bf215546Sopenharmony_ci   unsigned growbytes = ngrow * eltsize;
133bf215546Sopenharmony_ci
134bf215546Sopenharmony_ci   if (unlikely(ngrow > (UINT_MAX / eltsize) ||
135bf215546Sopenharmony_ci                growbytes > UINT_MAX - buf->size))
136bf215546Sopenharmony_ci      return NULL;
137bf215546Sopenharmony_ci
138bf215546Sopenharmony_ci   unsigned newsize = buf->size + growbytes;
139bf215546Sopenharmony_ci   void *p = util_dynarray_ensure_cap(buf, newsize);
140bf215546Sopenharmony_ci   if (!p)
141bf215546Sopenharmony_ci      return NULL;
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_ci   buf->size = newsize;
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_ci   return p;
146bf215546Sopenharmony_ci}
147bf215546Sopenharmony_ci
148bf215546Sopenharmony_cistatic inline void
149bf215546Sopenharmony_ciutil_dynarray_trim(struct util_dynarray *buf)
150bf215546Sopenharmony_ci{
151bf215546Sopenharmony_ci   if (buf->size != buf->capacity) {
152bf215546Sopenharmony_ci      if (buf->size) {
153bf215546Sopenharmony_ci         if (buf->mem_ctx) {
154bf215546Sopenharmony_ci            buf->data = reralloc_size(buf->mem_ctx, buf->data, buf->size);
155bf215546Sopenharmony_ci         } else {
156bf215546Sopenharmony_ci            buf->data = realloc(buf->data, buf->size);
157bf215546Sopenharmony_ci         }
158bf215546Sopenharmony_ci         buf->capacity = buf->size;
159bf215546Sopenharmony_ci      } else {
160bf215546Sopenharmony_ci         if (buf->mem_ctx) {
161bf215546Sopenharmony_ci            ralloc_free(buf->data);
162bf215546Sopenharmony_ci         } else {
163bf215546Sopenharmony_ci            free(buf->data);
164bf215546Sopenharmony_ci         }
165bf215546Sopenharmony_ci         buf->data = NULL;
166bf215546Sopenharmony_ci         buf->capacity = 0;
167bf215546Sopenharmony_ci      }
168bf215546Sopenharmony_ci   }
169bf215546Sopenharmony_ci}
170bf215546Sopenharmony_ci
171bf215546Sopenharmony_ci#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)
172bf215546Sopenharmony_ci/* Returns a pointer to the space of the first new element (in case of growth) or NULL on failure. */
173bf215546Sopenharmony_ci#define util_dynarray_resize(buf, type, nelts) util_dynarray_resize_bytes(buf, (nelts), sizeof(type))
174bf215546Sopenharmony_ci#define util_dynarray_grow(buf, type, ngrow) util_dynarray_grow_bytes(buf, (ngrow), sizeof(type))
175bf215546Sopenharmony_ci#define util_dynarray_top_ptr(buf, type) (type*)((char*)(buf)->data + (buf)->size - sizeof(type))
176bf215546Sopenharmony_ci#define util_dynarray_top(buf, type) *util_dynarray_top_ptr(buf, type)
177bf215546Sopenharmony_ci#define util_dynarray_pop_ptr(buf, type) (type*)((char*)(buf)->data + ((buf)->size -= sizeof(type)))
178bf215546Sopenharmony_ci#define util_dynarray_pop(buf, type) *util_dynarray_pop_ptr(buf, type)
179bf215546Sopenharmony_ci#define util_dynarray_contains(buf, type) ((buf)->size >= sizeof(type))
180bf215546Sopenharmony_ci#define util_dynarray_element(buf, type, idx) ((type*)(buf)->data + (idx))
181bf215546Sopenharmony_ci#define util_dynarray_begin(buf) ((buf)->data)
182bf215546Sopenharmony_ci#define util_dynarray_end(buf) ((void*)util_dynarray_element((buf), char, (buf)->size))
183bf215546Sopenharmony_ci#define util_dynarray_num_elements(buf, type) ((buf)->size / sizeof(type))
184bf215546Sopenharmony_ci
185bf215546Sopenharmony_ci#define util_dynarray_foreach(buf, type, elem) \
186bf215546Sopenharmony_ci   for (type *elem = (type *)(buf)->data; \
187bf215546Sopenharmony_ci        elem < (type *)((char *)(buf)->data + (buf)->size); elem++)
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci#define util_dynarray_foreach_reverse(buf, type, elem)          \
190bf215546Sopenharmony_ci   if ((buf)->size > 0)                                         \
191bf215546Sopenharmony_ci      for (type *elem = util_dynarray_top_ptr(buf, type);       \
192bf215546Sopenharmony_ci           elem;                                                \
193bf215546Sopenharmony_ci           elem = elem > (type *)(buf)->data ? elem - 1 : NULL)
194bf215546Sopenharmony_ci
195bf215546Sopenharmony_ci#define util_dynarray_delete_unordered(buf, type, v)                    \
196bf215546Sopenharmony_ci   do {                                                                 \
197bf215546Sopenharmony_ci      unsigned num_elements = (buf)->size / sizeof(type);               \
198bf215546Sopenharmony_ci      unsigned i;                                                       \
199bf215546Sopenharmony_ci      for (i = 0; i < num_elements; i++) {                              \
200bf215546Sopenharmony_ci         type __v = *util_dynarray_element((buf), type, (i));           \
201bf215546Sopenharmony_ci         if (v == __v) {                                                \
202bf215546Sopenharmony_ci            memcpy(util_dynarray_element((buf), type, (i)),             \
203bf215546Sopenharmony_ci                   util_dynarray_pop_ptr((buf), type), sizeof(type));   \
204bf215546Sopenharmony_ci            break;                                                      \
205bf215546Sopenharmony_ci         }                                                              \
206bf215546Sopenharmony_ci      }                                                                 \
207bf215546Sopenharmony_ci   } while (0)
208bf215546Sopenharmony_ci
209bf215546Sopenharmony_ci#ifdef __cplusplus
210bf215546Sopenharmony_ci}
211bf215546Sopenharmony_ci#endif
212bf215546Sopenharmony_ci
213bf215546Sopenharmony_ci#endif /* U_DYNARRAY_H */
214bf215546Sopenharmony_ci
215