1 | /** @file
|
---|
2 | * STL-inspired vector implementation in C
|
---|
3 | * @note functions in this file are inline to prevent warnings about
|
---|
4 | * unused static functions. I assume that in this day and age a
|
---|
5 | * compiler makes its own decisions about whether to actually
|
---|
6 | * inline a function.
|
---|
7 | * @note as this header is included in rdesktop-vrdp, we do not include other
|
---|
8 | * required header files here (to wit assert.h, err.h, mem.h and
|
---|
9 | * types.h). These must be included first. If this moves to iprt, we
|
---|
10 | * should write a wrapper around it doing that.
|
---|
11 | * @todo can we do more of the type checking at compile time somehow?
|
---|
12 | */
|
---|
13 |
|
---|
14 | /*
|
---|
15 | * Copyright (C) 2008-2010 Oracle Corporation
|
---|
16 | *
|
---|
17 | * This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
18 | * available from http://www.virtualbox.org. This file is free software;
|
---|
19 | * you can redistribute it and/or modify it under the terms of the GNU
|
---|
20 | * General Public License (GPL) as published by the Free Software
|
---|
21 | * Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
22 | * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
23 | * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
24 | */
|
---|
25 |
|
---|
26 | #ifndef MAIN_VECTOR_H
|
---|
27 | # define MAIN_VECTOR_H
|
---|
28 |
|
---|
29 | /*** Helper macros and deinitions ***/
|
---|
30 |
|
---|
31 | /** The unit by which the vector capacity is increased */
|
---|
32 | #define VECTOR_ALLOC_UNIT 16
|
---|
33 |
|
---|
34 | /** Calculate a hash of a string of tokens for sanity type checking */
|
---|
35 | #define VECTOR_TOKEN_HASH(token) \
|
---|
36 | ((unsigned) \
|
---|
37 | ( VECTOR_TOKEN_HASH4(token, 0) \
|
---|
38 | ^ VECTOR_TOKEN_HASH4(token, 4) \
|
---|
39 | ^ VECTOR_TOKEN_HASH4(token, 8) \
|
---|
40 | ^ VECTOR_TOKEN_HASH4(token, 12)))
|
---|
41 |
|
---|
42 | /** Helper macro for @a VECTOR_TOKEN_HASH */
|
---|
43 | #define VECTOR_TOKEN_HASH_VALUE(token, place, mul) \
|
---|
44 | (sizeof(#token) > place ? #token[place] * mul : 0)
|
---|
45 |
|
---|
46 | /** Helper macro for @a VECTOR_TOKEN_HASH */
|
---|
47 | #define VECTOR_TOKEN_HASH4(token, place) \
|
---|
48 | VECTOR_TOKEN_HASH_VALUE(token, place, 0x1) \
|
---|
49 | ^ VECTOR_TOKEN_HASH_VALUE(token, place + 1, 0x100) \
|
---|
50 | ^ VECTOR_TOKEN_HASH_VALUE(token, place + 2, 0x10000) \
|
---|
51 | ^ VECTOR_TOKEN_HASH_VALUE(token, place + 3, 0x1000000)
|
---|
52 |
|
---|
53 | /** Generic vector structure, used by @a VECTOR_OBJ and @a VECTOR_PTR */
|
---|
54 | #define VECTOR_STRUCT \
|
---|
55 | { \
|
---|
56 | /** The number of elements in the vector */ \
|
---|
57 | size_t mcElements; \
|
---|
58 | /** The current capacity of the vector */ \
|
---|
59 | size_t mcCapacity; \
|
---|
60 | /** The size of an element */ \
|
---|
61 | size_t mcbElement; \
|
---|
62 | /** Hash value of the element type */ \
|
---|
63 | unsigned muTypeHash; \
|
---|
64 | /** The elements themselves */ \
|
---|
65 | void *mpvaElements; \
|
---|
66 | /** Destructor for elements - takes a pointer to an element. */ \
|
---|
67 | void (*mpfnCleanup)(void *); \
|
---|
68 | }
|
---|
69 |
|
---|
70 | /*** Structure definitions ***/
|
---|
71 |
|
---|
72 | /** A vector of values or objects */
|
---|
73 | typedef struct VECTOR_OBJ VECTOR_STRUCT VECTOR_OBJ;
|
---|
74 |
|
---|
75 | /** A vector of pointer values. (A handy special case.) */
|
---|
76 | typedef struct VECTOR_PTR VECTOR_STRUCT VECTOR_PTR;
|
---|
77 |
|
---|
78 | /** Convenience macro for annotating the type of the vector. Unfortunately the
|
---|
79 | * type name is only cosmetic. */
|
---|
80 | /** @todo can we do something useful with the type? */
|
---|
81 | #define VECTOR_OBJ(type) VECTOR_OBJ
|
---|
82 |
|
---|
83 | /** Convenience macro for annotating the type of the vector. Unfortunately the
|
---|
84 | * type name is only cosmetic. */
|
---|
85 | #define VECTOR_PTR(type) VECTOR_PTR
|
---|
86 |
|
---|
87 | /*** Private helper functions and macros ***/
|
---|
88 |
|
---|
89 | #define VEC_GET_ELEMENT_OBJ(pvaElements, cbElement, cElement) \
|
---|
90 | ((void *)((char *)(pvaElements) + (cElement) * (cbElement)))
|
---|
91 |
|
---|
92 | #define VEC_GET_ELEMENT_PTR(pvaElements, cElement) \
|
---|
93 | (*(void **)VEC_GET_ELEMENT_OBJ(pvaElements, sizeof(void *), cElement))
|
---|
94 |
|
---|
95 | /** Default cleanup function that does nothing. */
|
---|
96 | DECLINLINE(void) vecNoCleanup(void *pvElement)
|
---|
97 | {
|
---|
98 | (void) pvElement;
|
---|
99 | }
|
---|
100 |
|
---|
101 | /** Expand an existing vector, implementation */
|
---|
102 | DECLINLINE(int) vecExpand(size_t *pcCapacity, void **ppvaElements,
|
---|
103 | size_t cbElement)
|
---|
104 | {
|
---|
105 | size_t cOldCap, cNewCap;
|
---|
106 | void *pRealloc;
|
---|
107 |
|
---|
108 | cOldCap = *pcCapacity;
|
---|
109 | cNewCap = cOldCap + VECTOR_ALLOC_UNIT;
|
---|
110 | pRealloc = RTMemRealloc(*ppvaElements, cNewCap * cbElement);
|
---|
111 | if (!pRealloc)
|
---|
112 | return VERR_NO_MEMORY;
|
---|
113 | *pcCapacity = cNewCap;
|
---|
114 | *ppvaElements = pRealloc;
|
---|
115 | return VINF_SUCCESS;
|
---|
116 | }
|
---|
117 |
|
---|
118 | /** Expand an existing vector */
|
---|
119 | #define VEC_EXPAND(pvec) vecExpand(&(pvec)->mcCapacity, &(pvec)->mpvaElements, \
|
---|
120 | (pvec)->mcbElement)
|
---|
121 |
|
---|
122 | /** Reset a vector, cleaning up all its elements. */
|
---|
123 | DECLINLINE(void) vecClearObj(VECTOR_OBJ *pvec)
|
---|
124 | {
|
---|
125 | unsigned i;
|
---|
126 |
|
---|
127 | for (i = 0; i < pvec->mcElements; ++i)
|
---|
128 | pvec->mpfnCleanup(VEC_GET_ELEMENT_OBJ(pvec->mpvaElements,
|
---|
129 | pvec->mcbElement, i));
|
---|
130 | pvec->mcElements = 0;
|
---|
131 | }
|
---|
132 |
|
---|
133 | /** Reset a pointer vector, cleaning up all its elements. */
|
---|
134 | DECLINLINE(void) vecClearPtr(VECTOR_PTR *pvec)
|
---|
135 | {
|
---|
136 | unsigned i;
|
---|
137 |
|
---|
138 | for (i = 0; i < pvec->mcElements; ++i)
|
---|
139 | pvec->mpfnCleanup(VEC_GET_ELEMENT_PTR(pvec->mpvaElements, i));
|
---|
140 | pvec->mcElements = 0;
|
---|
141 | }
|
---|
142 |
|
---|
143 | /** Clean up a vector */
|
---|
144 | DECLINLINE(void) vecCleanupObj(VECTOR_OBJ *pvec)
|
---|
145 | {
|
---|
146 | vecClearObj(pvec);
|
---|
147 | RTMemFree(pvec->mpvaElements);
|
---|
148 | pvec->mpvaElements = NULL;
|
---|
149 | }
|
---|
150 |
|
---|
151 | /** Clean up a pointer vector */
|
---|
152 | DECLINLINE(void) vecCleanupPtr(VECTOR_PTR *pvec)
|
---|
153 | {
|
---|
154 | vecClearPtr(pvec);
|
---|
155 | RTMemFree(pvec->mpvaElements);
|
---|
156 | pvec->mpvaElements = NULL;
|
---|
157 | }
|
---|
158 |
|
---|
159 | /** Initialise a vector structure, implementation */
|
---|
160 | #define VEC_INIT(pvec, cbElement, uTypeHash, pfnCleanup) \
|
---|
161 | pvec->mcElements = pvec->mcCapacity = 0; \
|
---|
162 | pvec->mcbElement = cbElement; \
|
---|
163 | pvec->muTypeHash = uTypeHash; \
|
---|
164 | pvec->mpfnCleanup = pfnCleanup ? pfnCleanup : vecNoCleanup; \
|
---|
165 | pvec->mpvaElements = NULL; \
|
---|
166 | return VEC_EXPAND(pvec);
|
---|
167 |
|
---|
168 | /** Initialise a vector. */
|
---|
169 | DECLINLINE(int) vecInitObj(VECTOR_OBJ *pvec, size_t cbElement,
|
---|
170 | unsigned uTypeHash, void (*pfnCleanup)(void *))
|
---|
171 | {
|
---|
172 | VEC_INIT(pvec, cbElement, uTypeHash, pfnCleanup)
|
---|
173 | }
|
---|
174 |
|
---|
175 | /** Initialise a pointer vector. */
|
---|
176 | DECLINLINE(int) vecInitPtr(VECTOR_PTR *pvec, size_t cbElement,
|
---|
177 | unsigned uTypeHash, void (*pfnCleanup)(void *))
|
---|
178 | {
|
---|
179 | VEC_INIT(pvec, cbElement, uTypeHash, pfnCleanup)
|
---|
180 | }
|
---|
181 |
|
---|
182 | /** Add an element onto the end of a vector */
|
---|
183 | DECLINLINE(int) vecPushBackObj(VECTOR_OBJ *pvec, unsigned uTypeHash,
|
---|
184 | void *pvElement)
|
---|
185 | {
|
---|
186 | int rc2;
|
---|
187 | AssertReturn(pvec->muTypeHash == uTypeHash, VERR_INVALID_PARAMETER);
|
---|
188 | if ( pvec->mcElements == pvec->mcCapacity
|
---|
189 | && RT_FAILURE((rc2 = VEC_EXPAND(pvec))))
|
---|
190 | return rc2;
|
---|
191 | memcpy(VEC_GET_ELEMENT_OBJ(pvec->mpvaElements, pvec->mcbElement,
|
---|
192 | pvec->mcElements), pvElement, pvec->mcbElement);
|
---|
193 | ++pvec->mcElements;
|
---|
194 | return VINF_SUCCESS;
|
---|
195 | }
|
---|
196 |
|
---|
197 | /** Add a pointer onto the end of a pointer vector */
|
---|
198 | DECLINLINE(int) vecPushBackPtr(VECTOR_PTR *pvec, unsigned uTypeHash,
|
---|
199 | void *pv)
|
---|
200 | {
|
---|
201 | int rc2;
|
---|
202 | AssertReturn(pvec->muTypeHash == uTypeHash, VERR_INVALID_PARAMETER);
|
---|
203 | if ( pvec->mcElements == pvec->mcCapacity
|
---|
204 | && RT_FAILURE((rc2 = VEC_EXPAND(pvec))))
|
---|
205 | return rc2;
|
---|
206 | VEC_GET_ELEMENT_PTR(pvec->mpvaElements, pvec->mcElements) = pv;
|
---|
207 | ++pvec->mcElements;
|
---|
208 | return VINF_SUCCESS;
|
---|
209 | }
|
---|
210 |
|
---|
211 | /*** Public interface macros ***/
|
---|
212 |
|
---|
213 | /**
|
---|
214 | * Initialise a vector structure.
|
---|
215 | * @returns iprt status code (VINF_SUCCESS or VERR_NO_MEMORY)
|
---|
216 | * @param pvec pointer to an uninitialised vector structure
|
---|
217 | * @param type the type of the objects in the vector. As this is
|
---|
218 | * hashed by the preprocessor use of space etc is
|
---|
219 | * important.
|
---|
220 | * @param pfnCleanup cleanup function (void (*pfn)(void *)) that is called
|
---|
221 | * on a pointer to a vector element when that element is
|
---|
222 | * dropped
|
---|
223 | */
|
---|
224 | #define VEC_INIT_OBJ(pvec, type, pfnCleanup) \
|
---|
225 | vecInitObj(pvec, sizeof(type), VECTOR_TOKEN_HASH(type), \
|
---|
226 | (void (*)(void*)) pfnCleanup)
|
---|
227 |
|
---|
228 | /**
|
---|
229 | * Initialise a vector-of-pointers structure.
|
---|
230 | * @returns iprt status code (VINF_SUCCESS or VERR_NO_MEMORY)
|
---|
231 | * @param pvec pointer to an uninitialised vector structure
|
---|
232 | * @param type the type of the pointers in the vector, including the
|
---|
233 | * final "*". As this is hashed by the preprocessor use
|
---|
234 | * of space etc is important.
|
---|
235 | * @param pfnCleanup cleanup function (void (*pfn)(void *)) that is called
|
---|
236 | * directly on a vector element when that element is
|
---|
237 | * dropped
|
---|
238 | */
|
---|
239 | #define VEC_INIT_PTR(pvec, type, pfnCleanup) \
|
---|
240 | vecInitPtr(pvec, sizeof(type), VECTOR_TOKEN_HASH(type), \
|
---|
241 | (void (*)(void*)) pfnCleanup)
|
---|
242 |
|
---|
243 | /**
|
---|
244 | * Clean up a vector.
|
---|
245 | * @param pvec pointer to the vector to clean up. The clean up function
|
---|
246 | * specified at initialisation (if any) is called for each element
|
---|
247 | * in the vector. After clean up, the vector structure is invalid
|
---|
248 | * until it is re-initialised
|
---|
249 | */
|
---|
250 | #define VEC_CLEANUP_OBJ vecCleanupObj
|
---|
251 |
|
---|
252 | /**
|
---|
253 | * Clean up a vector-of-pointers.
|
---|
254 | * @param pvec pointer to the vector to clean up. The clean up function
|
---|
255 | * specified at initialisation (if any) is called for each element
|
---|
256 | * in the vector. After clean up, the vector structure is invalid
|
---|
257 | * until it is re-initialised
|
---|
258 | */
|
---|
259 | #define VEC_CLEANUP_PTR vecCleanupPtr
|
---|
260 |
|
---|
261 | /**
|
---|
262 | * Reinitialises a vector structure to empty.
|
---|
263 | * @param pvec pointer to the vector to re-initialise. The clean up function
|
---|
264 | * specified at initialisation (if any) is called for each element
|
---|
265 | * in the vector.
|
---|
266 | */
|
---|
267 | #define VEC_CLEAR_OBJ vecClearObj
|
---|
268 |
|
---|
269 | /**
|
---|
270 | * Reinitialises a vector-of-pointers structure to empty.
|
---|
271 | * @param pvec pointer to the vector to re-initialise. The clean up function
|
---|
272 | * specified at initialisation (if any) is called for each element
|
---|
273 | * in the vector.
|
---|
274 | */
|
---|
275 | #define VEC_CLEAR_PTR vecClearPtr
|
---|
276 |
|
---|
277 | /**
|
---|
278 | * Adds an element to the back of a vector. The element will be byte-copied
|
---|
279 | * and become owned by the vector, to be cleaned up by the vector's clean-up
|
---|
280 | * routine when the element is dropped.
|
---|
281 | * @returns iprt status code (VINF_SUCCESS or VERR_NO_MEMORY)
|
---|
282 | * @returns VERR_INVALID_PARAMETER if the type does not match the type given
|
---|
283 | * when the vector was initialised (asserted)
|
---|
284 | * @param pvec pointer to the vector on to which the element should be
|
---|
285 | * added
|
---|
286 | * @param type the type of the vector as specified at initialisation.
|
---|
287 | * Spacing etc is important.
|
---|
288 | * @param pvElement void pointer to the element to be added
|
---|
289 | */
|
---|
290 | #define VEC_PUSH_BACK_OBJ(pvec, type, pvElement) \
|
---|
291 | vecPushBackObj(pvec, VECTOR_TOKEN_HASH(type), \
|
---|
292 | (pvElement) + ((pvElement) - (type *)(pvElement)))
|
---|
293 |
|
---|
294 | /**
|
---|
295 | * Adds a pointer to the back of a vector-of-pointers. The pointer will become
|
---|
296 | * owned by the vector, to be cleaned up by the vector's clean-up routine when
|
---|
297 | * it is dropped.
|
---|
298 | * @returns iprt status code (VINF_SUCCESS or VERR_NO_MEMORY)
|
---|
299 | * @returns VERR_INVALID_PARAMETER if the type does not match the type given
|
---|
300 | * when the vector was initialised (asserted)
|
---|
301 | * @param pvec pointer to the vector on to which the element should be
|
---|
302 | * added
|
---|
303 | * @param type the type of the vector as specified at initialisation.
|
---|
304 | * Spacing etc is important.
|
---|
305 | * @param pvElement the pointer to be added, typecast to pointer-to-void
|
---|
306 | */
|
---|
307 | #define VEC_PUSH_BACK_PTR(pvec, type, pvElement) \
|
---|
308 | vecPushBackPtr(pvec, VECTOR_TOKEN_HASH(type), \
|
---|
309 | (pvElement) + ((pvElement) - (type)(pvElement)))
|
---|
310 |
|
---|
311 | /**
|
---|
312 | * Returns the count of elements in a vector.
|
---|
313 | * @param pvec pointer to the vector.
|
---|
314 | */
|
---|
315 | #define VEC_SIZE_OBJ(pvec) (pvec)->mcElements
|
---|
316 |
|
---|
317 | /**
|
---|
318 | * Returns the count of elements in a vector-of-pointers.
|
---|
319 | * @param pvec pointer to the vector.
|
---|
320 | */
|
---|
321 | #define VEC_SIZE_PTR VEC_SIZE_OBJ
|
---|
322 |
|
---|
323 | /**
|
---|
324 | * Iterates over the vector elements from first to last and execute the
|
---|
325 | * following instruction or block on each iteration with @a pIterator set to
|
---|
326 | * point to the current element (that is, a pointer to the pointer element for
|
---|
327 | * a vector-of-pointers). Use in the same way as a "for" statement.
|
---|
328 | * @param pvec pointer to the vector to be iterated over
|
---|
329 | * @param type the type of the vector, must match the type specified at
|
---|
330 | * vector initialisation (including whitespace etc)
|
---|
331 | * @todo can we assert the correctness of the type in some way?
|
---|
332 | * @param pIterator a pointer to @a type which will be set to point to the
|
---|
333 | * current vector element on each iteration
|
---|
334 | */
|
---|
335 | #define VEC_FOR_EACH(pvec, type, pIterator) \
|
---|
336 | for (pIterator = (type *) (pvec)->mpvaElements; \
|
---|
337 | (pvec)->muTypeHash == VECTOR_TOKEN_HASH(type) \
|
---|
338 | && pIterator < (type *) (pvec)->mpvaElements + (pvec)->mcElements; \
|
---|
339 | ++pIterator)
|
---|
340 |
|
---|
341 | #endif /* MAIN_VECTOR_H */
|
---|