]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - cddl/contrib/opensolaris/cmd/sgs/include/alist.h
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / cddl / contrib / opensolaris / cmd / sgs / include / alist.h
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Define an Alist, a list maintained as a reallocable array, and a for() loop
27  * macro to generalize its traversal.  Note that the array can be reallocated
28  * as it is being traversed, thus the offset of each element is recomputed from
29  * the start of the structure.
30  */
31
32 #ifndef _ALIST_H
33 #define _ALIST_H
34
35 #pragma ident   "%Z%%M% %I%     %E% SMI"
36
37 #ifdef  __cplusplus
38 extern "C" {
39 #endif
40
41 #include <sys/types.h>
42 #if defined(sun)
43 #include <sys/machelf.h>
44 #else
45 #include <sys/elf.h>
46 #endif
47
48 /*
49  * An Alist implements array lists. The functionality is similar to
50  * that of a linked list. However, an Alist is represented by a single
51  * contigious allocation of memory. The head of the memory is a header
52  * that contains control information for the list. Following the header
53  * is an array used to hold the user data. In the type definitions that
54  * follow, we define these as an array with a single element, but when
55  * we allocate the memory, we actually allocate the amount of memory needed.
56  *
57  * There are two "flavors" of array list:
58  *
59  *      Alist - Contain arbitrary data, usually structs.
60  *      APlist - Contain pointers to data allocated elsewhere.
61  *
62  * This differentiation is useful, because pointer lists are heavily
63  * used, and support a slightly different set of operations that are
64  * unique to their purpose.
65  *
66  * Array lists are initially represented by a NULL pointer. The memory
67  * for the list is only allocated if an item is inserted. This is very
68  * efficient for data structures that may or may not be needed for a
69  * given linker operation --- you only pay for what you use. In addition:
70  *
71  *      - Array lists grow as needed (memory is reallocated as necessary)
72  *      - Data is kept contiguously (no unused holes in between elements)
73  *              at the beginning of the data area. This locality has
74  *              good cache behavior, as access to adjacent items are
75  *              highly likely to be in the same page of memory.
76  *      - Insert/Delete operations at the end of the list are very
77  *              efficient. However, insert/delete operations elsewhere
78  *              will cause a relatively expensive overlapped memory
79  *              copy of the data following the insert/delete location.
80  *      - As with any generic memory alloctor (i.e. malloc()/free()),
81  *              array lists are not type safe for the data they contain.
82  *              Data is managed as (void *) pointers to data of a given
83  *              length, so the Alist module cannot prevent the caller from
84  *              inserting/extracting the wrong type of data. The caller
85  *              must guard against this.
86  *      - To free an array list, simply call the standard free() function
87  *              on the list pointer.
88  */
89
90
91
92 /*
93  * Aliste is used to represent list indexes, offsets, and sizes.
94  */
95 typedef size_t  Aliste;
96
97
98
99 /*
100  * Alist is used to hold non-pointer items --- usually structs:
101  *      - There must be an even number of Aliste fields before the
102  *              al_data field. This ensures that al_data will have
103  *              an alignment of 8, no matter whether sizeof(Aliste)
104  *              is 4 or 8. That means that al_data will have sufficient
105  *              alignment for any use, just like memory allocated via
106  *              malloc().
107  *      - al_nitems and al_next are redundant, in that they are
108  *              directly related:
109  *                      al_next = al_nitems * al_size
110  *              We do this to make ALIST_TRAVERSE_BYOFFSET maximally
111  *              efficient. This doesn't waste space, because of the
112  *              requirement to have an even # of Alist fields (above).
113  *
114  * Note that Alists allow the data to be referenced by 0 based array
115  * index, or by their byte offset from the start of the Alist memory
116  * allocation. The index form is preferred for most use, as it is simpler.
117  * However, by-offset access is used by rtld link maps, and this ability
118  * is convenient in that case.
119  */
120 typedef struct {
121         Aliste          al_arritems;    /* # of items in al_data allocation */
122         Aliste          al_nitems;      /* # items (index of next avail item) */
123         Aliste          al_next;        /* offset of next available al_data[] */
124         Aliste          al_size;        /* size of each al_data[] item */
125         void            *al_data[1];    /* data (can grow) */
126 } Alist;
127
128 /*
129  * APlist is a variant of Alist that contains pointers. There are several
130  * benefits to this special type:
131  *      - API is simpler
132  *      - Pointers are used directly, instead of requiring a
133  *              pointer-to-pointer double indirection.
134  *      - The implementation is slightly more efficient.
135  *      - Operations that make particular sense for pointers
136  *              can be supported without confusing the API for the
137  *              regular Alists.
138  */
139 typedef struct {
140         Aliste          apl_arritems;   /* # of items in apl_data allocation */
141         Aliste          apl_nitems;     /* # items (index of next avail item) */
142         void            *apl_data[1];   /* data area: (arrcnt * size) bytes */
143 } APlist;
144
145
146 /*
147  * The ALIST_OFF_DATA and APLIST_OFF_DATA macros give the byte offset
148  * from the start of an array list to the first byte of the data area
149  * used to hold user data. The same trick used by the standard offsetof()
150  * macro is used.
151  */
152 #define ALIST_OFF_DATA  ((size_t)(((Alist *)0)->al_data))
153 #define APLIST_OFF_DATA ((size_t)(((APlist *)0)->apl_data))
154
155
156 /*
157  * The TRAVERSE macros are intended to be used within a for(), and
158  * cause the resulting loop to iterate over each item in the loop,
159  * in order.
160  *      ALIST_TRAVERSE: Traverse over the items in an Alist,
161  *              using the zero based item array index to refer to
162  *              each item.
163  *      ALIST_TRAVERSE_BY_OFFSET: Traverse over the items in an
164  *              Alist using the byte offset from the head of the
165  *              Alist pointer to refer to each item. It should be noted
166  *              that the first such offset is given by ALIST_OFF_DATA,
167  *              and as such, there will never be a 0 offset. Some code
168  *              uses this fact to treat 0 as a reserved value with
169  *              special meaning.
170  *
171  *              By-offset access is convenient for some parts of
172  *              rtld, where a value of 0 is used to indicate an
173  *              uninitialized link map control.
174  *
175  *      APLIST_TRAVERSE: Traverse over the pointers in an APlist, using
176  *              the zero based item array index to refer to each pointer.
177  */
178
179 /*
180  * Within the loop:
181  *
182  *      LIST - Pointer to Alist structure for list
183  *      IDX - The current item index
184  *      OFF - The current item offset
185  *      DATA - Pointer to item
186  */
187 #define ALIST_TRAVERSE(LIST, IDX, DATA) \
188         (IDX) = 0, \
189         ((LIST) != NULL) && ((DATA) = (void *)(LIST)->al_data); \
190         \
191         ((LIST) != NULL) && ((IDX) < (LIST)->al_nitems); \
192         \
193         (IDX)++, \
194         (DATA) = (void *) (((LIST)->al_size * (IDX)) + (char *)(LIST)->al_data)
195
196 #define ALIST_TRAVERSE_BY_OFFSET(LIST, OFF, DATA) \
197         (((LIST) != NULL) && ((OFF) = ALIST_OFF_DATA) && \
198         (((DATA) = (void *)((char *)(LIST) + (OFF))))); \
199         \
200         (((LIST) != NULL) && ((OFF) < (LIST)->al_next)); \
201         \
202         (((OFF) += ((LIST)->al_size)), \
203         ((DATA) = (void *)((char *)(LIST) + (OFF))))
204
205 /*
206  * Within the loop:
207  *
208  *      LIST - Pointer to APlist structure for list
209  *      IDX - The current item index
210  *      PTR - item value
211  *
212  * Note that this macro is designed to ensure that PTR retains the
213  * value of the final pointer in the list after exiting the for loop,
214  * and to avoid dereferencing an out of range address. This is done by
215  * doing the dereference in the middle expression, using the comma
216  * operator to ensure that a NULL pointer won't stop the loop.
217  */
218 #define APLIST_TRAVERSE(LIST, IDX, PTR) \
219         (IDX) = 0; \
220         \
221         ((LIST) != NULL) && ((IDX) < (LIST)->apl_nitems) && \
222         (((PTR) = ((LIST)->apl_data)[IDX]), 1); \
223         \
224         (IDX)++
225
226
227 /*
228  * Possible values returned by aplist_test()
229  */
230 typedef enum {
231         ALE_ALLOCFAIL = 0,      /* Memory allocation error */
232         ALE_EXISTS =    1,      /* alist entry already exists */
233         ALE_NOTFND =    2,      /* item not found and insert not required */
234         ALE_CREATE =    3       /* alist entry created */
235 } aplist_test_t;
236
237
238 /*
239  * Access to an Alist item by index or offset. This is needed because the
240  * size of an item in an Alist is not known by the C compiler, and we
241  * have to do the indexing arithmetic explicitly.
242  *
243  * For an APlist, index the apl_data field directly --- No macro is needed.
244  */
245 #define alist_item(_lp, _idx) \
246         ((void *)(ALIST_OFF_DATA + ((_idx) * (_lp)->al_size) + (char *)(_lp)))
247 #define alist_item_by_offset(_lp, _off) \
248         ((void *)((_off) + (char *)(_lp)))
249
250 /*
251  * # of items currently found in a list. These macros handle the case
252  * where the list has not been allocated yet.
253  */
254 #define alist_nitems(_lp) (((_lp) == NULL) ? 0 : (_lp)->al_nitems)
255 #define aplist_nitems(_lp) (((_lp) == NULL) ? 0 : (_lp)->apl_nitems)
256
257
258 extern void             *alist_append(Alist **, const void *, size_t, Aliste);
259 extern void             alist_delete(Alist *, Aliste *);
260 extern void             alist_delete_by_offset(Alist *, Aliste *);
261 extern void             *alist_insert(Alist **, const void *, size_t,
262                             Aliste, Aliste);
263 extern void             *alist_insert_by_offset(Alist **, const void *, size_t,
264                             Aliste, Aliste);
265 extern void             alist_reset(Alist *);
266
267
268 extern void             *aplist_append(APlist **, const void *, Aliste);
269 extern void             aplist_delete(APlist *, Aliste *);
270 extern int              aplist_delete_value(APlist *, const void *);
271 extern void             *aplist_insert(APlist **, const void *,
272                             Aliste, Aliste idx);
273 extern void             aplist_reset(APlist *);
274 extern aplist_test_t    aplist_test(APlist **, const void *, Aliste);
275
276 #ifdef  __cplusplus
277 }
278 #endif
279
280 #endif /* _ALIST_H */