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 VECTOR_ELEMENT_SIZE * 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 */
|
---|
57 | typedef 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 | /*** Private methods ***/
|
---|
68 |
|
---|
69 | /** Destructor that does nothing. */
|
---|
70 | static inline void VECTOR_INTERNAL(empty_destructor)(VECTOR_TYPENAME *pSelf)
|
---|
71 | {
|
---|
72 | (void) pSelf;
|
---|
73 | }
|
---|
74 |
|
---|
75 | /** Expand an existing vector */
|
---|
76 | static inline int VECTOR_INTERNAL(expand)(VECTOR_TYPENAME *pSelf)
|
---|
77 | {
|
---|
78 | size_t cNewCap = pSelf->mCapacity - pSelf->mBegin + VECTOR_ALLOC_UNIT;
|
---|
79 | size_t cOffEnd = pSelf->mEnd - pSelf->mBegin;
|
---|
80 | void *pRealloc = VECTOR_ALLOCATOR(pSelf->mBegin, cNewCap);
|
---|
81 | if (!pRealloc)
|
---|
82 | return 0;
|
---|
83 | pSelf->mBegin = (VECTOR_TYPE *)pRealloc;
|
---|
84 | pSelf->mEnd = pSelf->mBegin + cOffEnd;
|
---|
85 | pSelf->mCapacity = pSelf->mBegin + cNewCap / VECTOR_ELEMENT_SIZE;
|
---|
86 | memset(pSelf->mEnd, 0, pSelf->mCapacity - pSelf->mEnd);
|
---|
87 | return 1;
|
---|
88 | }
|
---|
89 |
|
---|
90 | /** Expand an existing vector */
|
---|
91 | static inline void VECTOR_INTERNAL(destruct_all)(VECTOR_TYPENAME *pSelf)
|
---|
92 | {
|
---|
93 | VECTOR_TYPE *pIter;
|
---|
94 | for (pIter = pSelf->mBegin; pIter < pSelf->mEnd; ++pIter)
|
---|
95 | VECTOR_DESTRUCTOR(pIter);
|
---|
96 | }
|
---|
97 |
|
---|
98 | /*** Public methods ***/
|
---|
99 |
|
---|
100 | /** Initialise a newly allocated vector. The vector will be zeroed on failure.
|
---|
101 | */
|
---|
102 | static inline int VECTOR_PUBLIC(init)(VECTOR_TYPENAME *pSelf)
|
---|
103 | {
|
---|
104 | memset(pSelf, 0, sizeof(*pSelf));
|
---|
105 | return VECTOR_INTERNAL(expand)(pSelf);
|
---|
106 | }
|
---|
107 |
|
---|
108 | /** Clean up a vector so that the memory can be returned. For convenience,
|
---|
109 | * this may be used safely on a zeroed vector structure. */
|
---|
110 | static inline void VECTOR_PUBLIC(cleanup)(VECTOR_TYPENAME *pSelf)
|
---|
111 | {
|
---|
112 | if (pSelf->mBegin)
|
---|
113 | {
|
---|
114 | VECTOR_INTERNAL(destruct_all)(pSelf);
|
---|
115 | VECTOR_ALLOCATOR(pSelf->mBegin, 0);
|
---|
116 | }
|
---|
117 | pSelf->mBegin = pSelf->mEnd = pSelf->mCapacity = NULL;
|
---|
118 | }
|
---|
119 |
|
---|
120 | /** Add a value onto the end of a vector */
|
---|
121 | static inline int VECTOR_PUBLIC(push_back)(VECTOR_TYPENAME *pSelf,
|
---|
122 | VECTOR_TYPE *pElement)
|
---|
123 | {
|
---|
124 | if (pSelf->mEnd == pSelf->mCapacity && !VECTOR_INTERNAL(expand)(pSelf))
|
---|
125 | return 0;
|
---|
126 | if (pElement)
|
---|
127 | *pSelf->mEnd = *pElement;
|
---|
128 | ++pSelf->mEnd;
|
---|
129 | return 1;
|
---|
130 | }
|
---|
131 |
|
---|
132 | /** Reset the vector */
|
---|
133 | static inline void VECTOR_PUBLIC(clear)(VECTOR_TYPENAME *pSelf)
|
---|
134 | {
|
---|
135 | VECTOR_INTERNAL(destruct_all)(pSelf);
|
---|
136 | memset(pSelf->mBegin, 0, pSelf->mEnd - pSelf->mBegin);
|
---|
137 | pSelf->mEnd = pSelf->mBegin;
|
---|
138 | }
|
---|
139 |
|
---|
140 | /** Number of elements in the vector */
|
---|
141 | static inline size_t VECTOR_PUBLIC(size)(VECTOR_TYPENAME *pSelf)
|
---|
142 | {
|
---|
143 | return (pSelf->mEnd - pSelf->mBegin) / VECTOR_ELEMENT_SIZE;
|
---|
144 | }
|
---|
145 |
|
---|
146 | /*** Iterators ***/
|
---|
147 |
|
---|
148 | /** Non-constant iterator over the vector */
|
---|
149 | typedef VECTOR_TYPE *VECTOR_PUBLIC(iterator);
|
---|
150 |
|
---|
151 | /** Initialise a newly allocated iterator */
|
---|
152 | static inline void VECTOR_PUBLIC(iter_init)(VECTOR_PUBLIC(iterator) *pSelf,
|
---|
153 | const VECTOR_PUBLIC(iterator) *pOther)
|
---|
154 | {
|
---|
155 | *pSelf = *pOther;
|
---|
156 | }
|
---|
157 |
|
---|
158 | /** Dereference an iterator */
|
---|
159 | static inline VECTOR_TYPE *VECTOR_PUBLIC(iter_target)(VECTOR_PUBLIC(iterator) *pSelf)
|
---|
160 | {
|
---|
161 | return *pSelf;
|
---|
162 | }
|
---|
163 |
|
---|
164 | /** Increment an iterator */
|
---|
165 | static inline void VECTOR_PUBLIC(iter_incr)(VECTOR_PUBLIC(iterator) *pSelf)
|
---|
166 | {
|
---|
167 | ++*pSelf;
|
---|
168 | }
|
---|
169 |
|
---|
170 | /** Get the special "begin" iterator for a vector */
|
---|
171 | static inline const VECTOR_PUBLIC(iterator) *VECTOR_PUBLIC(begin)
|
---|
172 | (VECTOR_TYPENAME *pSelf)
|
---|
173 | {
|
---|
174 | return &pSelf->mBegin;
|
---|
175 | }
|
---|
176 |
|
---|
177 | /** Get the special "end" iterator for a vector */
|
---|
178 | static inline const VECTOR_PUBLIC(iterator) *VECTOR_PUBLIC(end)
|
---|
179 | (VECTOR_TYPENAME *pSelf)
|
---|
180 | {
|
---|
181 | return &pSelf->mEnd;
|
---|
182 | }
|
---|
183 |
|
---|
184 | /** Test whether an iterator is less than another. */
|
---|
185 | static inline int VECTOR_PUBLIC(iter_lt)(const VECTOR_PUBLIC(iterator) *pFirst,
|
---|
186 | const VECTOR_PUBLIC(iterator) *pSecond)
|
---|
187 | {
|
---|
188 | return *pFirst < *pSecond;
|
---|
189 | }
|
---|
190 |
|
---|
191 | /** Test whether an iterator is equal to another. The special values
|
---|
192 | * ITERATOR_BEGIN and ITERATOR_END are recognised. */
|
---|
193 | static inline int VECTOR_PUBLIC(iter_eq)(const VECTOR_PUBLIC(iterator) *pFirst,
|
---|
194 | const VECTOR_PUBLIC(iterator) *pSecond)
|
---|
195 | {
|
---|
196 | return *pFirst == *pSecond;
|
---|
197 | }
|
---|
198 |
|
---|
199 | /* We need to undefine anything we have defined (and for convenience we also
|
---|
200 | * undefine our "parameter" macros) as this header may be included multiple
|
---|
201 | * times in one source file with different parameters. */
|
---|
202 | #undef VECTOR_CONCAT
|
---|
203 | #undef VECTOR_XCONCAT
|
---|
204 | #undef VECTOR_PUBLIC
|
---|
205 | #undef VECTOR_INTERN
|
---|
206 | #undef VECTOR_ELEMENT_SIZE
|
---|
207 | #undef VECTOR_ALLOC_UNIT
|
---|
208 | #undef VECTOR_TYPE
|
---|
209 | #undef VECTOR_TYPENAME
|
---|
210 | #undef VECTOR_ALLOCATOR
|
---|
211 | #undef VECTOR_DESTRUCTOR
|
---|