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 45 struct array { 46 void **v; 47 unsigned num, max; 48 }; 49 50 struct array *array_create(void); 51 void array_destroy(struct array *); 52 void array_init(struct array *); 53 void array_cleanup(struct array *); 54 unsigned array_num(const struct array *); 55 void *array_get(const struct array *, unsigned index_); 56 void array_set(const struct array *, unsigned index_, void *val); 57 int array_setsize(struct array *, unsigned num); 58 int array_add(struct array *, void *val, unsigned *index_ret); 59 int array_insert(struct array *a, unsigned index_); 60 void array_remove(struct array *a, unsigned index_); 61 62 //////////////////////////////////////////////////////////// 63 // inlining for base operations 64 65 #ifndef ARRAYINLINE 66 #define ARRAYINLINE extern __attribute__((__gnu_inline__)) __inline 67 #endif 68 69 ARRAYINLINE unsigned 70 array_num(const struct array *a) 71 { 72 return a->num; 73 } 74 75 ARRAYINLINE void * 76 array_get(const struct array *a, unsigned index_) 77 { 78 arrayassert(index_ < a->num); 79 return a->v[index_]; 80 } 81 82 ARRAYINLINE void 83 array_set(const struct array *a, unsigned index_, void *val) 84 { 85 arrayassert(index_ < a->num); 86 a->v[index_] = val; 87 } 88 89 ARRAYINLINE int 90 array_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 236 DECLARRAY_BYTYPE(stringarray, char); 237 DEFARRAY_BYTYPE(stringarray, char, ARRAYINLINE); 238 239 #endif /* ARRAY_H */ 240