/*-1* Copyright (c) 2009 The NetBSD Foundation, Inc.2* All rights reserved.3*4* This code is derived from software contributed to The NetBSD Foundation5* by David A. Holland.6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions9* are met:10* 1. Redistributions of source code must retain the above copyright11* notice, this list of conditions and the following disclaimer.12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS17* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED18* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR19* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS20* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR21* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF22* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS23* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN24* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)25* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE26* POSSIBILITY OF SUCH DAMAGE.27*/2829#ifndef _ARRAY_H_30#define _ARRAY_H_3132#define ARRAYS_CHECKED3334#ifdef ARRAYS_CHECKED35#define ARRAYASSERT KASSERT36#else37#define ARRAYASSERT(x) ((void)(x))38#endif3940/*41* Base array type (resizeable array of void pointers) and operations.42*43* create - allocate an array.44* destroy - destroy an allocated array.45* init - initialize an array in space externally allocated.46* cleanup - clean up an array in space exteranlly allocated.47* num - return number of elements in array.48* get - return element no. INDEX.49* set - set element no. INDEX to VAL.50* setsize - change size to NUM elements; may fail and return error.51* add - append VAL to end of array; return its index in INDEX_RET if52* INDEX_RET isn't null; may fail and return error.53* remove - excise entry INDEX and slide following entries down to54* close the resulting gap.55*56* Note that expanding an array with setsize doesn't initialize the new57* elements. (Usually the caller is about to store into them anyway.)58*/5960struct array {61void **v;62unsigned num, max;63};6465struct array *array_create(void);66void array_destroy(struct array *);67void array_init(struct array *);68void array_cleanup(struct array *);69unsigned array_num(const struct array *);70void *array_get(const struct array *, unsigned index);71void array_set(const struct array *, unsigned index, void *val);72int array_setsize(struct array *, unsigned num);73int array_add(struct array *, void *val, unsigned *index_ret);74void array_remove(struct array *, unsigned index);7576/*77* Inlining for base operations78*/7980#ifndef ARRAYINLINE81#define ARRAYINLINE INLINE82#endif8384ARRAYINLINE unsigned85array_num(const struct array *a)86{87return a->num;88}8990ARRAYINLINE void *91array_get(const struct array *a, unsigned index)92{93ARRAYASSERT(index < a->num);94return a->v[index];95}9697ARRAYINLINE void98array_set(const struct array *a, unsigned index, void *val)99{100ARRAYASSERT(index < a->num);101a->v[index] = val;102}103104ARRAYINLINE int105array_add(struct array *a, void *val, unsigned *index_ret)106{107unsigned index;108int ret;109110index = a->num;111ret = array_setsize(a, index+1);112if (ret) {113return ret;114}115a->v[index] = val;116if (index_ret != NULL) {117*index_ret = index;118}119return 0;120}121122/*123* Bits for declaring and defining typed arrays.124*125* Usage:126*127* DECLARRAY_BYTYPE(foo, bar) declares "struct foo", which is128* an array of pointers to "bar", plus the operations on it.129*130* DECLARRAY(foo) is equivalent to DECLARRAY_BYTYPE(fooarray, struct foo).131*132* DEFARRAY_BYTYPE and DEFARRAY are the same as DECLARRAY except that133* they define the operations, and both take an extra argument INLINE.134* For C99 this should be INLINE in header files and empty in the135* master source file, the same as the usage of ARRAYINLINE above and136* in array.c.137*138* Example usage in e.g. item.h of some game:139*140* DECLARRAY_BYTYPE(stringarray, char);141* DECLARRAY(potion);142* DECLARRAY(sword);143*144* #ifndef ITEMINLINE145* #define ITEMINLINE INLINE146* #endif147*148* DEFARRAY_BYTYPE(stringarray, char, ITEMINLINE);149* DEFARRAY(potion, ITEMINLINE);150* DEFARRAY(sword, ITEMINLINE);151*152* Then item.c would do "#define ITEMINLINE" before including item.h.153*154* This creates types "struct stringarray", "struct potionarray",155* and "struct swordarray", with operations such as "swordarray_num".156*157* The operations on typed arrays are the same as the operations on158* the base array, except typed.159*/160161#define DECLARRAY_BYTYPE(ARRAY, T) \162struct ARRAY { \163struct array arr; \164}; \165\166struct ARRAY *ARRAY##_create(void); \167void ARRAY##_destroy(struct ARRAY *a); \168void ARRAY##_init(struct ARRAY *a); \169void ARRAY##_cleanup(struct ARRAY *a); \170unsigned ARRAY##_num(const struct ARRAY *a); \171T *ARRAY##_get(const struct ARRAY *a, unsigned index); \172void ARRAY##_set(struct ARRAY *a, unsigned index, T *val); \173int ARRAY##_setsize(struct ARRAY *a, unsigned num); \174int ARRAY##_add(struct ARRAY *a, T *val, unsigned *index_ret); \175void ARRAY##_remove(struct ARRAY *a, unsigned index)176177#define DEFARRAY_BYTYPE(ARRAY, T, INLINE) \178INLINE struct ARRAY * \179ARRAY##_create(void) \180{ \181struct ARRAY *a = kmalloc(sizeof(*a)); \182if (a == NULL) { \183return NULL; \184} \185array_init(&a->arr); \186return a; \187} \188\189INLINE void \190ARRAY##_destroy(struct ARRAY *a) \191{ \192array_cleanup(&a->arr); \193kfree(a); \194} \195\196INLINE void \197ARRAY##_init(struct ARRAY *a) \198{ \199array_init(&a->arr); \200} \201\202INLINE void \203ARRAY##_cleanup(struct ARRAY *a) \204{ \205array_cleanup(&a->arr); \206} \207\208INLINE unsigned \209ARRAY##_num(const struct ARRAY *a) \210{ \211return array_num(&a->arr); \212} \213\214INLINE T * \215ARRAY##_get(const struct ARRAY *a, unsigned index) \216{ \217return (T *)array_get(&a->arr, index); \218} \219\220INLINE void \221ARRAY##_set(struct ARRAY *a, unsigned index, T *val) \222{ \223array_set(&a->arr, index, (void *)val); \224} \225\226INLINE int \227ARRAY##_setsize(struct ARRAY *a, unsigned num) \228{ \229return array_setsize(&a->arr, num); \230} \231\232INLINE int \233ARRAY##_add(struct ARRAY *a, T *val, unsigned *index_ret) \234{ \235return array_add(&a->arr, (void *)val, index_ret); \236} \237\238INLINE void \239ARRAY##_remove(struct ARRAY *a, unsigned index) \240{ \241return array_remove(&a->arr, index); \242}243244#define DECLARRAY(T) DECLARRAY_BYTYPE(T##array, struct T)245#define DEFARRAY(T, INLINE) DEFARRAY_BYTYPE(T##array, struct T, INLINE)246247/*248* This is how you declare an array of strings; it works out as249* an array of pointers to char.250*/251DECLARRAY_BYTYPE(stringarray, char);252DEFARRAY_BYTYPE(stringarray, char, ARRAYINLINE);253254255#endif /* ARRAY_H */256257258