Skip to content

Commit

Permalink
Implement T_arr_copy() & T_arr_join() + tests
Browse files Browse the repository at this point in the history
Copy can be used to make a 'deep' copy of a dynamic array. It obviously
won't know about any memory that underlying elements may point to, but
doing a copy of the actual data may sometimes be useful.

Join appends array b to array a, and then frees array b. This is useful
when adding batches of multiple elements to an array.
  • Loading branch information
vkoskiv committed Nov 16, 2023
1 parent 750a73f commit 03fe914
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/utils/dyn_array.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@ static inline size_t grow_x_2(size_t capacity, size_t elem_size) {
a->items = new; \
a->capacity = a->count; \
} \
static inline struct T##_arr T##_arr_copy(const struct T##_arr a) { \
if (!a.items) return (struct T##_arr){ 0 }; \
struct T##_arr c = a; \
c.items = malloc(a.count * sizeof(*a.items)); \
memcpy(c.items, a.items, a.count * sizeof(*a.items)); \
return c; \
} \
static inline void T##_arr_free(struct T##_arr *a) { \
if (!a) return; \
if (a->elem_free) { \
Expand All @@ -71,6 +78,12 @@ static inline size_t grow_x_2(size_t capacity, size_t elem_size) {
a->items = NULL; \
a->capacity = 0; \
a->count = 0; \
} \
static inline void T##_arr_join(struct T##_arr *a, struct T##_arr *b) { \
if (!a || !b) return; \
for (size_t i = 0; i < b->count; ++i) \
T##_arr_add(a, b->items[i]); \
T##_arr_free(b); \
}

dyn_array_def(int);
Expand Down
66 changes: 66 additions & 0 deletions tests/test_dyn_array.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,3 +199,69 @@ bool dyn_array_trim_expand(void) {

return true;
}

bool dyn_array_copy(void) {
struct int_arr arr = { 0 };

for (int i = 0; i < dyn_test_count; ++i) {
int_arr_add(&arr, i);
}

struct int_arr no_copy = arr;
test_assert(no_copy.count == arr.count);
test_assert(no_copy.capacity == arr.capacity);
test_assert(no_copy.elem_free == arr.elem_free);
test_assert(no_copy.grow_fn == arr.grow_fn);
test_assert(no_copy.items == arr.items);

struct int_arr copy = int_arr_copy(arr);
test_assert(copy.count == arr.count);
test_assert(copy.capacity == arr.capacity);
test_assert(copy.elem_free == arr.elem_free);
test_assert(copy.grow_fn == arr.grow_fn);
test_assert(copy.items != arr.items);

int_arr_free(&arr);
for (int i = 0; i < dyn_test_count; ++i) {
test_assert(copy.items[i] == i);
}
int_arr_free(&copy);

return true;
}

bool dyn_array_join(void) {
struct int_arr a = { 0 };
for (int i = 0; i < dyn_test_count / 2; ++i) {
int_arr_add(&a, i);
}

struct int_arr b = { 0 };
for (int i = 0; i < dyn_test_count / 2; ++i) {
int_arr_add(&b, i + (dyn_test_count / 2));
}

test_assert(a.count == dyn_test_count / 2);
test_assert(b.count == dyn_test_count / 2);

struct int_arr combined = { 0 };
int_arr_join(&combined, &a);
test_assert(combined.count == dyn_test_count / 2);
test_assert(a.count == 0);
test_assert(a.capacity == 0);
test_assert(!a.items);
for (int i = 0; i < dyn_test_count / 2; ++i) {
test_assert(combined.items[i] == i);
}

int_arr_join(&combined, &b);
test_assert(combined.count == dyn_test_count);
test_assert(b.count == 0);
test_assert(b.capacity == 0);
test_assert(!b.items);
for (int i = 0; i < dyn_test_count; ++i) {
test_assert(combined.items[i] == i);
}

return true;
}
2 changes: 2 additions & 0 deletions tests/tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ static test tests[] = {
{"dyn_array::custom", dyn_array_custom},
{"dyn_array::trim", dyn_array_trim},
{"dyn_array::trim_expand", dyn_array_trim_expand},
{"dyn_array::copy", dyn_array_copy},
{"dyn_array::join", dyn_array_join}
};

#define testCount (sizeof(tests) / sizeof(test))

0 comments on commit 03fe914

Please sign in to comment.