Thumbnail

rani/cscroll.git

Clone URL: https://git.buni.party/rani/cscroll.git

Viewing file on branch master

1/**
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2015 Evan Teran
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
25#ifndef CVECTOR_H_
26#define CVECTOR_H_
27/**
28 * @copyright Copyright (c) 2015 Evan Teran,
29 * License: The MIT License (MIT)
30 * @brief cvector heap implemented using C library malloc()
31 * @file cvector.h
32 */
33
34/* in case C library malloc() needs extra protection,
35 * allow these defines to be overridden.
36 */
37/* functions for allocation and deallocation need to correspond to each other, fall back to C library functions if not all are overridden */
38#if !defined(cvector_clib_free) || !defined(cvector_clib_malloc) || !defined(cvector_clib_calloc) || !defined(cvector_clib_realloc)
39#ifdef cvector_clib_free
40#undef cvector_clib_free
41#endif
42#ifdef cvector_clib_malloc
43#undef cvector_clib_malloc
44#endif
45#ifdef cvector_clib_calloc
46#undef cvector_clib_calloc
47#endif
48#ifdef cvector_clib_realloc
49#undef cvector_clib_realloc
50#endif
51#include <stdlib.h>
52#define cvector_clib_free free
53#define cvector_clib_malloc malloc
54#define cvector_clib_calloc calloc
55#define cvector_clib_realloc realloc
56#endif
57/* functions independent of memory allocation */
58#ifndef cvector_clib_assert
59#include <assert.h> /* for assert */
60#define cvector_clib_assert assert
61#endif
62#ifndef cvector_clib_memcpy
63#include <string.h> /* for memcpy */
64#define cvector_clib_memcpy memcpy
65#endif
66#ifndef cvector_clib_memmove
67#include <string.h> /* for memmove */
68#define cvector_clib_memmove memmove
69#endif
70
71/* NOTE: Similar to C's qsort and bsearch, you will receive a T*
72 * for a vector of Ts. This means that you cannot use `free` directly
73 * as a destructor. Instead if you have for example a cvector_vector_type(int *)
74 * you will need to supply a function which casts `elem_ptr` to an `int**`
75 * and then does a free on what that pointer points to:
76 *
77 * ex:
78 *
79 * void free_int(void *p) { free(*(int **)p); }
80 */
81typedef void (*cvector_elem_destructor_t)(void *elem_ptr);
82
83typedef struct cvector_metadata_t {
84 size_t size;
85 size_t capacity;
86 cvector_elem_destructor_t elem_destructor;
87} cvector_metadata_t;
88
89/**
90 * @brief cvector_vector_type - The vector type used in this library
91 * @param type The type of vector to act on.
92 */
93#define cvector_vector_type(type) type *
94
95/**
96 * @brief cvector - Syntactic sugar to retrieve a vector type
97 * @param type The type of vector to act on.
98 */
99#define cvector(type) cvector_vector_type(type)
100
101/**
102 * @brief cvector_iterator - The iterator type used for cvector
103 * @param type The type of iterator to act on.
104 */
105#define cvector_iterator(type) cvector_vector_type(type)
106
107/**
108 * @brief cvector_vec_to_base - For internal use, converts a vector pointer to a metadata pointer
109 * @param vec - the vector
110 * @return the metadata pointer of the vector
111 * @internal
112 */
113#define cvector_vec_to_base(vec) \
114 (&((cvector_metadata_t *)(void *)(vec))[-1])
115
116/**
117 * @brief cvector_base_to_vec - For internal use, converts a metadata pointer to a vector pointer
118 * @param ptr - pointer to the metadata
119 * @return the vector
120 * @internal
121 */
122#define cvector_base_to_vec(ptr) \
123 ((void *)&((cvector_metadata_t *)(ptr))[1])
124
125/**
126 * @brief cvector_capacity - gets the current capacity of the vector
127 * @param vec - the vector
128 * @return the capacity as a size_t
129 */
130#define cvector_capacity(vec) \
131 ((vec) ? cvector_vec_to_base(vec)->capacity : (size_t)0)
132
133/**
134 * @brief cvector_size - gets the current size of the vector
135 * @param vec - the vector
136 * @return the size as a size_t
137 */
138#define cvector_size(vec) \
139 ((vec) ? cvector_vec_to_base(vec)->size : (size_t)0)
140
141/**
142 * @brief cvector_elem_destructor - get the element destructor function used
143 * to clean up elements
144 * @param vec - the vector
145 * @return the function pointer as cvector_elem_destructor_t
146 */
147#define cvector_elem_destructor(vec) \
148 ((vec) ? cvector_vec_to_base(vec)->elem_destructor : NULL)
149
150/**
151 * @brief cvector_empty - returns non-zero if the vector is empty
152 * @param vec - the vector
153 * @return non-zero if empty, zero if non-empty
154 */
155#define cvector_empty(vec) \
156 (cvector_size(vec) == 0)
157
158/**
159 * @brief cvector_reserve - Requests that the vector capacity be at least enough
160 * to contain n elements. If n is greater than the current vector capacity, the
161 * function causes the container to reallocate its storage increasing its
162 * capacity to n (or greater).
163 * @param vec - the vector
164 * @param n - Minimum capacity for the vector.
165 * @return void
166 */
167#define cvector_reserve(vec, n) \
168 do { \
169 size_t cv_reserve_cap__ = cvector_capacity(vec); \
170 if (cv_reserve_cap__ < (n)) { \
171 cvector_grow((vec), (n)); \
172 } \
173 } while (0)
174
175/**
176 * @brief cvector_init - Initialize a vector. The vector must be NULL for this to do anything.
177 * @param vec - the vector
178 * @param capacity - vector capacity to reserve
179 * @param elem_destructor_fn - element destructor function
180 * @return void
181 */
182#define cvector_init(vec, capacity, elem_destructor_fn) \
183 do { \
184 if (!(vec)) { \
185 cvector_reserve((vec), capacity); \
186 cvector_set_elem_destructor((vec), (elem_destructor_fn)); \
187 } \
188 } while (0)
189
190/**
191 * @brief cvector_erase - removes the element at index i from the vector
192 * @param vec - the vector
193 * @param i - index of element to remove
194 * @return void
195 */
196#define cvector_erase(vec, i) \
197 do { \
198 if (vec) { \
199 const size_t cv_erase_sz__ = cvector_size(vec); \
200 if ((i) < cv_erase_sz__) { \
201 cvector_elem_destructor_t cv_erase_elem_dtor__ = cvector_elem_destructor(vec); \
202 if (cv_erase_elem_dtor__) { \
203 cv_erase_elem_dtor__(&(vec)[i]); \
204 } \
205 cvector_set_size((vec), cv_erase_sz__ - 1); \
206 cvector_clib_memmove( \
207 (vec) + (i), \
208 (vec) + (i) + 1, \
209 sizeof(*(vec)) * (cv_erase_sz__ - 1 - (i))); \
210 } \
211 } \
212 } while (0)
213
214/**
215 * @brief cvector_clear - erase all of the elements in the vector
216 * @param vec - the vector
217 * @return void
218 */
219#define cvector_clear(vec) \
220 do { \
221 if (vec) { \
222 cvector_elem_destructor_t cv_clear_elem_dtor__ = cvector_elem_destructor(vec); \
223 if (cv_clear_elem_dtor__) { \
224 size_t cv_clear_i__; \
225 for (cv_clear_i__ = 0; cv_clear_i__ < cvector_size(vec); ++cv_clear_i__) { \
226 cv_clear_elem_dtor__(&(vec)[cv_clear_i__]); \
227 } \
228 } \
229 cvector_set_size(vec, 0); \
230 } \
231 } while (0)
232
233/**
234 * @brief cvector_free - frees all memory associated with the vector
235 * @param vec - the vector
236 * @return void
237 */
238#define cvector_free(vec) \
239 do { \
240 if (vec) { \
241 void *cv_free_p__ = cvector_vec_to_base(vec); \
242 cvector_elem_destructor_t cv_free_elem_dtor__ = cvector_elem_destructor(vec); \
243 if (cv_free_elem_dtor__) { \
244 size_t cv_free_i__; \
245 for (cv_free_i__ = 0; cv_free_i__ < cvector_size(vec); ++cv_free_i__) { \
246 cv_free_elem_dtor__(&(vec)[cv_free_i__]); \
247 } \
248 } \
249 cvector_clib_free(cv_free_p__); \
250 } \
251 } while (0)
252
253/**
254 * @brief cvector_begin - returns an iterator to first element of the vector
255 * @param vec - the vector
256 * @return a pointer to the first element (or NULL)
257 */
258#define cvector_begin(vec) \
259 (vec)
260
261/**
262 * @brief cvector_end - returns an iterator to one past the last element of the vector
263 * @param vec - the vector
264 * @return a pointer to one past the last element (or NULL)
265 */
266#define cvector_end(vec) \
267 ((vec) ? &((vec)[cvector_size(vec)]) : NULL)
268
269/* user request to use linear growth algorithm */
270#ifdef CVECTOR_LINEAR_GROWTH
271
272/**
273 * @brief cvector_compute_next_grow - returns an the computed size in next vector grow
274 * size is increased by 1
275 * @param size - current size
276 * @return size after next vector grow
277 */
278#define cvector_compute_next_grow(size) \
279 ((size) + 1)
280
281#else
282
283/**
284 * @brief cvector_compute_next_grow - returns an the computed size in next vector grow
285 * size is increased by multiplication of 2
286 * @param size - current size
287 * @return size after next vector grow
288 */
289#define cvector_compute_next_grow(size) \
290 ((size) ? ((size) << 1) : 1)
291
292#endif /* CVECTOR_LINEAR_GROWTH */
293
294/**
295 * @brief cvector_push_back - adds an element to the end of the vector
296 * @param vec - the vector
297 * @param value - the value to add
298 * @return void
299 */
300#define cvector_push_back(vec, value) \
301 do { \
302 size_t cv_push_back_cap__ = cvector_capacity(vec); \
303 if (cv_push_back_cap__ <= cvector_size(vec)) { \
304 cvector_grow((vec), cvector_compute_next_grow(cv_push_back_cap__)); \
305 } \
306 (vec)[cvector_size(vec)] = (value); \
307 cvector_set_size((vec), cvector_size(vec) + 1); \
308 } while (0)
309
310/**
311 * @brief cvector_insert - insert element at position pos to the vector
312 * @param vec - the vector
313 * @param pos - position in the vector where the new elements are inserted.
314 * @param val - value to be copied (or moved) to the inserted elements.
315 * @return void
316 */
317#define cvector_insert(vec, pos, val) \
318 do { \
319 size_t cv_insert_cap__ = cvector_capacity(vec); \
320 if (cv_insert_cap__ <= cvector_size(vec)) { \
321 cvector_grow((vec), cvector_compute_next_grow(cv_insert_cap__)); \
322 } \
323 if ((pos) < cvector_size(vec)) { \
324 cvector_clib_memmove( \
325 (vec) + (pos) + 1, \
326 (vec) + (pos), \
327 sizeof(*(vec)) * ((cvector_size(vec)) - (pos))); \
328 } \
329 (vec)[(pos)] = (val); \
330 cvector_set_size((vec), cvector_size(vec) + 1); \
331 } while (0)
332
333/**
334 * @brief cvector_pop_back - removes the last element from the vector
335 * @param vec - the vector
336 * @return void
337 */
338#define cvector_pop_back(vec) \
339 do { \
340 cvector_elem_destructor_t cv_pop_back_elem_dtor__ = cvector_elem_destructor(vec); \
341 if (cv_pop_back_elem_dtor__) { \
342 cv_pop_back_elem_dtor__(&(vec)[cvector_size(vec) - 1]); \
343 } \
344 cvector_set_size((vec), cvector_size(vec) - 1); \
345 } while (0)
346
347/**
348 * @brief cvector_copy - copy a vector
349 * @param from - the original vector
350 * @param to - destination to which the function copy to
351 * @return void
352 */
353#define cvector_copy(from, to) \
354 do { \
355 if ((from)) { \
356 cvector_grow(to, cvector_size(from)); \
357 cvector_set_size(to, cvector_size(from)); \
358 cvector_clib_memcpy((to), (from), cvector_size(from) * sizeof(*(from))); \
359 } \
360 } while (0)
361
362/**
363 * @brief cvector_swap - exchanges the content of the vector by the content of another vector of the same type
364 * @param vec - the original vector
365 * @param other - the other vector to swap content with
366 * @param type - the type of both vectors
367 * @return void
368 */
369#define cvector_swap(vec, other, type) \
370 do { \
371 if (vec && other) { \
372 cvector_vector_type(type) cv_swap__ = vec; \
373 vec = other; \
374 other = cv_swap__; \
375 } \
376 } while (0)
377
378/**
379 * @brief cvector_set_capacity - For internal use, sets the capacity variable of the vector
380 * @param vec - the vector
381 * @param size - the new capacity to set
382 * @return void
383 * @internal
384 */
385#define cvector_set_capacity(vec, size) \
386 do { \
387 if (vec) { \
388 cvector_vec_to_base(vec)->capacity = (size); \
389 } \
390 } while (0)
391
392/**
393 * @brief cvector_set_size - For internal use, sets the size variable of the vector
394 * @param vec - the vector
395 * @param _size - the new capacity to set
396 * @return void
397 * @internal
398 */
399#define cvector_set_size(vec, _size) \
400 do { \
401 if (vec) { \
402 cvector_vec_to_base(vec)->size = (_size); \
403 } \
404 } while (0)
405
406/**
407 * @brief cvector_set_elem_destructor - set the element destructor function
408 * used to clean up removed elements. The vector must NOT be NULL for this to do anything.
409 * @param vec - the vector
410 * @param elem_destructor_fn - function pointer of type cvector_elem_destructor_t used to destroy elements
411 * @return void
412 */
413#define cvector_set_elem_destructor(vec, elem_destructor_fn) \
414 do { \
415 if (vec) { \
416 cvector_vec_to_base(vec)->elem_destructor = (elem_destructor_fn); \
417 } \
418 } while (0)
419
420/**
421 * @brief cvector_grow - For internal use, ensures that the vector is at least `count` elements big
422 * @param vec - the vector
423 * @param count - the new capacity to set
424 * @return void
425 * @internal
426 */
427#define cvector_grow(vec, count) \
428 do { \
429 const size_t cv_grow_sz__ = (count) * sizeof(*(vec)) + sizeof(cvector_metadata_t); \
430 if (vec) { \
431 void *cv_grow_p1__ = cvector_vec_to_base(vec); \
432 void *cv_grow_p2__ = cvector_clib_realloc(cv_grow_p1__, cv_grow_sz__); \
433 cvector_clib_assert(cv_grow_p2__); \
434 (vec) = cvector_base_to_vec(cv_grow_p2__); \
435 } else { \
436 void *cv_grow_p__ = cvector_clib_malloc(cv_grow_sz__); \
437 cvector_clib_assert(cv_grow_p__); \
438 (vec) = cvector_base_to_vec(cv_grow_p__); \
439 cvector_set_size((vec), 0); \
440 cvector_set_elem_destructor((vec), NULL); \
441 } \
442 cvector_set_capacity((vec), (count)); \
443 } while (0)
444
445/**
446 * @brief cvector_shrink_to_fit - requests the container to reduce its capacity to fit its size
447 * @param vec - the vector
448 * @return void
449 */
450#define cvector_shrink_to_fit(vec) \
451 do { \
452 if (vec) { \
453 const size_t cv_shrink_to_fit_sz__ = cvector_size(vec); \
454 cvector_grow(vec, cv_shrink_to_fit_sz__); \
455 } \
456 } while (0)
457
458/**
459 * @brief cvector_at - returns a reference to the element at position n in the vector.
460 * @param vec - the vector
461 * @param n - position of an element in the vector.
462 * @return the element at the specified position in the vector.
463 */
464#define cvector_at(vec, n) \
465 ((vec) ? (((int)(n) < 0 || (size_t)(n) >= cvector_size(vec)) ? NULL : &(vec)[n]) : NULL)
466
467/**
468 * @brief cvector_front - returns a reference to the first element in the vector. Unlike member cvector_begin, which returns an iterator to this same element, this function returns a direct reference.
469 * @param vec - the vector
470 * @return a reference to the first element in the vector container.
471 */
472#define cvector_front(vec) \
473 ((vec) ? ((cvector_size(vec) > 0) ? cvector_at(vec, 0) : NULL) : NULL)
474
475/**
476 * @brief cvector_back - returns a reference to the last element in the vector.Unlike member cvector_end, which returns an iterator just past this element, this function returns a direct reference.
477 * @param vec - the vector
478 * @return a reference to the last element in the vector.
479 */
480#define cvector_back(vec) \
481 ((vec) ? ((cvector_size(vec) > 0) ? cvector_at(vec, cvector_size(vec) - 1) : NULL) : NULL)
482
483/**
484 * @brief cvector_resize - resizes the container to contain count elements.
485 * @param vec - the vector
486 * @param count - new size of the vector
487 * @param value - the value to initialize new elements with
488 * @return void
489 */
490#define cvector_resize(vec, count, value) \
491 do { \
492 size_t cv_resize_count__ = (size_t)(count); \
493 size_t cv_resize_sz__ = cvector_size(vec); \
494 if (cv_resize_count__ > cv_resize_sz__) { \
495 cvector_reserve((vec), cv_resize_count__); \
496 cvector_set_size((vec), cv_resize_count__); \
497 do { \
498 (vec)[cv_resize_sz__++] = (value); \
499 } while (cv_resize_sz__ < cv_resize_count__); \
500 } else { \
501 while (cv_resize_count__ < cv_resize_sz__--) { \
502 cvector_pop_back(vec); \
503 } \
504 } \
505 } while (0)
506
507#endif /* CVECTOR_H_ */
508