Skip to content

Commit

Permalink
Fixing dst, src order, swap_data API, improving docs (#21)
Browse files Browse the repository at this point in the history
Ensure for all APIs taking two vectors that destination is always the first paramater
New API to perform a swap of a source vector into the destination vector
Improving documentation to reflect changes and be more clearly readable
  • Loading branch information
jrepp authored Feb 17, 2022
1 parent 25f15a1 commit bda7a5d
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 42 deletions.
15 changes: 10 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -236,19 +236,24 @@ current number of values. Returns 0 if the operation is successful, otherwise
-1 is returned and the vector remains unchanged.
## `vec_pusharr(v, arr, count)` / `vec_extend(v, v2)`
## `vec_pusharr(v, arr, count)` / `vec_extend(dst, src)`
Extend `v` by multiple source elements.
Pushes the contents of the array `arr` or the vector `v2` to the end of the vector `v`.
This operation will grow the underlying array. If the reallocation fails the array
These operations will grow the underlying array. If the reallocation fails the array
will be partially filled and `vec_oom` will return `1`.
## `vec_oom(v)`
Returns true when the underlying vector has experienced an out-of-memory condition.
## `vec_swap_data(dst, src)`
Swap the data from `src` into `dst`. Any data that exists in `dst` will be de-initialized and
freed first. After the swap `src` will be initialized to an empty state.
## `vec_find(v, val, idx)` / `vec_rfind(v, val, inx)`
Finds the first or last occurrence of the value `val` in the vector.
Expand Down Expand Up @@ -310,18 +315,18 @@ vec_each(&v, my_system, &arg);
```
* `_ptr` takes the address of the value position as an argument to `f`
## `vec_map[_ptr][_rev](v, v2, f, ...)`
## `vec_map[_ptr][_rev](dst, src, f, ...)`
`vec_map` allows mapping from one vector to another using a function and optional arguments.
Example:
```c
int convert(int x, int c) { /* transform x */ }
vec_int_t v, v2;
/* initialize and push values into v */
vec_map(&v, &v2, convert, 100); /* converts each element in v -> v2 using the argument 100*/
vec_map(&v2, &v, convert, 100); /* converts each element in v -> v2 using the argument 100*/
```
* `_ptr` pass the value to the function by pointer
* `_rev` reverses the iteration over `v`
* `_rev` reverses the iteration over `src`
* arguments after `f` are passed along after `v`


Expand Down
97 changes: 65 additions & 32 deletions src/vec.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ extern "C" {
#define VEC_FIXED (0)


// Optionally add assert into array access, the statement remains unchanged but
// but will break before access the array out of bounds.
#if defined(VEC_USE_CHECKED_ACCESS)
#define VEC_CHECK(v, i) assert(i < (v)->length)
#else
#define VEC_CHECK(v, i) ((void)1)
#endif // VEC_USE_CHECKED_ACCESS

//
// Count the dimensions of a fixed array
//
Expand Down Expand Up @@ -190,19 +198,43 @@ extern "C" {
((v)->length = 0)


// Return the first element (assumes length > 0)
#define vec_first(v) \
((v)->data[0])


// True when the vector is empty
#define vec_empty(v) \
((v)->length == 0)


// Get an element at index
#define vec_get(v, i) \
((v)->data[(VEC_CHECK(v, i), i)])


// Get an element by pointer at index
#define vec_get_ptr(v, i) \
(&((v)->data[(VEC_CHECK(v, i), i)]))


// Return the first element (assumes length > 0)
#define vec_first(v) \
((v)->data[(VEC_CHECK(v, 0), 0)])


// Returns the last element (assumes length > 0)
#define vec_last(v) \
((v)->data[(v)->length - 1])
((v)->data[(VEC_CHECK(v, (v)->length - 1), (v)->length - 1)])


// Swap the data of src into dst, releasing dst before the swap
#define vec_swap_data(dst, src) \
do { \
if (((dst)->data) == ((src)->data)) \
break; \
vec_deinit(dst); \
(dst)->data = (src)->data; \
(dst)->options = (src)->options; \
(dst)->length = (src)->length; \
(dst)->capacity = (src)->capacity; \
vec_init(src); \
} while(0);


// Reserve space for `n` elements
Expand Down Expand Up @@ -324,62 +356,63 @@ extern "C" {


// Apply v2[i] = f(v[i], ...) for each element v
#define vec_map(v, v2, f, ...) \
#define vec_map(dst, src, f, ...) \
do { \
if (VEC_OK != vec_reserve((v2), vec_length(v))) { \
if (VEC_OK != vec_reserve((dst), vec_length(src))) { \
break; \
} \
(v2)->length = (v)->length; \
VEC_TYPEOF((v)->data[0]) *s__ = &(v)->data[0], \
*e__ = &(v)->data[(v)->length], \
*d__ = &(v2)->data[0]; \
(dst)->length = (src)->length; \
VEC_TYPEOF((src)->data[0]) *s__ = &(src)->data[0], \
*e__ = &(src)->data[(src)->length], \
*d__ = &(dst)->data[0]; \
for (; s__ < e__; ++s__, ++d__) { \
*d__ = (f)(*s__ , ## __VA_ARGS__ ); \
} \
} while(0);


// Apply v2[i] = f(v[i], ...) for each element v in reverse
#define vec_map_rev(v, v2, f, ...) \
// Apply dst[i] = f(src[i], ...) for each element v in reverse
#define vec_map_rev(dst, src, f, ...) \
do { \
if (VEC_OK != vec_reserve((v2), vec_length(v))) { \
if (VEC_OK != vec_reserve((dst), vec_length(src))) { \
break; \
}; \
(v2)->length = (v)->length; \
VEC_TYPEOF((v)->data[0]) *s__ = &(v)->data[(v)->length - 1], \
*e__ = &(v)->data[-1], *d__ = &(v2)->data[0]; \
(dst)->length = (src)->length; \
VEC_TYPEOF((src)->data[0]) *s__ = &(src)->data[(src)->length - 1], \
*e__ = &(src)->data[-1], \
*d__ = &(dst)->data[0]; \
for (; s__ > e__; --s__, ++d__) { \
*d__ = (f)(*s__, ##__VA_ARGS__); \
} \
} while (0);


// Apply v2[i] = f(&v[i], ...) for each element of v
#define vec_map_ptr(v, v2, f, ...) \
// Apply dst[i] = f(&src[i], ...) for each element of v
#define vec_map_ptr(dst, src, f, ...) \
do { \
if (VEC_OK != vec_reserve((v2), vec_length(v))) { \
if (VEC_OK != vec_reserve((dst), vec_length(src))) { \
break; \
} \
(v2)->length = (v)->length; \
VEC_TYPEOF((v)->data[0]) *s__ = &(v)->data[0], \
*e__ = &(v)->data[(v)->length], \
*d__ = &(v2)->data[0]; \
(dst)->length = (src)->length; \
VEC_TYPEOF((src)->data[0]) *s__ = &(src)->data[0], \
*e__ = &(src)->data[(src)->length], \
*d__ = &(dst)->data[0]; \
for (; s__ < e__; ++s__, ++d__) { \
*d__ = (f)(s__, ## __VA_ARGS__ ); \
} \
} while(0);


// Apply v2[i] = f(&v[i], ...) for each element of v in reverse
#define vec_map_ptr_rev(v, v2, f, ...) \
// Apply dst[i] = f(&src[i], ...) for each element of v in reverse
#define vec_map_ptr_rev(dst, src, f, ...) \
do { \
if (VEC_OK != vec_reserve((v2), vec_length(v))) { \
if (VEC_OK != vec_reserve((dst), vec_length(src))) { \
break; \
} \
(v2)->length = (v)->length; \
VEC_TYPEOF((v)->data[0]) *s__ = &(v)->data[(v)->length - 1], \
*e__ = &(v)->data[-1], \
*d__ = &(v2)->data[0]; \
(dst)->length = (src)->length; \
VEC_TYPEOF((src)->data[0]) *s__ = &(src)->data[(src)->length - 1], \
*e__ = &(src)->data[-1], \
*d__ = &(dst)->data[0]; \
for (; s__ > e__; --s__, ++d__) { \
*d__ = (f)(s__, ##__VA_ARGS__); \
} \
Expand Down
3 changes: 3 additions & 0 deletions src/vec_config_default.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ typedef VEC_SIZE_TYPE vec_size_t;
// Define any signature decoration for vector APIs
#define VEC_API(name) name

// Enable checking of raw array accesses, disable for performance
#define VEC_USE_CHECKED_ACCESS 1

//
// Structure alignment and typeof helpers
//
Expand Down
7 changes: 6 additions & 1 deletion test/test_vec_custom.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ int test_vec_custom() {
vec_init(&v);
item_t i = { 1, 2, "1" };
vec_push(&v, i);
test_assert_item(&vec_last(&v), 1, 2, "1");
i.a = 3, i.b = 4;
vec_push(&v, i);
test_assert_item(&vec_last(&v), 3, 4, "1");
test_assert_item(&vec_get(&v, 0), 1, 2, "1");
test_assert_item(&vec_first(&v), 1, 2, "1");
test_assert(&vec_get(&v, 1) == vec_get_ptr(&v, 1));
vec_pop(&v);
vec_deinit(&v);

Expand Down
8 changes: 4 additions & 4 deletions test/test_vec_functional.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ int test_vec_functional() {
vec_init(&v2);
fill_vec(&v);
fill_vec(&v2);
vec_map(&v, &v2, power);
vec_map(&v2, &v, power);
test_assert(v2.length == count);
test_assert(is_ascending(&v2));
test_assert(is_power(&v2));
Expand All @@ -125,7 +125,7 @@ int test_vec_functional() {
vec_init(&v2);
fill_vec(&v);
fill_vec(&v2);
vec_map_ptr(&v, &v2, power_ptr);
vec_map_ptr(&v2, &v, power_ptr);
test_assert(v2.length == count);
test_assert(is_ascending(&v2));
test_assert(is_power(&v2));
Expand All @@ -139,7 +139,7 @@ int test_vec_functional() {
vec_init(&v2);
fill_vec(&v);
fill_vec(&v2);
vec_map_rev(&v, &v2, power);
vec_map_rev(&v2, &v, power);
test_assert(v2.length == count);
test_assert(is_descending(&v2));
vec_deinit(&v);
Expand All @@ -152,7 +152,7 @@ int test_vec_functional() {
vec_init(&v2);
fill_vec(&v);
fill_vec(&v2);
vec_map_ptr_rev(&v, &v2, power_ptr);
vec_map_ptr_rev(&v2, &v, power_ptr);
test_assert(v2.length == count);
test_assert(is_descending(&v2));
vec_deinit(&v);
Expand Down
19 changes: 19 additions & 0 deletions test/test_vec_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -362,5 +362,24 @@ int test_vec_ops() {
vec_deinit(&v);
}

{ test_section("vec_swap_data");
vec_int_t v, v2;
vec_init(&v);
vec_init(&v2);
vec_push(&v, 19);
vec_push(&v, 31);
vec_push(&v, 47);
vec_push(&v2, 78);
vec_swap_data(&v2, &v) ;
test_assert(v.data == NULL);
test_assert(vec_get(&v2, 0) == 19);
test_assert(vec_get(&v2, 1) == 31);
test_assert(vec_get(&v2, 2) == 47);
vec_swap_data(&v2, &v2);
test_assert(!vec_empty(&v2));
test_assert(vec_get(&v2, 2) == 47);
vec_deinit(&v2);
}

return 0;
}

0 comments on commit bda7a5d

Please sign in to comment.