diff --git a/cvector.h b/cvector.h index ae26e49..44b0fa3 100644 --- a/cvector.h +++ b/cvector.h @@ -7,27 +7,39 @@ #ifndef CVECTOR_H_ #define CVECTOR_H_ -#include /* for assert */ -#include /* for malloc/realloc/free */ -#include /* for memcpy/memmove */ - /* cvector heap implemented using C library malloc() */ /* in case C library malloc() needs extra protection, * allow these defines to be overridden. */ #ifndef cvector_clib_free +#include /* for free */ #define cvector_clib_free free #endif #ifndef cvector_clib_malloc +#include /* for malloc */ #define cvector_clib_malloc malloc #endif #ifndef cvector_clib_calloc +#include /* for calloc */ #define cvector_clib_calloc calloc #endif #ifndef cvector_clib_realloc +#include /* for realloc */ #define cvector_clib_realloc realloc #endif +#ifndef cvector_clib_assert +#include /* for assert */ +#define cvector_clib_assert assert +#endif +#ifndef cvector_clib_memcpy +#include /* for memcpy */ +#define cvector_clib_memcpy memcpy +#endif +#ifndef cvector_clib_memmove +#include /* for memmove */ +#define cvector_clib_memmove memmove +#endif typedef void (*cvector_elem_destructor_t)(void *elem); @@ -49,6 +61,11 @@ typedef struct cvector_metadata_t { */ #define cvector(type) cvector_vector_type(type) +/* + * @brief cvector_iterator - The iterator type used for cvector + */ +#define cvector_iterator(type) cvector_vector_type(type) + /** * @brief cvector_vec_to_base - For internal use, converts a vector pointer to a metadata pointer * @param vec - the vector @@ -146,7 +163,7 @@ typedef struct cvector_metadata_t { elem_destructor__(&(vec)[i]); \ } \ cvector_set_size((vec), cv_sz__ - 1); \ - memmove( \ + cvector_clib_memmove( \ (vec) + (i), \ (vec) + (i) + 1, \ sizeof(*(vec)) * (cv_sz__ - 1 - (i))); \ @@ -264,7 +281,7 @@ typedef struct cvector_metadata_t { cvector_grow((vec), cvector_compute_next_grow(cv_cap__)); \ } \ if ((pos) < cvector_size(vec)) { \ - memmove( \ + cvector_clib_memmove( \ (vec) + (pos) + 1, \ (vec) + (pos), \ sizeof(*(vec)) * ((cvector_size(vec)) - (pos))); \ @@ -298,10 +315,26 @@ typedef struct cvector_metadata_t { if ((from)) { \ cvector_grow(to, cvector_size(from)); \ cvector_set_size(to, cvector_size(from)); \ - memcpy((to), (from), cvector_size(from) * sizeof(*(from))); \ + cvector_clib_memcpy((to), (from), cvector_size(from) * sizeof(*(from))); \ } \ } while (0) +/** + * @brief cvector_swap - exchanges the content of the vector by the content of another vector of the same type + * @param vec - the original vector + * @param other - the other vector to swap content with + * @param type - the type of both vectors + * @return void + */ +#define cvector_swap(vec, other, type) \ + do { \ + if (vec && other) { \ + cvector_vector_type(type) cv_swap__ = vec; \ + vec = other; \ + other = cv_swap__; \ + } \ + } while (0) + /** * @brief cvector_set_capacity - For internal use, sets the capacity variable of the vector * @param vec - the vector @@ -354,11 +387,11 @@ typedef struct cvector_metadata_t { if (vec) { \ void *cv_p1__ = cvector_vec_to_base(vec); \ void *cv_p2__ = cvector_clib_realloc(cv_p1__, cv_sz__); \ - assert(cv_p2__); \ + cvector_clib_assert(cv_p2__); \ (vec) = cvector_base_to_vec(cv_p2__); \ } else { \ void *cv_p__ = cvector_clib_malloc(cv_sz__); \ - assert(cv_p__); \ + cvector_clib_assert(cv_p__); \ (vec) = cvector_base_to_vec(cv_p__); \ cvector_set_size((vec), 0); \ cvector_set_elem_destructor((vec), NULL); \ @@ -366,4 +399,17 @@ typedef struct cvector_metadata_t { cvector_set_capacity((vec), (count)); \ } while (0) +/** + * @brief cvector_shrink_to_fit - requests the container to reduce its capacity to fit its size + * @param vec - the vector + * @return void + */ +#define cvector_shrink_to_fit(vec) \ + do { \ + if (vec) { \ + const size_t cv_sz___ = cvector_size(vec); \ + cvector_grow(vec, cv_sz___); \ + } \ + } while (0) + #endif /* CVECTOR_H_ */ diff --git a/example.c b/example.c index 21c6cea..cc1fbc1 100644 --- a/example.c +++ b/example.c @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) { /* iterator over the vector using "iterator" style */ if (v) { - int *it; + cvector_iterator(int) it; int i = 0; for (it = cvector_begin(v); it != cvector_end(v); ++it) { printf("v[%d] = %d\n", i, *it); diff --git a/test.c b/test.c index 1afba85..92d16bd 100644 --- a/test.c +++ b/test.c @@ -34,7 +34,7 @@ int main() { /* iterator over the vector using "iterator" style */ if (v) { - int *it; + cvector_iterator(int) it; int i = 0; for (it = cvector_begin(v); it != cvector_end(v); ++it) { printf("v[%d] = %d\n", i, *it); diff --git a/unit-tests.c b/unit-tests.c index 07d6f47..059eed9 100644 --- a/unit-tests.c +++ b/unit-tests.c @@ -48,7 +48,7 @@ UTEST(test, vector_iterator) { /* iterator over the vector using "iterator" style */ if (v) { - int *it; + cvector_iterator(int) it; int i = 0; for (it = cvector_begin(v); it != cvector_end(v); ++it) { switch (i) { @@ -143,6 +143,33 @@ UTEST(test, vector_copy) { cvector_free(b); } +UTEST(test, vector_swap) { + cvector_vector_type(int) a = NULL; + cvector_vector_type(int) b = NULL; + + cvector_push_back(a, 1); + cvector_push_back(a, 2); + cvector_push_back(a, 3); + + cvector_push_back(b, 4); + cvector_push_back(b, 5); + cvector_push_back(b, 6); + cvector_push_back(b, 7); + + ASSERT_EQ(cvector_size(a), (size_t)3); + ASSERT_EQ(cvector_size(b), (size_t)4); + + cvector_swap(a, b, int); + + ASSERT_EQ(cvector_size(a), (size_t)4); + ASSERT_EQ(cvector_size(b), (size_t)3); + + ASSERT_EQ(a[0], 4); + ASSERT_EQ(a[1], 5); + ASSERT_EQ(b[0], 1); + ASSERT_EQ(b[1], 2); +} + UTEST(test, vector_reserve) { int i; cvector_vector_type(int) c = NULL; @@ -182,7 +209,7 @@ UTEST(test, vector_free_all) { } UTEST(test, vector_for_each_int) { - char **it; + cvector_iterator(char *) it; int i; cvector_vector_type(char *) v = NULL; for (i = 0; i < 10; ++i) { @@ -201,6 +228,22 @@ UTEST(test, vector_for_each_int) { cvector_free_each_and_free(v, free); } +UTEST(test, vector_shrink_to_fit) { + cvector_vector_type(int) a = NULL; + + cvector_push_back(a, 1); + cvector_push_back(a, 5); + cvector_push_back(a, 4); + + cvector_reserve(a, 50); + ASSERT_EQ(cvector_capacity(a), (size_t)50); + + cvector_shrink_to_fit(a); + ASSERT_EQ(cvector_capacity(a), (size_t)3); + + cvector_free(a); +} + struct data_t { int num; int a, b, c, d;