VirtualBox

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

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

Main/linux: fixes to vector container code

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.1 KB
Line 
1/** @file
2 * STL-like 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 */
8
9/*
10 * Copyright (C) 2008-2010 Oracle Corporation
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 */
20
21#define VECTOR_CONCAT(a, b) a ## b
22#define VECTOR_XCONCAT(a, b) VECTOR_CONCAT(a, b)
23/** A publicly visible (method, type, etc) name relating to the vector type */
24#define VECTOR_PUBLIC(NAME) VECTOR_XCONCAT(VECTOR_TYPENAME, _ ## NAME)
25/** An implementation-private (method, type, etc) name */
26#define VECTOR_INTERNAL(NAME) VECTOR_XCONCAT(VECTOR_TYPENAME, _internal_ ## NAME)
27/** The size of a vector element */
28#define VECTOR_ELEMENT_SIZE sizeof(VECTOR_TYPE)
29/** The unit by which the vector capacity is increased */
30#define VECTOR_ALLOC_UNIT 16
31
32#ifndef VECTOR_TYPE
33/** VECTOR_TYPE must be defined to the type that the vector will contain. The
34 * macro will be undef-ed again by this header. */
35# error You must define VECTOR_TYPE before including this header!
36#endif
37#ifndef VECTOR_TYPENAME
38/** VECTOR_TYPENAME must be defined to the typename for the vector. The
39 * macro will be undef-ed again by this header. */
40# error You must define VECTOR_TYPENAME before including this header!
41#endif
42#ifndef VECTOR_ALLOCATOR
43/** VECTOR_ALLOCATOR can be defined to an alternative allocator for the
44 * vector's memory. The allocator must be a function with realloc semantics.
45 * The macro will be undef-ed again by this header. */
46# define VECTOR_ALLOCATOR RTMemRealloc
47#endif
48#ifndef VECTOR_DESTRUCTOR
49/** VECTOR_DESTRUCTOR can be defined to be a routine to clean up vector
50 * elements before they are freed. It must return void and take a pointer to
51 * an element as a parameter. The macro will be undef-ed again by this header.
52 */
53# define VECTOR_DESTRUCTOR VECTOR_INTERNAL(empty_destructor)
54#endif
55
56/** Structure describing the vector itself */
57typedef struct VECTOR_TYPENAME
58{
59 /** The beginning of the allocated memory */
60 VECTOR_TYPE *mBegin;
61 /** Pointer to just after the end of the last element */
62 VECTOR_TYPE *mEnd;
63 /** Pointer to just after the end of the allocated memory */
64 VECTOR_TYPE *mCapacity;
65} VECTOR_TYPENAME;
66
67/** Non-constant iterator over the vector */
68typedef VECTOR_TYPE *VECTOR_PUBLIC(iterator);
69
70/*** Private methods ***/
71
72/** Destructor that does nothing. */
73static inline void VECTOR_INTERNAL(empty_destructor)(VECTOR_TYPENAME *pSelf)
74{
75 (void) pSelf;
76}
77
78/** Expand an existing vector */
79static inline int VECTOR_INTERNAL(expand)(VECTOR_TYPENAME *pSelf)
80{
81 size_t cNewCap = pSelf->mCapacity - pSelf->mBegin + VECTOR_ALLOC_UNIT;
82 size_t cOffEnd = pSelf->mEnd - pSelf->mBegin;
83 void *pRealloc = VECTOR_ALLOCATOR(pSelf->mBegin,
84 cNewCap * VECTOR_ELEMENT_SIZE);
85 if (!pRealloc)
86 return 0;
87 pSelf->mBegin = (VECTOR_TYPE *)pRealloc;
88 pSelf->mEnd = pSelf->mBegin + cOffEnd;
89 pSelf->mCapacity = pSelf->mBegin + cNewCap;
90 memset(pSelf->mEnd, 0, pSelf->mCapacity - pSelf->mEnd);
91 return 1;
92}
93
94/** Expand an existing vector */
95static inline void VECTOR_INTERNAL(destruct_all)(VECTOR_TYPENAME *pSelf)
96{
97 VECTOR_TYPE *pIter;
98 for (pIter = pSelf->mBegin; pIter < pSelf->mEnd; ++pIter)
99 VECTOR_DESTRUCTOR(pIter);
100}
101
102/*** Public methods ***/
103
104/** Initialise a newly allocated vector. The vector will be zeroed on failure.
105 */
106static inline int VECTOR_PUBLIC(init)(VECTOR_TYPENAME *pSelf)
107{
108 memset(pSelf, 0, sizeof(*pSelf));
109 return VECTOR_INTERNAL(expand)(pSelf);
110}
111
112/** Clean up a vector so that the memory can be returned. For convenience,
113 * this may be used safely on a zeroed vector structure. */
114static inline void VECTOR_PUBLIC(cleanup)(VECTOR_TYPENAME *pSelf)
115{
116 if (pSelf->mBegin)
117 {
118 VECTOR_INTERNAL(destruct_all)(pSelf);
119 VECTOR_ALLOCATOR(pSelf->mBegin, 0);
120 }
121 pSelf->mBegin = pSelf->mEnd = pSelf->mCapacity = NULL;
122}
123
124/** Add a value onto the end of a vector */
125static inline int VECTOR_PUBLIC(push_back)(VECTOR_TYPENAME *pSelf,
126 VECTOR_TYPE *pElement)
127{
128 if (pSelf->mEnd == pSelf->mCapacity && !VECTOR_INTERNAL(expand)(pSelf))
129 return 0;
130 if (pElement)
131 *pSelf->mEnd = *pElement;
132 ++pSelf->mEnd;
133 return 1;
134}
135
136/** Reset the vector */
137static inline void VECTOR_PUBLIC(clear)(VECTOR_TYPENAME *pSelf)
138{
139 VECTOR_INTERNAL(destruct_all)(pSelf);
140 memset(pSelf->mBegin, 0, pSelf->mEnd - pSelf->mBegin);
141 pSelf->mEnd = pSelf->mBegin;
142}
143
144/** Number of elements in the vector */
145static inline size_t VECTOR_PUBLIC(size)(VECTOR_TYPENAME *pSelf)
146{
147 return (pSelf->mEnd - pSelf->mBegin) / VECTOR_ELEMENT_SIZE;
148}
149
150/** Get the special "begin" iterator for a vector */
151static inline const VECTOR_PUBLIC(iterator) *VECTOR_PUBLIC(begin)
152 (VECTOR_TYPENAME *pSelf)
153{
154 return &pSelf->mBegin;
155}
156
157/** Get the special "end" iterator for a vector */
158static inline const VECTOR_PUBLIC(iterator) *VECTOR_PUBLIC(end)
159 (VECTOR_TYPENAME *pSelf)
160{
161 return &pSelf->mEnd;
162}
163
164/** A structure with pointers to class operations to save too much use of long
165 * identifiers in source code. Use like:
166 * <vector_type>_op_table *pOps = &<vector_type>_ops;
167 * and then
168 * pOps->init(&my_vector);
169 */
170typedef const struct VECTOR_INTERNAL(op_table)
171{
172 int (*init) (VECTOR_TYPENAME *pSelf);
173 void (*cleanup) (VECTOR_TYPENAME *pSelf);
174 int (*push_back) (VECTOR_TYPENAME *pSelf, VECTOR_TYPE *pElement);
175 void (*clear) (VECTOR_TYPENAME *pSelf);
176 size_t (*size) (VECTOR_TYPENAME *pSelf);
177 const VECTOR_PUBLIC(iterator) *
178 (*begin) (VECTOR_TYPENAME *pSelf);
179 const VECTOR_PUBLIC(iterator) *
180 (*end) (VECTOR_TYPENAME *pSelf);
181} VECTOR_PUBLIC(op_table);
182
183static VECTOR_PUBLIC(op_table) VECTOR_PUBLIC(ops) =
184{
185 VECTOR_PUBLIC(init),
186 VECTOR_PUBLIC(cleanup),
187 VECTOR_PUBLIC(push_back),
188 VECTOR_PUBLIC(clear),
189 VECTOR_PUBLIC(size),
190 VECTOR_PUBLIC(begin),
191 VECTOR_PUBLIC(end)
192};
193
194/*** Iterator methods ***/
195
196/** Initialise a newly allocated iterator */
197static inline void VECTOR_PUBLIC(iter_init)(VECTOR_PUBLIC(iterator) *pSelf,
198 const VECTOR_PUBLIC(iterator) *pOther)
199{
200 *pSelf = *pOther;
201}
202
203/** Dereference an iterator */
204static inline VECTOR_TYPE *VECTOR_PUBLIC(iter_target)(VECTOR_PUBLIC(iterator) *pSelf)
205{
206 return *pSelf;
207}
208
209/** Increment an iterator */
210static inline void VECTOR_PUBLIC(iter_incr)(VECTOR_PUBLIC(iterator) *pSelf)
211{
212 ++*pSelf;
213}
214
215/** Test whether an iterator is less than another. */
216static inline int VECTOR_PUBLIC(iter_lt)(const VECTOR_PUBLIC(iterator) *pFirst,
217 const VECTOR_PUBLIC(iterator) *pSecond)
218{
219 return *pFirst < *pSecond;
220}
221
222/** Test whether an iterator is equal to another. The special values
223 * ITERATOR_BEGIN and ITERATOR_END are recognised. */
224static inline int VECTOR_PUBLIC(iter_eq)(const VECTOR_PUBLIC(iterator) *pFirst,
225 const VECTOR_PUBLIC(iterator) *pSecond)
226{
227 return *pFirst == *pSecond;
228}
229
230/** A structure with pointers to iterator operations to save too much use of
231 * long identifiers in source code. Use like:
232 * <vector_type>_iter_op_table *pOps = &<vector_type>_iter_ops;
233 * and then
234 * pOps->init(&my_iter, &other_iter);
235 */
236typedef const struct VECTOR_INTERNAL(iter_op_table)
237{
238 void (*init) (VECTOR_PUBLIC(iterator) *pSelf,
239 const VECTOR_PUBLIC(iterator) *pOther);
240 VECTOR_TYPE *(*target) (VECTOR_PUBLIC(iterator) *pSelf);
241 void (*incr) (VECTOR_PUBLIC(iterator) *pSelf);
242 int (*lt) (const VECTOR_PUBLIC(iterator) *pFirst,
243 const VECTOR_PUBLIC(iterator) *pSecond);
244 int (*eq) (const VECTOR_PUBLIC(iterator) *pFirst,
245 const VECTOR_PUBLIC(iterator) *pSecond);
246} VECTOR_PUBLIC(iter_op_table);
247
248static VECTOR_PUBLIC(iter_op_table) VECTOR_PUBLIC(iter_ops) =
249{
250 VECTOR_PUBLIC(iter_init),
251 VECTOR_PUBLIC(iter_target),
252 VECTOR_PUBLIC(iter_incr),
253 VECTOR_PUBLIC(iter_lt),
254 VECTOR_PUBLIC(iter_eq)
255};
256
257/* We need to undefine anything we have defined (and for convenience we also
258 * undefine our "parameter" macros) as this header may be included multiple
259 * times in one source file with different parameters. */
260#undef VECTOR_CONCAT
261#undef VECTOR_XCONCAT
262#undef VECTOR_PUBLIC
263#undef VECTOR_INTERN
264#undef VECTOR_ELEMENT_SIZE
265#undef VECTOR_ALLOC_UNIT
266#undef VECTOR_TYPE
267#undef VECTOR_TYPENAME
268#undef VECTOR_ALLOCATOR
269#undef VECTOR_DESTRUCTOR
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