1/*-
2 * Copyright (c) 2009 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by David A. Holland.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#ifndef ARRAY_H
31#define ARRAY_H
32
33#include "inlinedefs.h" // XXX
34#include "utils.h"
35
36#define ARRAYS_CHECKED
37
38#ifdef ARRAYS_CHECKED
39#include <assert.h>
40#define arrayassert assert
41#else
42#define arrayassert(x) ((void)(x))
43#endif
44
45#ifndef ARRAYINLINE
46#define ARRAYINLINE C99INLINE
47#endif
48
49////////////////////////////////////////////////////////////
50// type and base operations
51
52struct array {
53	void **v;
54	unsigned num, max;
55};
56
57struct array *array_create(void);
58void array_destroy(struct array *);
59void array_init(struct array *);
60void array_cleanup(struct array *);
61ARRAYINLINE unsigned array_num(const struct array *);
62ARRAYINLINE void *array_get(const struct array *, unsigned index_);
63ARRAYINLINE void array_set(const struct array *, unsigned index_, void *val);
64void array_setsize(struct array *, unsigned num);
65ARRAYINLINE void array_add(struct array *, void *val, unsigned *index_ret);
66void array_insert(struct array *a, unsigned index_);
67void array_remove(struct array *a, unsigned index_);
68
69////////////////////////////////////////////////////////////
70// inlining for base operations
71
72ARRAYINLINE unsigned
73array_num(const struct array *a)
74{
75	return a->num;
76}
77
78ARRAYINLINE void *
79array_get(const struct array *a, unsigned index_)
80{
81	arrayassert(index_ < a->num);
82	return a->v[index_];
83}
84
85ARRAYINLINE void
86array_set(const struct array *a, unsigned index_, void *val)
87{
88	arrayassert(index_ < a->num);
89	a->v[index_] = val;
90}
91
92ARRAYINLINE void
93array_add(struct array *a, void *val, unsigned *index_ret)
94{
95	unsigned index_ = a->num;
96	array_setsize(a, index_+1);
97	a->v[index_] = val;
98	if (index_ret != NULL) {
99		*index_ret = index_;
100	}
101}
102
103////////////////////////////////////////////////////////////
104// bits for declaring and defining typed arrays
105
106/*
107 * Usage:
108 *
109 * DECLARRAY_BYTYPE(foo, bar, INLINE) declares "struct foo", which is
110 * an array of pointers to "bar", plus the operations on it.
111 *
112 * DECLARRAY(foo, INLINE) is equivalent to
113 * DECLARRAY_BYTYPE(fooarray, struct foo, INLINE).
114 *
115 * DEFARRAY_BYTYPE and DEFARRAY are the same as DECLARRAY except that
116 * they define the operations.
117 *
118 * The argument INLINE can be used as follows:
119 *
120 * 1. For no inlining:
121 *    In foo.h:
122 *           DECLARRAY(foo, );
123 *    In foo.c:
124 *           DEFARRAY(foo, );
125 *
126 * 2. To be file-static:
127 *    In foo.c:
128 *           DECLARRAY(foo, static);
129 *           DEFARRAY(foo, static);
130 *
131 * 3. To inline using C99:
132 *    In foo.h:
133 *           DECLARRAY(foo, inline);
134 *           DEFARRAY(foo, inline);
135 *
136 * 4. To inline with old gcc:
137 *    In foo.h:
138 *           #ifndef FOO_INLINE
139 *           #define FOO_INLINE extern inline
140 *           #endif
141 *           DECLARRAY(foo, );
142 *           DEFARRAY(foo, FOO_INLINE);
143 *    In foo.c:
144 *           #define FOO_INLINE
145 *           #include "foo.h"
146 *
147 * 5. To inline such that it works both with old gcc and C99:
148 *    In foo.h:
149 *           #ifndef FOO_INLINE
150 *           #define FOO_INLINE extern inline
151 *           #endif
152 *           DECLARRAY(foo, FOO_INLINE);
153 *           DEFARRAY(foo, FOO_INLINE);
154 *    In foo.c:
155 *           #define FOO_INLINE
156 *           #include "foo.h"
157 *
158 * The mechanism in case (4) ensures that an externally linkable
159 * definition exists.
160 */
161
162#define DECLARRAY_BYTYPE(ARRAY, T, INLINE) \
163	struct ARRAY {							\
164		struct array arr;					\
165	};								\
166									\
167	INLINE struct ARRAY *ARRAY##_create(void);			\
168	INLINE void ARRAY##_destroy(struct ARRAY *a);			\
169	INLINE void ARRAY##_init(struct ARRAY *a);			\
170	INLINE void ARRAY##_cleanup(struct ARRAY *a);			\
171	INLINE unsigned ARRAY##_num(const struct ARRAY *a);		\
172	INLINE T *ARRAY##_get(const struct ARRAY *a, unsigned index_);	\
173	INLINE void ARRAY##_set(struct ARRAY *a, unsigned index_, T *val); \
174	INLINE void ARRAY##_setsize(struct ARRAY *a, unsigned num);	\
175	INLINE void ARRAY##_add(struct ARRAY *a, T *val, unsigned *index_ret);\
176	INLINE void ARRAY##_insert(struct ARRAY *a, unsigned index_);	\
177	INLINE void ARRAY##_remove(struct ARRAY *a, unsigned index_)
178
179
180#define DEFARRAY_BYTYPE(ARRAY, T, INLINE) \
181	INLINE void						\
182	ARRAY##_init(struct ARRAY *a)				\
183	{							\
184		array_init(&a->arr);				\
185	}							\
186								\
187	INLINE void						\
188	ARRAY##_cleanup(struct ARRAY *a)			\
189	{							\
190		array_cleanup(&a->arr);				\
191	}							\
192								\
193	INLINE struct						\
194	ARRAY *ARRAY##_create(void)				\
195	{							\
196		struct ARRAY *a;				\
197								\
198		a = domalloc(sizeof(*a));			\
199		ARRAY##_init(a);				\
200		return a;					\
201	}							\
202								\
203	INLINE void						\
204	ARRAY##_destroy(struct ARRAY *a)			\
205	{							\
206		ARRAY##_cleanup(a);				\
207		dofree(a, sizeof(*a));				\
208	}							\
209								\
210	INLINE unsigned						\
211	ARRAY##_num(const struct ARRAY *a)			\
212	{							\
213		return array_num(&a->arr);			\
214	}							\
215								\
216	INLINE T *						\
217	ARRAY##_get(const struct ARRAY *a, unsigned index_)	\
218	{				 			\
219		return (T *)array_get(&a->arr, index_);		\
220	}							\
221								\
222	INLINE void						\
223	ARRAY##_set(struct ARRAY *a, unsigned index_, T *val)	\
224	{				 			\
225		array_set(&a->arr, index_, (void *)val);	\
226	}							\
227								\
228	INLINE void						\
229	ARRAY##_setsize(struct ARRAY *a, unsigned num)		\
230	{				 			\
231		array_setsize(&a->arr, num);			\
232	}							\
233								\
234	INLINE void						\
235	ARRAY##_add(struct ARRAY *a, T *val, unsigned *ret)	\
236	{				 			\
237		array_add(&a->arr, (void *)val, ret);		\
238	}							\
239								\
240	INLINE void						\
241	ARRAY##_insert(struct ARRAY *a, unsigned index_)	\
242	{				 			\
243		array_insert(&a->arr, index_);			\
244	}							\
245								\
246	INLINE void						\
247	ARRAY##_remove(struct ARRAY *a, unsigned index_)	\
248	{				 			\
249		array_remove(&a->arr, index_);			\
250	}
251
252#define DECLARRAY(T, INLINE) DECLARRAY_BYTYPE(T##array, struct T, INLINE)
253#define DEFARRAY(T, INLINE) DEFARRAY_BYTYPE(T##array, struct T, INLINE)
254
255#define DESTROYALL_ARRAY(T, INLINE) \
256	INLINE void T##array_destroyall(struct T##array *arr);	\
257							\
258	INLINE void					\
259	T##array_destroyall(struct T##array *arr)	\
260	{						\
261		unsigned i, num;			\
262		struct T *t;				\
263							\
264		num = T##array_num(arr);		\
265		for (i=0; i<num; i++) {			\
266			t = T##array_get(arr, i);	\
267			T##_destroy(t);			\
268		}					\
269		T##array_setsize(arr, 0);		\
270	}
271
272
273////////////////////////////////////////////////////////////
274// basic array types
275
276DECLARRAY_BYTYPE(stringarray, char, ARRAYINLINE);
277DEFARRAY_BYTYPE(stringarray, char, ARRAYINLINE);
278
279#endif /* ARRAY_H */
280