array.h revision 1.2
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#define ARRAYS_CHECKED
34
35#ifdef ARRAYS_CHECKED
36#include <assert.h>
37#define arrayassert assert
38#else
39#define arrayassert(x) ((void)(x))
40#endif
41
42////////////////////////////////////////////////////////////
43// type and base operations
44
45struct array {
46	void **v;
47	unsigned num, max;
48};
49
50struct array *array_create(void);
51void array_destroy(struct array *);
52void array_init(struct array *);
53void array_cleanup(struct array *);
54unsigned array_num(const struct array *);
55void *array_get(const struct array *, unsigned index_);
56void array_set(const struct array *, unsigned index_, void *val);
57int array_setsize(struct array *, unsigned num);
58int array_add(struct array *, void *val, unsigned *index_ret);
59int array_insert(struct array *a, unsigned index_);
60void array_remove(struct array *a, unsigned index_);
61
62////////////////////////////////////////////////////////////
63// inlining for base operations
64
65#ifndef ARRAYINLINE
66#define ARRAYINLINE __c99inline
67#endif
68
69ARRAYINLINE unsigned
70array_num(const struct array *a)
71{
72	return a->num;
73}
74
75ARRAYINLINE void *
76array_get(const struct array *a, unsigned index_)
77{
78	arrayassert(index_ < a->num);
79	return a->v[index_];
80}
81
82ARRAYINLINE void
83array_set(const struct array *a, unsigned index_, void *val)
84{
85	arrayassert(index_ < a->num);
86	a->v[index_] = val;
87}
88
89ARRAYINLINE int
90array_add(struct array *a, void *val, unsigned *index_ret)
91{
92	unsigned index_ = a->num;
93	if (array_setsize(a, index_+1)) {
94		return -1;
95	}
96	a->v[index_] = val;
97	if (index_ret != NULL) {
98		*index_ret = index_;
99	}
100	return 0;
101}
102
103////////////////////////////////////////////////////////////
104// bits for declaring and defining typed arrays
105
106/*
107 * Usage:
108 *
109 * DECLARRAY_BYTYPE(foo, bar) declares "struct foo", which is
110 * an array of pointers to "bar", plus the operations on it.
111 *
112 * DECLARRAY(foo) is equivalent to DECLARRAY_BYTYPE(fooarray, struct foo).
113 *
114 * DEFARRAY_BYTYPE and DEFARRAY are the same as DECLARRAY except that
115 * they define the operations, and both take an extra argument INLINE.
116 * For C99 this should be INLINE in header files and empty in the
117 * master source file, the same as the usage of ARRAYINLINE above and
118 * in array.c.
119 *
120 * Example usage in e.g. item.h of some game:
121 *
122 * DECLARRAY_BYTYPE(stringarray, char);
123 * DECLARRAY(potion);
124 * DECLARRAY(sword);
125 *
126 * #ifndef ITEMINLINE
127 * #define ITEMINLINE INLINE
128 * #endif
129 *
130 * DEFARRAY_BYTYPE(stringarray, char, ITEMINLINE);
131 * DEFARRAY(potion, ITEMINLINE);
132 * DEFARRAY(sword, ITEMINLINE);
133 *
134 * Then item.c would do "#define ITEMINLINE" before including item.h.
135 */
136
137#define DECLARRAY_BYTYPE(ARRAY, T) \
138	struct ARRAY {						\
139		struct array arr;				\
140	};							\
141								\
142	struct ARRAY *ARRAY##_create(void);			\
143	void ARRAY##_destroy(struct ARRAY *a);			\
144	void ARRAY##_init(struct ARRAY *a);			\
145	void ARRAY##_cleanup(struct ARRAY *a);			\
146	unsigned ARRAY##_num(const struct ARRAY *a);		\
147	T *ARRAY##_get(const struct ARRAY *a, unsigned index_);	\
148	void ARRAY##_set(struct ARRAY *a, unsigned index_, T *val); \
149	int ARRAY##_setsize(struct ARRAY *a, unsigned num);	\
150	int ARRAY##_add(struct ARRAY *a, T *val, unsigned *index_ret); \
151	int ARRAY##_insert(struct ARRAY *a, unsigned index_);	\
152	void ARRAY##_remove(struct ARRAY *a, unsigned index_)
153
154
155#define DEFARRAY_BYTYPE(ARRAY, T, INLINE) \
156	INLINE void						\
157	ARRAY##_init(struct ARRAY *a)				\
158	{							\
159		array_init(&a->arr);				\
160	}							\
161								\
162	INLINE void						\
163	ARRAY##_cleanup(struct ARRAY *a)			\
164	{							\
165		array_cleanup(&a->arr);				\
166	}							\
167								\
168	INLINE struct						\
169	ARRAY *ARRAY##_create(void)				\
170	{							\
171		struct ARRAY *a;				\
172								\
173		a  = malloc(sizeof(*a));			\
174		if (a == NULL) {				\
175			return NULL;				\
176		}						\
177		ARRAY##_init(a);				\
178		return a;					\
179	}							\
180								\
181	INLINE void						\
182	ARRAY##_destroy(struct ARRAY *a)			\
183	{							\
184		ARRAY##_cleanup(a);				\
185		free(a);					\
186	}							\
187								\
188	INLINE unsigned						\
189	ARRAY##_num(const struct ARRAY *a)			\
190	{							\
191		return array_num(&a->arr);			\
192	}							\
193								\
194	INLINE T *						\
195	ARRAY##_get(const struct ARRAY *a, unsigned index_)	\
196	{				 			\
197		return (T *)array_get(&a->arr, index_);		\
198	}							\
199								\
200	INLINE void						\
201	ARRAY##_set(struct ARRAY *a, unsigned index_, T *val)	\
202	{				 			\
203		array_set(&a->arr, index_, (void *)val);	\
204	}							\
205								\
206	INLINE int						\
207	ARRAY##_setsize(struct ARRAY *a, unsigned num)		\
208	{				 			\
209		return array_setsize(&a->arr, num);		\
210	}							\
211								\
212	INLINE int						\
213	ARRAY##_add(struct ARRAY *a, T *val, unsigned *ret)	\
214	{				 			\
215		return array_add(&a->arr, (void *)val, ret);	\
216	}							\
217								\
218	INLINE int						\
219	ARRAY##_insert(struct ARRAY *a, unsigned index_)	\
220	{				 			\
221		return array_insert(&a->arr, index_);		\
222	}							\
223								\
224	INLINE void						\
225	ARRAY##_remove(struct ARRAY *a, unsigned index_)	\
226	{				 			\
227		return array_remove(&a->arr, index_);		\
228	}
229
230#define DECLARRAY(T) DECLARRAY_BYTYPE(T##array, struct T)
231#define DEFARRAY(T, INLINE) DEFARRAY_BYTYPE(T##array, struct T, INLINE)
232
233////////////////////////////////////////////////////////////
234// basic array types
235
236DECLARRAY_BYTYPE(stringarray, char);
237DEFARRAY_BYTYPE(stringarray, char, ARRAYINLINE);
238
239#endif /* ARRAY_H */
240