CVEC v1.0.0-build
Functional C++ vector-like manipulation for C
Loading...
Searching...
No Matches
cvec.h
Go to the documentation of this file.
1#pragma once
2
3#include "CVECpredefines.h"
4
5#ifdef CVEC_sys_strdup
6# undef CVEC_sys_strdup
7#endif
8
9#if defined(CVEC_OS_WIN32)
10# include <string.h>
11# define CVEC_sys_strdup _strdup
12#else
13# ifdef _POSIX_C_SOURCE
14# undef _POSIX_C_SOURCE
15# endif
16# define _POSIX_C_SOURCE 200809L
17# include <string.h>
18# define CVEC_sys_strdup strdup
19#endif // defined(CVEC_OS_WIN32)
20
21#include <stdio.h>
22#include <stdbool.h>
23#include <stdlib.h>
24
25#define CVEC_NPOS -1
26#define CVEC_SUCCESS 0
27#define CVEC_FAIL 1
28#define CVEC_FAIL_ALLOCATION 2 // Or reallocation
29#define CVEC_FORCECAP_FAIL 3
30#define CVEC_ELEM_NOT_FOUND 4
31#define CVEC_GET_NULL 5
32#define CVEC_OUT_BOUNDS 6
33#define CVEC_NOT_ENOUGH_CAP 7
34
35#define __CVEC_CAP_ADDITION 1
36
37#define __CVEC_SET_NULL(vec, ptrSym) \
38 vec ptrSym size = 0; \
39 vec ptrSym cap = 0; \
40 vec ptrSym elemLen = 0; \
41 vec ptrSym forceCap = false; \
42 vec ptrSym dynamicCap = false; \
43 vec ptrSym initialized = false \
44
45/**
46 * @brief Custom generic dynamic vector type
47 *
48 * CVEC is a flexible container that stores a sequence of elements of uniform size.
49 * It behaves similarly to std::vector in C++, supporting dynamic resizing,
50 * insertion, deletion, merging, reversing, and splitting.
51 *
52 * @note Direct modification of structure fields should be avoided — prefer CVEC API usage.
53 */
54typedef struct
55{
56 bool initialized; /**< Tracks whether this CVEC has been properly initialized */
57 bool __usedSplit; /**< Internal flag used by split operations */
58 void *data; /**< Pointer to contiguous allocated memory storing array elements */
59 bool forceCap; /**< Prevents capacity expansion if true; insertion fails when full */
60 bool dynamicCap; /**< Enables automatic capacity growth when true */
61 size_t size; /**< Current number of stored items */
62 size_t cap; /**< Allocated storage capacity */
63 size_t elemLen; /**< Size in bytes of each element */
64} CVEC;
65
66// PUBLIC //
67
68/**
69 * @brief Initialize a new vector with requested capacity and element size
70 *
71 * @param _cap Initial capacity (number of elements, not bytes)
72 * @param _elemSize Size in bytes of each element
73 * @return A fully initialized CVEC instance
74 */
75CVEC cvec_init(int _cap, size_t _elemSize);
76
77/**
78 * @brief Create a deep copy of an existing CVEC
79 *
80 * Copies memory, capacity, element properties, and flags.
81 *
82 * @param _src Pointer to the original CVEC
83 * @return A new CVEC instance with copied data
84 */
85CVEC cvec_initCopy(const CVEC *_src);
86
87/**
88 * @brief Clear all elements and reset size to zero without freeing memory
89 *
90 * @param _vec Pointer to the vector
91 * @return CVEC_SUCCESS on success, else CVEC_FAIL
92 */
94
95/**
96 * @brief Destroy a CVEC, freeing allocated memory and invalidating the structure
97 *
98 * @param _vec Pointer to the CVEC to destroy
99 * @return CVEC_SUCCESS on success, or CVEC_FAIL
100 */
102
103/**
104 * @brief Merge contents of `_input` vector into `_toMerge`
105 *
106 * Appends all items from `_input` to `_toMerge`, expanding capacity if allowed.
107 *
108 * @param _toMerge Destination vector to merge into
109 * @param _input Vector to merge from
110 * @return CVEC_SUCCESS or error code (CVEC_FAIL, CVEC_NOT_ENOUGH_CAP, ...)
111 */
112int cvec_merge(CVEC *_toMerge, const CVEC *_input);
113
114/**
115 * @brief Remove an element at a specific index
116 *
117 * Shifts trailing elements left by one.
118 *
119 * @param _vec Pointer to vector
120 * @param _index Index to remove
121 * @return CVEC_SUCCESS, CVEC_OUT_BOUNDS, or CVEC_FAIL
122 */
123int cvec_remove(CVEC *_vec, const size_t _index);
124
125/**
126 * @brief Remove the last element
127 *
128 * @param _vec Vector to modify
129 * @return CVEC_SUCCESS or CVEC_FAIL
130 */
132
133/**
134 * @brief Remove the first element, shifting all others left
135 *
136 * @param _vec Vector to modify
137 * @return CVEC_SUCCESS or CVEC_FAIL
138 */
140
141/**
142 * @brief Reverse the order of elements in place
143 *
144 * @param _vec Pointer to CVEC
145 * @return CVEC_SUCCESS or CVEC_FAIL
146 */
148
149/**
150 * @brief Shrink allocated memory to match current size
151 *
152 * @param _vec Pointer to vector
153 * @return CVEC_SUCCESS or CVEC_FAIL_ALLOCATION
154 */
155int cvec_shrink(CVEC *_vec);
156
157/**
158 * @brief Split a string by delimiter and store parts inside CVEC
159 *
160 * Internal `__usedSplit` tracks cleanup ownership.
161 *
162 * @param _vec Destination vector
163 * @param _str Input string to tokenize
164 * @param _del Delimiter string
165 * @return CVEC_SUCCESS or CVEC_FAIL
166 */
167int cvec_split(CVEC *_vec, char *_str, const char *_del);
168
169/**
170 * @brief Check whether element exists at index
171 *
172 * @param _vec Vector to inspect
173 * @param _index Element index
174 * @return true if valid index, false otherwise
175 */
176bool cvec_at(const CVEC *_vec, const size_t _index);
177
178/**
179 * @brief Check whether element exists within vector capacity
180 *
181 * @param _vec Vector to inspect
182 * @param _index Index inside original allocated capacity
183 * @return true if index < capacity, else false
184 */
185bool cvec_atCap(const CVEC *_vec, const size_t _index);
186
187/**
188 * @brief Get a pointer to an element at specified index
189 *
190 * @param _vec Vector to inspect
191 * @param _index Position to access
192 * @return Pointer to element or NULL if invalid
193 */
194void *cvec_get(const CVEC *_vec, const size_t _index);
195
196/**
197 * @brief Swap two CVEC instances
198 *
199 * @param _a First vector
200 * @param _b Second vector
201 */
202void cvec_swap(CVEC *_a, CVEC *_b);
203
204/**
205 * @brief Clear vector contents but keep capacity unchanged
206 *
207 * @param _vec Pointer to vector
208 */
209void cvec_clear(CVEC *_vec);
210
211// PRIVATE //
212
213/**
214 * @brief Insert at end of vector
215 *
216 * @param _vec Vector
217 * @param _elem Pointer to element data to store
218 * @return CVEC_SUCCESS or an error code
219 */
220int __cvec_push(CVEC *_vec, void *_elem);
221
222/**
223 * @brief Insert new element at beginning
224 *
225 * @return CVEC_SUCCESS or CVEC_NOT_ENOUGH_CAP
226 */
227int __cvec_pushFront(CVEC *_vec, void *_elem);
228
229/**
230 * @brief Insert element at specific index, shifting elements as needed
231 */
232int __cvec_pushIndex(CVEC *_vec, const size_t _index, void *_elem);
233
234/**
235 * @brief Replace value at given index
236 */
237int __cvec_set(CVEC *_vec, const size_t _index, void *_set);
238
239/**
240 * @brief Delete matching element starting search at index
241 */
242int __cvec_delIndex(CVEC *_vec, void *_elem, const size_t start);
243
244/**
245 * @brief Delete first occurrence of matching value
246 */
247int __cvec_del(CVEC *_vec, void *_elem);
248
249/**
250 * @brief Search for an element in the vector
251 *
252 * @return index or CVEC_NPOS
253 */
254int __cvec_find(const CVEC *_vec, void *_find);
255
256/**
257 * @brief Cleanup after split operations
258 */
260
261/**
262 * @brief Check whether capacity is sufficient for requested additions
263 *
264 * @return true if capacity allows, else false
265 */
266bool __cvec_hasEnoughCap(const CVEC *_vec, const size_t _additions);
267
268/**/
269
270#define __CVEC_MACRO_MOD_CALL(func, vec, type, val) \
271({ \
272 type _CVEC_TMP_X_VAR_ = val; \
273 int _CVEC_TMP_RETVAL_ = CVEC_NOT_ENOUGH_CAP; \
274 if (__cvec_hasEnoughCap(vec, 1)) \
275 _CVEC_TMP_RETVAL_ = func(vec, &_CVEC_TMP_X_VAR_); \
276 _CVEC_TMP_RETVAL_; \
277})
278
279// Capacity modifiers
280#define cvec_push(vec, type, val) \
281 __CVEC_MACRO_MOD_CALL(__cvec_push, vec, type, val)
282
283#define cvec_pushFront(vec, type, val) \
284 __CVEC_MACRO_MOD_CALL(__cvec_pushFront, vec, type, val)
285
286#define cvec_pushIndex(vec, type, pos, val) \
287({ \
288 type _CVEC_TMP_X_VAR_ = val; \
289 int _CVEC_TMP_RETVAL_; \
290 if (__cvec_hasEnoughCap(vec, 1)) \
291 _CVEC_TMP_RETVAL_ = __cvec_pushIndex(vec, pos, &_CVEC_TMP_X_VAR_); \
292 else \
293 _CVEC_TMP_RETVAL_ = CVEC_NOT_ENOUGH_CAP; \
294 _CVEC_TMP_RETVAL_; \
295})
296
297////
298
299#define cvec_set(vec, type, val, index) \
300({ \
301 type _CVEC_TMP_X_VAR_ = val; \
302 int _CVEC_TMP_RETVAL_ = __cvec_set(vec, index, &_CVEC_TMP_X_VAR_); \
303 _CVEC_TMP_RETVAL_; \
304})
305
306#define cvec_delIndex(vec, type, val, index) \
307({ \
308 type _CVEC_TMP_X_VAR_ = val; \
309 int _CVEC_TMP_RETVAL_ = __cvec_delIndex(vec, &_CVEC_TMP_X_VAR_, index); \
310 _CVEC_TMP_RETVAL_; \
311})
312
313#define cvec_del(vec, type, val) \
314({ \
315 type _CVEC_TMP_X_VAR_ = val; \
316 int _CVEC_TMP_RETVAL_ = __cvec_del(vec, &_CVEC_TMP_X_VAR_); \
317 _CVEC_TMP_RETVAL_; \
318})
319
320#define cvec_find(vec, type, val) \
321({ \
322 type _CVEC_TMP_X_VAR_ = val; \
323 int _CVEC_TMP_RETVAL_ = __cvec_find(vec, &_CVEC_TMP_X_VAR_); \
324 _CVEC_TMP_RETVAL_; \
325})
326
int cvec_reverse(CVEC *_vec)
Reverse the order of elements in place.
int cvec_popFront(CVEC *_vec)
Remove the first element, shifting all others left.
int cvec_remove(CVEC *_vec, const size_t _index)
Remove an element at a specific index.
void * cvec_get(const CVEC *_vec, const size_t _index)
Get a pointer to an element at specified index.
int __cvec_delIndex(CVEC *_vec, void *_elem, const size_t start)
Delete matching element starting search at index.
void cvec_swap(CVEC *_a, CVEC *_b)
Swap two CVEC instances.
int __cvec_set(CVEC *_vec, const size_t _index, void *_set)
Replace value at given index.
int cvec_merge(CVEC *_toMerge, const CVEC *_input)
Merge contents of _input vector into _toMerge.
int __cvec_pushIndex(CVEC *_vec, const size_t _index, void *_elem)
Insert element at specific index, shifting elements as needed.
int __cvec_find(const CVEC *_vec, void *_find)
Search for an element in the vector.
void cvec_clear(CVEC *_vec)
Clear vector contents but keep capacity unchanged.
CVEC cvec_initCopy(const CVEC *_src)
Create a deep copy of an existing CVEC.
CVEC cvec_init(int _cap, size_t _elemSize)
Initialize a new vector with requested capacity and element size.
bool __cvec_hasEnoughCap(const CVEC *_vec, const size_t _additions)
Check whether capacity is sufficient for requested additions.
int cvec_emptyAll(CVEC *_vec)
Clear all elements and reset size to zero without freeing memory.
int __cvec_del(CVEC *_vec, void *_elem)
Delete first occurrence of matching value.
int __cvec_pushFront(CVEC *_vec, void *_elem)
Insert new element at beginning.
bool cvec_at(const CVEC *_vec, const size_t _index)
Check whether element exists at index.
int __cvec_destroySplit(CVEC *_vec)
Cleanup after split operations.
int cvec_destroy(CVEC *_vec)
Destroy a CVEC, freeing allocated memory and invalidating the structure.
int __cvec_push(CVEC *_vec, void *_elem)
Insert at end of vector.
int cvec_shrink(CVEC *_vec)
Shrink allocated memory to match current size.
bool cvec_atCap(const CVEC *_vec, const size_t _index)
Check whether element exists within vector capacity.
int cvec_popBack(CVEC *_vec)
Remove the last element.
int cvec_split(CVEC *_vec, char *_str, const char *_del)
Split a string by delimiter and store parts inside CVEC.
Custom generic dynamic vector type.
Definition cvec.h:55
size_t cap
Allocated storage capacity.
Definition cvec.h:62
bool dynamicCap
Enables automatic capacity growth when true.
Definition cvec.h:60
void * data
Pointer to contiguous allocated memory storing array elements.
Definition cvec.h:58
bool forceCap
Prevents capacity expansion if true; insertion fails when full.
Definition cvec.h:59
bool initialized
Tracks whether this CVEC has been properly initialized.
Definition cvec.h:56
size_t size
Current number of stored items.
Definition cvec.h:61
bool __usedSplit
Internal flag used by split operations.
Definition cvec.h:57
size_t elemLen
Size in bytes of each element.
Definition cvec.h:63