libcstl
Loading...
Searching...
No Matches
vector.c
Go to the documentation of this file.
1/*!
2 * @file
3 */
4
5#include "cstl/vector.h"
6#include "cstl/array.h"
7
8#include <stdlib.h>
9#include <assert.h>
10
11/*! @private */
12static void * __cstl_vector_at(
13 const struct cstl_vector * const v, const size_t i)
14{
15 return (void *)((uintptr_t)v->elem.base + i * v->elem.size);
16}
17
19 const struct cstl_vector * const v, const size_t i)
20{
21 if (i >= v->count) {
22 abort();
23 }
24
25 return __cstl_vector_at(v, i);
26}
27
28void * cstl_vector_at(struct cstl_vector * const v, const size_t i)
29{
30 return (void *)cstl_vector_at_const(v, i);
31}
32
33/*! @private */
34static void cstl_vector_set_capacity(
35 struct cstl_vector * const v, const size_t sz)
36{
37 void * e;
38
39 /*
40 * this shouldn't be able to be triggered by the
41 * api. it's here to catch bugs internally in the
42 * vector code. the check is enabled for tests and
43 * disappears in the actual build
44 */
45 assert(sz >= v->count);
46
47 /*
48 * the vector always (quietly) stores space for one extra
49 * element at the end to use as scratch space for exchanging
50 * elements during sort and reverse operations
51 */
52 e = realloc(v->elem.base, (sz + 1) * v->elem.size);
53 if (e != NULL) {
54 v->elem.base = e;
55 v->cap = sz;
56 }
57}
58
59void cstl_vector_reserve(struct cstl_vector * const v, const size_t sz)
60{
61 if (sz > v->cap) {
62 cstl_vector_set_capacity(v, sz);
63 }
64}
65
67{
68 if (v->cap > v->count) {
69 cstl_vector_set_capacity(v, v->count);
70 }
71}
72
73void cstl_vector_resize(struct cstl_vector * const v, const size_t sz)
74{
75 void * const priv = v->elem.xtor.priv;
76 cstl_xtor_func_t * xtor = NULL;
77
79 if (v->cap < sz) {
80 /*
81 * this is designed to catch a failure to allocate
82 * memory. it represents a runtime error that the
83 * caller is not expected to ever have to deal with
84 */
85 abort(); // GCOV_EXCL_LINE
86 }
87
88 if (v->count < sz) {
89 xtor = v->elem.xtor.cons;
90 } else if (v->count > sz) {
91 xtor = v->elem.xtor.dest;
92 }
93
94 if (xtor == NULL) {
95 v->count = sz;
96 } else if (v->count < sz) {
97 do {
98 xtor(__cstl_vector_at(v, v->count++), priv);
99 } while (v->count < sz);
100 } else if (v->count > sz) {
101 do {
102 xtor(__cstl_vector_at(v, --v->count), priv);
103 } while (v->count > sz);
104 }
105}
106
107void cstl_vector_clear(struct cstl_vector * const v)
108{
109 cstl_vector_resize(v, 0);
110 free(v->elem.base);
111
112 v->elem.base = NULL;
113 v->cap = 0;
114}
115
116void __cstl_vector_sort(struct cstl_vector * const v,
117 cstl_compare_func_t * const cmp, void * const priv,
118 cstl_swap_func_t * const swap,
119 const cstl_sort_algorithm_t algo)
120{
122 v->elem.base, v->count, v->elem.size,
123 cmp, priv,
124 swap, __cstl_vector_at(v, v->cap),
125 algo);
126}
127
128ssize_t cstl_vector_search(const struct cstl_vector * const v,
129 const void * const e,
130 cstl_compare_func_t * const cmp,
131 void * const priv)
132{
133 return cstl_raw_array_search(v->elem.base,
134 v->count, v->elem.size,
135 e,
136 cmp, priv);
137}
138
139ssize_t cstl_vector_find(const struct cstl_vector * const v,
140 const void * const e,
141 cstl_compare_func_t * const cmp,
142 void * const priv)
143{
144 return cstl_raw_array_find(v->elem.base,
145 v->count, v->elem.size,
146 e,
147 cmp, priv);
148}
149
150void __cstl_vector_reverse(struct cstl_vector * const v,
151 cstl_swap_func_t * const swap)
152{
153 cstl_raw_array_reverse(v->elem.base,
154 v->count, v->elem.size,
155 swap, __cstl_vector_at(v, v->cap));
156}
157
158void cstl_vector_swap(struct cstl_vector * const a,
159 struct cstl_vector * const b)
160{
161 struct cstl_vector t;
162 cstl_swap(a, b, &t, sizeof(t));
163}
164
165#ifdef __cfg_test__
166// GCOV_EXCL_START
167#include "internal/check.h"
168
169#include <stdlib.h>
170
171static int int_cmp(const void * const a, const void * const b,
172 void * const p)
173{
174 (void)p;
175 return *(int *)a - *(int *)b;
176}
177
178START_TEST(sort)
179{
180 static size_t n = 71;
181 static const cstl_sort_algorithm_t algo[] = {
186 /*
187 * a wildly wrong enumeration to ensure that the
188 * vector still gets sorted
189 */
190 2897234,
191 };
192
193 DECLARE_CSTL_VECTOR(v, int);
194 unsigned int i;
195
196 cstl_vector_resize(&v, n);
197
198 for (i = 0; i < sizeof(algo) / sizeof(*algo); i++) {
199 unsigned int j;
200
201 for (j = 0; j < n; j++) {
202 *(int *)cstl_vector_at(&v, j) = rand() % n;
203 }
204 __cstl_vector_sort(&v, int_cmp, NULL, cstl_swap, algo[i]);
205 for (j = 1; j < n; j++) {
206 ck_assert_int_ge(*(int *)cstl_vector_at(&v, j),
207 *(int *)cstl_vector_at(&v, j - 1));
208 }
209 }
210
212}
213END_TEST
214
215START_TEST(invalid_access)
216{
217 DECLARE_CSTL_VECTOR(v, int);
218
219 cstl_vector_resize(&v, 5);
220
221 ck_assert_signal(SIGABRT, cstl_vector_at(&v, -1));
222 ck_assert_signal(SIGABRT, cstl_vector_at(&v, 5));
223
225}
226END_TEST
227
228START_TEST(search)
229{
230 static size_t n = 63;
231
232 DECLARE_CSTL_VECTOR(v, int);
233 unsigned int i;
234
235 cstl_vector_resize(&v, n);
236 for (i = 0; i < n; i++) {
237 *(int *)cstl_vector_at(&v, i) = i;
238 }
239
240 for (i = 0; i < n; i++) {
241 ck_assert_int_eq(cstl_vector_search(&v, &i, int_cmp, NULL), i);
242 }
243 ck_assert_int_eq(cstl_vector_search(&v, &i, int_cmp, NULL), -1);
244
245 for (i = 0; i < n; i++) {
246 ck_assert_int_eq(cstl_vector_find(&v, &i, int_cmp, NULL), i);
247 }
248 ck_assert_int_eq(cstl_vector_find(&v, &i, int_cmp, NULL), -1);
249
251}
252END_TEST
253
254START_TEST(reverse)
255{
256 static size_t n = 27;
257
258 DECLARE_CSTL_VECTOR(v, int);
259 unsigned int i;
260
261 cstl_vector_resize(&v, n);
262 for (i = 0; i < n; i++) {
263 *(int *)cstl_vector_at(&v, i) = i;
264 }
265
267 for (i = 1; i < n; i++) {
268 ck_assert_int_le(*(int *)cstl_vector_at(&v, i),
269 *(int *)cstl_vector_at(&v, i - 1));
270 }
271
273}
274END_TEST
275
276static void int_cons(void * const i, void * const p)
277{
278 (void)p;
279
280 *(int *)i = 0;
281}
282
283static void int_dest(void * const i, void * const p)
284{
285 (void)p;
286
287 *(int *)i = -1;
288}
289
290START_TEST(complex)
291{
292 struct cstl_vector v;
293 int i;
294
295 cstl_vector_init_complex(&v, sizeof(int),
296 int_cons, int_dest, NULL);
297
298 cstl_vector_resize(&v, 10);
299 for (i = 0; i < (int)cstl_vector_size(&v); i++) {
300 ck_assert_int_eq(*(int *)cstl_vector_at(&v, i), 0);
301 }
302 ck_assert_int_eq(i, 10);
303 for (; i < (int)cstl_vector_capacity(&v); i++) {
304 ck_assert_int_eq(*(int *)__cstl_vector_at(&v, i), -1);
305 }
306 ck_assert_int_eq(i, 10);
307
308 cstl_vector_resize(&v, 3);
309 for (i = 0; i < (int)cstl_vector_size(&v); i++) {
310 ck_assert_int_eq(*(int *)cstl_vector_at(&v, i), 0);
311 }
312 ck_assert_int_eq(i, 3);
313 for (; i < (int)cstl_vector_capacity(&v); i++) {
314 ck_assert_int_eq(*(int *)__cstl_vector_at(&v, i), -1);
315 }
316 ck_assert_int_eq(i, 10);
317
318 cstl_vector_resize(&v, 6);
319 for (i = 0; i < (int)cstl_vector_size(&v); i++) {
320 ck_assert_int_eq(*(int *)cstl_vector_at(&v, i), 0);
321 }
322 ck_assert_int_eq(i, 6);
323 for (; i < (int)cstl_vector_capacity(&v); i++) {
324 ck_assert_int_eq(*(int *)__cstl_vector_at(&v, i), -1);
325 }
326 ck_assert_int_eq(i, 10);
327
328 ck_assert_int_ne(cstl_vector_size(&v), cstl_vector_capacity(&v));
330 ck_assert_int_eq(cstl_vector_size(&v), cstl_vector_capacity(&v));
331
333}
334END_TEST
335
336Suite * vector_suite(void)
337{
338 Suite * const s = suite_create("vector");
339
340 TCase * tc;
341
342 tc = tcase_create("vector");
343 tcase_add_test(tc, invalid_access);
344 tcase_add_test(tc, sort);
345 tcase_add_test(tc, search);
346 tcase_add_test(tc, reverse);
347 tcase_add_test(tc, complex);
348 suite_add_tcase(s, tc);
349
350 return s;
351}
352
353// GCOV_EXCL_STOP
354#endif
cstl_sort_algorithm_t
Enumeration indicating the desired sort algorithm.
Definition common.h:24
@ CSTL_SORT_ALGORITHM_QUICK_M
Median-of-three quicksort.
Definition common.h:30
@ CSTL_SORT_ALGORITHM_QUICK
Quicksort.
Definition common.h:26
@ CSTL_SORT_ALGORITHM_HEAP
Heapsort.
Definition common.h:32
@ CSTL_SORT_ALGORITHM_QUICK_R
Randomized quicksort.
Definition common.h:28
static void cstl_swap(void *const x, void *const y, void *const t, const size_t sz)
Swap values at two memory locations via use of a third.
Definition common.h:137
void cstl_xtor_func_t(void *obj, void *priv)
Type for functions called to construct, clear, or destroy an object.
Definition common.h:97
void cstl_swap_func_t(void *a, void *b, void *t, size_t len)
Type of function called to swap two objects.
Definition common.h:118
int cstl_compare_func_t(const void *obj1, const void *obj2, void *priv)
Function type for comparing (in)equality of two objects.
Definition common.h:49
ssize_t cstl_raw_array_find(const void *arr, size_t count, size_t size, const void *ex, cstl_compare_func_t *cmp, void *priv)
Perform a linear search of the array.
Definition array.c:54
void cstl_raw_array_sort(void *arr, size_t count, size_t size, cstl_compare_func_t *cmp, void *priv, cstl_swap_func_t *swap, void *tmp, cstl_sort_algorithm_t algo)
Sort the array using the specified algorithm.
Definition array.c:340
ssize_t cstl_raw_array_search(const void *arr, size_t count, size_t size, const void *ex, cstl_compare_func_t *cmp, void *priv)
Perform a binary search of the array.
Definition array.c:30
void cstl_raw_array_reverse(void *arr, size_t count, size_t size, cstl_swap_func_t *swap, void *tmp)
Reverse the contents of an array.
Definition array.c:15
void cstl_vector_resize(struct cstl_vector *const v, const size_t sz)
Change the number of valid elements in the vector.
Definition vector.c:73
void cstl_vector_reserve(struct cstl_vector *const v, const size_t sz)
Request to increase the capacity of the vector.
Definition vector.c:59
void * cstl_vector_at(struct cstl_vector *const v, const size_t i)
Get a pointer to an element in the vector.
Definition vector.c:28
#define DECLARE_CSTL_VECTOR(NAME, TYPE)
(Statically) declare and initialize a vector
Definition vector.h:74
static size_t cstl_vector_size(const struct cstl_vector *const v)
Get the number of elements in the vector.
Definition vector.h:138
static void cstl_vector_init_complex(struct cstl_vector *const v, const size_t sz, cstl_xtor_func_t *const cons, cstl_xtor_func_t *const dest, void *const priv)
Initialize a vector object.
Definition vector.h:102
static size_t cstl_vector_capacity(const struct cstl_vector *const v)
Get the number of elements the vector can hold.
Definition vector.h:154
void cstl_vector_swap(struct cstl_vector *const a, struct cstl_vector *const b)
Swap the vector objects at the two given locations.
Definition vector.c:158
void cstl_vector_shrink_to_fit(struct cstl_vector *const v)
Request to decrease the capacity of the vector.
Definition vector.c:66
ssize_t cstl_vector_search(const struct cstl_vector *const v, const void *const e, cstl_compare_func_t *const cmp, void *const priv)
Perform a binary search of the vector.
Definition vector.c:128
const void * cstl_vector_at_const(const struct cstl_vector *const v, const size_t i)
Get a const pointer to an element from a const vector.
Definition vector.c:18
void cstl_vector_clear(struct cstl_vector *const v)
Return a vector to its initialized state.
Definition vector.c:107
static void cstl_vector_reverse(struct cstl_vector *const v)
Reverse the current order of the elements.
Definition vector.h:314
ssize_t cstl_vector_find(const struct cstl_vector *const v, const void *const e, cstl_compare_func_t *const cmp, void *const priv)
Perform a linear search of the vector.
Definition vector.c:139
void __cstl_vector_reverse(struct cstl_vector *const v, cstl_swap_func_t *const swap)
Reverse the current order of the elements.
Definition vector.c:150
void __cstl_vector_sort(struct cstl_vector *const v, cstl_compare_func_t *const cmp, void *const priv, cstl_swap_func_t *const swap, const cstl_sort_algorithm_t algo)
Sort the elements in the vector.
Definition vector.c:116
Vector object.
Definition vector.h:31