This is similar to vector_clone(), except that it performs a shallow copy of the vector instead of using memcpy(). The vector that is stolen from is for all intents and purposes unusable after calling this function.
This is useful for cases where a vector is built up and then needs to be copied as part of a struct initializer. Signed-off-by: Mark Michelson <[email protected]> --- v1 -> v2: * Expanded the test case in test-vector.c. --- lib/vec.c | 18 +++++++++++++++ lib/vec.h | 1 + tests/ovn.at | 2 ++ tests/test-vector.c | 54 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+) diff --git a/lib/vec.c b/lib/vec.c index 97e6b6549..e4bb72c2c 100644 --- a/lib/vec.c +++ b/lib/vec.c @@ -168,6 +168,24 @@ vector_clone(struct vector *vec) return clone; } +/* Performs a shallow copy of vec into another structure. vec is + * re-initialized after this operation and is safe to re-use or + * destroy. However, its buffer will be empty. + */ +struct vector +vector_steal(struct vector *vec) +{ + struct vector thief = (struct vector) { + .buffer = vec->buffer, + .esize = vec->esize, + .len = vec->len, + .capacity = vec->capacity, + }; + + vector_init(vec); + return thief; +} + /* Reserves additional space to fit extra n items. */ void vector_reserve(struct vector *vec, size_t n) diff --git a/lib/vec.h b/lib/vec.h index ff8f69a5e..50dd09bc4 100644 --- a/lib/vec.h +++ b/lib/vec.h @@ -76,6 +76,7 @@ bool vector_remove_block(struct vector *vec, size_t start, size_t end); void *vector_get_ptr(const struct vector *vec, size_t index); void vector_shrink_to_fit(struct vector *vec); struct vector vector_clone(struct vector *vec); +struct vector vector_steal(struct vector *vec); void vector_reserve(struct vector *vec, size_t n); /* Pushes element into the end of the vector. */ diff --git a/tests/ovn.at b/tests/ovn.at index 94ed06c63..8081fb04c 100644 --- a/tests/ovn.at +++ b/tests/ovn.at @@ -2453,6 +2453,8 @@ check ovstest test-vector shrink check ovstest test-vector clone check ovstest test-vector pointers + +check ovstest test-vector steal AT_CLEANUP AT_SETUP([Sparse array operations]) diff --git a/tests/test-vector.c b/tests/test-vector.c index f2bad0c33..f91741856 100644 --- a/tests/test-vector.c +++ b/tests/test-vector.c @@ -254,6 +254,59 @@ test_clone(struct ovs_cmdl_context *ctx OVS_UNUSED) vector_destroy(&clone); } +static void +test_steal(struct ovs_cmdl_context *ctx OVS_UNUSED) +{ + uint32_t elements[3] = {0, 1, 2}; + struct vector vec = VECTOR_CAPACITY_INITIALIZER(uint32_t, 10); + vector_push_array(&vec, elements, ARRAY_SIZE(elements)); + + struct vector thief = vector_steal(&vec); + ovs_assert(vector_capacity(&thief) == 10); + ovs_assert(vector_len(&thief) == 3); + + ovs_assert(vector_capacity(&vec) == 0); + ovs_assert(vector_len(&vec) == 0); + + size_t i = 0; + uint32_t num; + VECTOR_FOR_EACH (&thief, num) { + ovs_assert(elements[i++] == num); + } + ovs_assert(i == ARRAY_SIZE(elements)); + + vector_shrink_to_fit(&thief); + ovs_assert(vector_capacity(&thief) == 3); + ovs_assert(vector_len(&thief) == 3); + + /* Let's make sure the original vec has been unaffected by + * the changes to thief. + */ + ovs_assert(vector_capacity(&vec) == 0); + ovs_assert(vector_len(&vec) == 0); + + /* The vast majority of the time, the reason you would want to steal a + * vector is because it is going to go out of scope and this prevents + * having to destroy it. However, it is also possible to steal a vector as + * a way of saving its contents elsewhere and resetting it. Let's make sure + * we can still operate on vec after it has been stolen. + */ + uint32_t more_elements[5] = {3, 4, 5, 6, 7}; + vector_push_array(&vec, more_elements, ARRAY_SIZE(more_elements)); + ovs_assert(vector_capacity(&vec) == 5); + ovs_assert(vector_len(&vec) == 5); + + /* And now let's make sure the thief is unaffected by changes to vec. */ + ovs_assert(vector_capacity(&thief) == 3); + ovs_assert(vector_len(&thief) == 3); + + /* Since we have re-added elements to vec, we now need to destroy it. + * If we had stolen from it and left it alone, this would be unnecessary. + */ + vector_destroy(&vec); + vector_destroy(&thief); +} + static void test_pointers(struct ovs_cmdl_context *ctx OVS_UNUSED) { @@ -305,6 +358,7 @@ test_vector_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED) {"shrink", NULL, 0, 0, test_shrink, OVS_RO}, {"clone", NULL, 0, 0, test_clone, OVS_RO}, {"pointers", NULL, 0, 0, test_pointers, OVS_RO}, + {"steal", NULL, 0, 0, test_steal, OVS_RO}, {NULL, NULL, 0, 0, NULL, OVS_RO}, }; struct ovs_cmdl_context ctx; -- 2.55.0 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
