VirtualBox

source: vbox/trunk/src/VBox/Main/include/vector.h@ 32258

Last change on this file since 32258 was 32258, checked in by vboxsync, 14 years ago

Main/USB/linux: simplified the vector container and the code using it

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.6 KB
Line 
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 */
73typedef struct VECTOR_OBJ VECTOR_STRUCT VECTOR_OBJ;
74
75/** A vector of pointer values. (A handy special case.) */
76typedef 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. */
96DECLINLINE(void) vecNoCleanup(void *pvElement)
97{
98 (void) pvElement;
99}
100
101/** Expand an existing vector, implementation */
102DECLINLINE(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. */
123DECLINLINE(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. */
134DECLINLINE(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 */
144DECLINLINE(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 */
152DECLINLINE(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. */
169DECLINLINE(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. */
176DECLINLINE(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 */
183DECLINLINE(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 */
198DECLINLINE(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 */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette