Add a smartlist_grow() function to expand a smartlist

Tests included.
This commit is contained in:
Nick Mathewson 2019-01-10 13:56:22 -05:00
parent 56bda7464f
commit 253fea84cf
3 changed files with 86 additions and 0 deletions

View file

@ -88,6 +88,30 @@ smartlist_ensure_capacity(smartlist_t *sl, size_t size)
#undef MAX_CAPACITY
}
/** Expand <b>sl</b> so that its length is at least <b>new_size</b>,
* filling in previously unused entries with NULL>
*
* Do nothing if <b>sl</b> already had at least <b>new_size</b> elements.
*/
void
smartlist_grow(smartlist_t *sl, size_t new_size)
{
smartlist_ensure_capacity(sl, new_size);
if (new_size > (size_t)sl->num_used) {
/* This memset() should be a no-op: everything else in the smartlist code
* tries to make sure that unused entries are always NULL. Still, that is
* meant as a safety mechanism, so let's clear the memory here.
*/
memset(sl->list + sl->num_used, 0,
sizeof(void *) * (new_size - sl->num_used));
/* This cast is safe, since we already asserted that we were below
* MAX_CAPACITY in smartlist_ensure_capacity(). */
sl->num_used = (int)new_size;
}
}
/** Append element to the end of the list. */
void
smartlist_add(smartlist_t *sl, void *element)

View file

@ -43,6 +43,7 @@ void smartlist_clear(smartlist_t *sl);
void smartlist_add(smartlist_t *sl, void *element);
void smartlist_add_all(smartlist_t *sl, const smartlist_t *s2);
void smartlist_add_strdup(struct smartlist_t *sl, const char *string);
void smartlist_grow(smartlist_t *sl, size_t new_size);
void smartlist_remove(smartlist_t *sl, const void *element);
void smartlist_remove_keeporder(smartlist_t *sl, const void *element);

View file

@ -606,6 +606,66 @@ test_container_smartlist_ints_eq(void *arg)
smartlist_free(sl2);
}
static void
test_container_smartlist_grow(void *arg)
{
(void)arg;
smartlist_t *sl = smartlist_new();
int i;
const char *s[] = { "first", "2nd", "3rd" };
/* case 1: starting from empty. */
smartlist_grow(sl, 10);
tt_int_op(10, OP_EQ, smartlist_len(sl));
for (i = 0; i < 10; ++i) {
tt_ptr_op(smartlist_get(sl, i), OP_EQ, NULL);
}
/* case 2: starting with a few elements, probably not reallocating. */
smartlist_free(sl);
sl = smartlist_new();
smartlist_add(sl, (char*)s[0]);
smartlist_add(sl, (char*)s[1]);
smartlist_add(sl, (char*)s[2]);
smartlist_grow(sl, 5);
tt_int_op(5, OP_EQ, smartlist_len(sl));
for (i = 0; i < 3; ++i) {
tt_ptr_op(smartlist_get(sl, i), OP_EQ, s[i]);
}
tt_ptr_op(smartlist_get(sl, 3), OP_EQ, NULL);
tt_ptr_op(smartlist_get(sl, 4), OP_EQ, NULL);
/* case 3: starting with a few elements, but reallocating. */
smartlist_free(sl);
sl = smartlist_new();
smartlist_add(sl, (char*)s[0]);
smartlist_add(sl, (char*)s[1]);
smartlist_add(sl, (char*)s[2]);
smartlist_grow(sl, 100);
tt_int_op(100, OP_EQ, smartlist_len(sl));
for (i = 0; i < 3; ++i) {
tt_ptr_op(smartlist_get(sl, i), OP_EQ, s[i]);
}
for (i = 3; i < 100; ++i) {
tt_ptr_op(smartlist_get(sl, i), OP_EQ, NULL);
}
/* case 4: shrinking doesn't happen. */
smartlist_free(sl);
sl = smartlist_new();
smartlist_add(sl, (char*)s[0]);
smartlist_add(sl, (char*)s[1]);
smartlist_add(sl, (char*)s[2]);
smartlist_grow(sl, 1);
tt_int_op(3, OP_EQ, smartlist_len(sl));
for (i = 0; i < 3; ++i) {
tt_ptr_op(smartlist_get(sl, i), OP_EQ, s[i]);
}
done:
smartlist_free(sl);
}
/** Run unit tests for bitarray code */
static void
test_container_bitarray(void *arg)
@ -1312,6 +1372,7 @@ struct testcase_t container_tests[] = {
CONTAINER_LEGACY(smartlist_pos),
CONTAINER(smartlist_remove, 0),
CONTAINER(smartlist_ints_eq, 0),
CONTAINER(smartlist_grow, 0),
CONTAINER_LEGACY(bitarray),
CONTAINER_LEGACY(digestset),
CONTAINER_LEGACY(strmap),