1 /* $Id$ */
2 
3 /*
4  * Copyright (c) 2006 Nicholas Marriott <nicholas.marriott@gmail.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #ifndef ARRAY_H
20 #define ARRAY_H
21 
22 #define ARRAY_INITIALIZER { NULL, 0, 0 }
23 
24 #define ARRAY_DECL(n, c)						\
25 	struct n {							\
26 		c	*list;						\
27 		u_int	 num;						\
28 		size_t	 space;						\
29 	}
30 
31 #define ARRAY_ITEM(a, i) ((a)->list[i])
32 #define ARRAY_ITEMSIZE(a) (sizeof *(a)->list)
33 #define ARRAY_INITIALSPACE(a) (10 * ARRAY_ITEMSIZE(a))
34 
35 #define ARRAY_ENSURE(a, n) do {						\
36 	if (UINT_MAX - (n) < (a)->num)					\
37 		fatalx("number too big");				\
38 	if (SIZE_MAX / ((a)->num + (n)) < ARRAY_ITEMSIZE(a))		\
39 		fatalx("size too big");					\
40 	if ((a)->space == 0) {						\
41 		(a)->space = ARRAY_INITIALSPACE(a);			\
42 		(a)->list = xrealloc((a)->list, 1, (a)->space);		\
43 	}								\
44 	while ((a)->space <= ((a)->num + (n)) * ARRAY_ITEMSIZE(a)) {	\
45 		(a)->list = xrealloc((a)->list, 2, (a)->space);		\
46 		(a)->space *= 2;					\
47 	}								\
48 } while (0)
49 
50 #define ARRAY_EMPTY(a) (((void *) (a)) == NULL || (a)->num == 0)
51 #define ARRAY_LENGTH(a) ((a)->num)
52 #define ARRAY_DATA(a) ((a)->list)
53 
54 #define ARRAY_FIRST(a) ARRAY_ITEM(a, 0)
55 #define ARRAY_LAST(a) ARRAY_ITEM(a, (a)->num - 1)
56 
57 #define ARRAY_INIT(a) do {						\
58 	(a)->num = 0;							\
59 	(a)->list = NULL;						\
60 	(a)->space = 0;							\
61 } while (0)
62 #define ARRAY_CLEAR(a) do {						\
63 	(a)->num = 0;							\
64 } while (0)
65 
66 #define ARRAY_SET(a, i, s) do {						\
67 	(a)->list[i] = s;						\
68 } while (0)
69 
70 #define ARRAY_ADD(a, s) do {						\
71 	ARRAY_ENSURE(a, 1);						\
72 	(a)->list[(a)->num] = s;					\
73 	(a)->num++;							\
74 } while (0)
75 #define ARRAY_INSERT(a, i, s) do {					\
76 	ARRAY_ENSURE(a, 1);						\
77 	if ((i) < (a)->num) {						\
78 		memmove((a)->list + (i) + 1, (a)->list + (i),		\
79 		    ARRAY_ITEMSIZE(a) * ((a)->num - (i)));		\
80 	}								\
81 	(a)->list[i] = s;						\
82 	(a)->num++;							\
83 } while (0)
84 #define ARRAY_REMOVE(a, i) do {						\
85 	if ((i) < (a)->num - 1) {					\
86 		memmove((a)->list + (i), (a)->list + (i) + 1,		\
87 		    ARRAY_ITEMSIZE(a) * ((a)->num - (i) - 1));		\
88 	}								\
89 	(a)->num--;							\
90 	if ((a)->num == 0)						\
91 		ARRAY_FREE(a);						\
92 } while (0)
93 
94 #define ARRAY_EXPAND(a, n) do {						\
95 	ARRAY_ENSURE(a, n);						\
96 	(a)->num += n;							\
97 } while (0)
98 #define ARRAY_TRUNC(a, n) do {						\
99 	if ((a)->num > n)						\
100 		(a)->num -= n;						\
101 	else								\
102 		ARRAY_FREE(a);						\
103 } while (0)
104 
105 #define ARRAY_CONCAT(a, b) do {						\
106 	ARRAY_ENSURE(a, (b)->num);					\
107 	memcpy((a)->list + (a)->num, (b)->list, (b)->num * ARRAY_ITEMSIZE(a)); \
108 	(a)->num += (b)->num;						\
109 } while (0)
110 
111 #define ARRAY_FREE(a) do {						\
112 	if ((a)->list != NULL)						\
113 		xfree((a)->list);					\
114 	ARRAY_INIT(a);							\
115 } while (0)
116 #define ARRAY_FREEALL(a) do {						\
117 	ARRAY_FREE(a);							\
118 	xfree(a);							\
119 } while (0)
120 
121 #endif
122