Line data Source code
1 : // lgtm [cpp/missing-header-guard]
2 :
3 : /******************************************************************************
4 : * Darmstadtium - a library of data structures
5 : * Ds_vector - a vector (growable array) library
6 : * One of the Bohr Game Libraries (see chaoslizard.org/devel/bohr)
7 : * Copyright (C) 2008 Charles Lindsay. Some rights reserved; see COPYING.
8 : * $Id: ds_vector.h 317 2008-01-05 21:45:34Z chaz $
9 : ******************************************************************************/
10 :
11 :
12 : // You must be careful about including this file multiple times. Each time it's
13 : // included in the same source file it must have a different Ds_VECTOR_SUFFIX.
14 :
15 : #include <stddef.h>
16 : #include <stdint.h>
17 : #include <stdlib.h>
18 : #include <string.h>
19 :
20 : #include <kdbhelper.h>
21 :
22 :
23 : // Controls inlining of this library's functions.
24 : #ifndef Ds_VECTOR_INLINE
25 : #ifdef Ds_INLINE
26 : #define Ds_VECTOR_INLINE Ds_INLINE
27 : #else
28 : #define Ds_VECTOR_INLINE inline static
29 : #endif
30 : #endif
31 :
32 : // Nix non-critical C99 keywords in compilers that don't support them.
33 : #if ((!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) && !defined(restrict))
34 : #define restrict
35 : #define _Ds_VECTOR_DEFINED_RESTRICT
36 : #endif
37 :
38 :
39 : // How to grow when the buffer is insufficient. The following values are
40 : // available: 1 - the buffer will grow to the exact needed size; 2 - the buffer
41 : // will double in size until sufficient (default); or 4 - the buffer will
42 : // quadruple in size until sufficient.
43 : #ifndef Ds_VECTOR_BEHAVIOR
44 : #define Ds_VECTOR_BEHAVIOR 2
45 : #endif
46 :
47 : // The type stored in Ds_vectors for this instance of the library.
48 : #ifndef Ds_VECTOR_TYPE
49 : #define Ds_VECTOR_TYPE int
50 : #endif
51 :
52 : // Suffix appended to all symbols exported by this header.
53 : #ifndef Ds_VECTOR_SUFFIX
54 : #define Ds_VECTOR_SUFFIX
55 : #endif
56 :
57 : // Macros to make symbols including a defined suffix (there's a seemingly
58 : // extraneous middle step because it must pass through the macro processor twice
59 : // to get what Ds_VECTOR_SUFFIX is defined as, instead of "Ds_VECTOR_SUFFIX").
60 : #define __Ds_VECTOR_SYMBOL_CAT(symbol, suffix) symbol##suffix
61 : #define _Ds_VECTOR_SYMBOL_CAT(symbol, suffix) __Ds_VECTOR_SYMBOL_CAT (symbol, suffix)
62 : #define _Ds_VECTOR_SYMBOL(symbol) _Ds_VECTOR_SYMBOL_CAT (symbol, Ds_VECTOR_SUFFIX)
63 :
64 : // Define symbols that in reality have a suffix attached to them.
65 : #define Ds_vector _Ds_VECTOR_SYMBOL (Ds_vector)
66 : #define Ds_InitVector _Ds_VECTOR_SYMBOL (Ds_InitVector)
67 : #define Ds_FreeVector _Ds_VECTOR_SYMBOL (Ds_FreeVector)
68 : #define Ds_InsertVectorItems _Ds_VECTOR_SYMBOL (Ds_InsertVectorItems)
69 : #define Ds_RemoveVectorItems _Ds_VECTOR_SYMBOL (Ds_RemoveVectorItems)
70 : #define Ds_ResizeVector _Ds_VECTOR_SYMBOL (Ds_ResizeVector)
71 :
72 :
73 : // Tells Ds_Insert- and RemoveVectorItems() to use the last items in the vector.
74 : #define Ds_VECTOR_END SIZE_MAX
75 :
76 :
77 : // A growable array.
78 : typedef struct Ds_vector
79 : {
80 : Ds_VECTOR_TYPE * buf; // the memory buffer
81 : size_t num; // how many items in it
82 : size_t cap; // how many items the buffer can hold
83 :
84 : } Ds_vector;
85 : #define Ds_VECTOR_INIT \
86 : { \
87 : NULL, 0, 0 \
88 : } // initializer
89 :
90 :
91 : /* Reserves an initial capacity for the Ds_vector. Returns 0/nonzero on
92 : * failure/success.
93 : */
94 : Ds_VECTOR_INLINE int Ds_InitVector (Ds_vector * restrict v, size_t cap)
95 : {
96 2090 : *v = (Ds_vector) Ds_VECTOR_INIT;
97 :
98 2090 : if (cap > 0)
99 : {
100 2193 : if (!(v->buf = (Ds_VECTOR_TYPE *) elektraMalloc (cap * sizeof (Ds_VECTOR_TYPE)))) return 0;
101 :
102 2193 : v->cap = cap;
103 : }
104 :
105 : return 1;
106 : }
107 :
108 : /* Frees all memory associated with the Ds_vector.
109 : */
110 : Ds_VECTOR_INLINE void Ds_FreeVector (Ds_vector * restrict v)
111 : {
112 2193 : if (v->buf)
113 : {
114 2193 : elektraFree (v->buf);
115 : }
116 2193 : *v = (Ds_vector) Ds_VECTOR_INIT;
117 : }
118 :
119 : /* Inserts items somewhere into the Ds_vector. pos is the 0-based offset to
120 : * place the inserted items--use Ds_VECTOR_END to mean the end of the existing
121 : * items. Returns 0/nonzero on failure/success. The vector won't be modified
122 : * if it fails.
123 : */
124 : Ds_VECTOR_INLINE int Ds_InsertVectorItems (Ds_vector * restrict v, const Ds_VECTOR_TYPE * restrict items, size_t num, size_t pos)
125 : {
126 : size_t new_cap;
127 :
128 : #if (Ds_VECTOR_BEHAVIOR == 1)
129 : new_cap = v->num + num;
130 : #else
131 : new_cap = (v->cap ? v->cap : 1);
132 : while (new_cap < v->num + num)
133 : #if (Ds_VECTOR_BEHAVIOR == 4)
134 : new_cap <<= 2; // the same as *= 4
135 : #else
136 : new_cap <<= 1; // the same as *= 2
137 : #endif
138 : #endif
139 : if (new_cap > v->cap)
140 : {
141 : Ds_VECTOR_TYPE * new_buf;
142 : if (!(new_buf = (Ds_VECTOR_TYPE *) realloc (v->buf, new_cap * sizeof (Ds_VECTOR_TYPE))))
143 : {
144 : return 0;
145 : }
146 : v->buf = new_buf;
147 : v->cap = new_cap;
148 : }
149 :
150 : if (pos > v->num)
151 : pos = v->num;
152 : else if (pos < v->num)
153 : {
154 : memmove (v->buf + pos + num, v->buf + pos, (v->num - pos) * sizeof (Ds_VECTOR_TYPE));
155 : }
156 :
157 : memcpy (v->buf + pos, items, num * sizeof (Ds_VECTOR_TYPE));
158 : v->num += num;
159 :
160 : return 1;
161 : }
162 :
163 : /* Takes items out of the Ds_vector, optionally copying them to a buffer.
164 : */
165 : Ds_VECTOR_INLINE void Ds_RemoveVectorItems (Ds_vector * restrict v, Ds_VECTOR_TYPE * restrict items, size_t num, size_t pos)
166 : {
167 : if (num > v->num) num = v->num;
168 : if (pos > v->num - num) pos = v->num - num;
169 :
170 : if (items) memcpy (items, v->buf + pos, num * sizeof (Ds_VECTOR_TYPE));
171 :
172 : if (v->num - num - pos > 0)
173 : {
174 : memmove (v->buf + pos, v->buf + num + pos, (v->num - num - pos) * sizeof (Ds_VECTOR_TYPE));
175 : }
176 : v->num -= num;
177 : }
178 :
179 : /* Resizes the Ds_vector. Returns 0/nonzero on failure/success.
180 : */
181 4 : Ds_VECTOR_INLINE int Ds_ResizeVector (Ds_vector * restrict v, size_t cap)
182 : {
183 4 : if (cap > 0)
184 : {
185 : Ds_VECTOR_TYPE * new_buf;
186 :
187 4 : if (!(new_buf = (Ds_VECTOR_TYPE *) realloc (v->buf, cap * sizeof (Ds_VECTOR_TYPE))))
188 : {
189 : return 0;
190 : }
191 :
192 4 : v->buf = new_buf;
193 4 : v->cap = cap;
194 :
195 4 : if (v->num > cap) v->num = cap;
196 : }
197 :
198 : return 1;
199 : }
200 :
201 :
202 : // We don't want these internal names clogging up the global namespace.
203 : #undef Ds_ResizeVector
204 : #undef Ds_RemoveVectorItems
205 : #undef Ds_InsertVectorItems
206 : #undef Ds_FreeVector
207 : #undef Ds_InitVector
208 : #undef Ds_vector
209 : #undef _Ds_VECTOR_SYMBOL
210 : #undef _Ds_VECTOR_SYMBOL_CAT
211 : #undef __Ds_VECTOR_SYMBOL_CAT
212 :
213 : // Undefine these so it's easier to change them and include this file again.
214 : #undef Ds_VECTOR_SUFFIX
215 : #undef Ds_VECTOR_TYPE
216 : #undef Ds_VECTOR_BEHAVIOR
217 :
218 : #ifdef _Ds_VECTOR_DEFINED_RESTRICT
219 : #undef _Ds_VECTOR_DEFINED_RESTRICT
220 : #undef restrict
221 : #endif
|