Skip to content

Commit b05474a

Browse files
rjustogitster
authored andcommitted
strvec: strvec_splice() to a statically initialized vector
We use a singleton empty array to initialize a `struct strvec`, similar to the empty string singleton we use to initialize a `struct strbuf`. Note that an empty strvec instance (with zero elements) does not necessarily need to be an instance initialized with the singleton. Let's refer to strvec instances initialized with the singleton as "empty-singleton" instances. As a side note, this is the current `strvec_pop()`: void strvec_pop(struct strvec *array) { if (!array->nr) return; free((char *)array->v[array->nr - 1]); array->v[array->nr - 1] = NULL; array->nr--; } So, with `strvec_pop()` an instance can become empty but it does not going to be the an "empty-singleton". This "empty-singleton" circumstance requires us to be careful when adding elements to instances. Specifically, when adding the first element: we detach the strvec instance from the singleton and set the internal pointer in the instance to NULL. After this point we apply `realloc()` on the pointer. We do this in `strvec_push_nodup()`, for example. The recently introduced `strvec_splice()` API is expected to be normally used with non-empty strvec's. However, it can also end up being used with "empty-singleton" strvec's: struct strvec arr = STRVEC_INIT; int a = 0, b = 0; ... no modification to arr, a or b ... const char *rep[] = { "foo" }; strvec_splice(&arr, a, b, rep, ARRAY_SIZE(rep)); So, we'll try to add elements to an "empty-singleton" strvec instance. Avoid misapplying `realloc()` to the singleton in `strvec_splice()` by adding a special case for "empty-singleton" strvec's. Signed-off-by: Rubén Justo <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 60c778d commit b05474a

File tree

2 files changed

+16
-4
lines changed

2 files changed

+16
-4
lines changed

strvec.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,16 +61,18 @@ void strvec_splice(struct strvec *array, size_t idx, size_t len,
6161
{
6262
if (idx + len > array->nr)
6363
BUG("range outside of array boundary");
64-
if (replacement_len > len)
64+
if (replacement_len > len) {
65+
if (array->v == empty_strvec)
66+
array->v = NULL;
6567
ALLOC_GROW(array->v, array->nr + (replacement_len - len) + 1,
6668
array->alloc);
69+
}
6770
for (size_t i = 0; i < len; i++)
6871
free((char *)array->v[idx + i]);
69-
if (replacement_len != len) {
72+
if ((replacement_len != len) && array->nr)
7073
memmove(array->v + idx + replacement_len, array->v + idx + len,
7174
(array->nr - idx - len + 1) * sizeof(char *));
72-
array->nr += (replacement_len - len);
73-
}
75+
array->nr += replacement_len - len;
7476
for (size_t i = 0; i < replacement_len; i++)
7577
array->v[idx + i] = xstrdup(replacement[i]);
7678
}

t/unit-tests/strvec.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,16 @@ void test_strvec__pushv(void)
8888
strvec_clear(&vec);
8989
}
9090

91+
void test_strvec__splice_just_initialized_strvec(void)
92+
{
93+
struct strvec vec = STRVEC_INIT;
94+
const char *replacement[] = { "foo" };
95+
96+
strvec_splice(&vec, 0, 0, replacement, ARRAY_SIZE(replacement));
97+
check_strvec(&vec, "foo", NULL);
98+
strvec_clear(&vec);
99+
}
100+
91101
void test_strvec__splice_with_same_size_replacement(void)
92102
{
93103
struct strvec vec = STRVEC_INIT;

0 commit comments

Comments
 (0)