Subject: Re: [PATCH 03/16] strvec: introduce `strvec_init_alloc()`

From: Jeff King <[email-masked]>
Date: Mon, 30 Mar 2026 18:46:31 -0400

On Sun, Mar 29, 2026 at 05:40:58PM -0400, Taylor Blau wrote:

> When the caller knows upfront how many elements will be pushed onto a
> `strvec`, it is useful to pre-allocate enough space in the array to fit
> that many elements (and one additional slot to store NULL, indicating
> the end of the list.)

The main reason I didn't add an "alloc" parameter to the initializer
originally is that if you know how many elements you are going to push,
you probably don't need a strvec in the first place (you can just make
an array). But let's wait and see how it gets used in a future patch.

> +void strvec_init_alloc(struct strvec *array, size_t alloc)
> +{
> +	if (!alloc) {
> +		struct strvec blank = STRVEC_INIT;
> +		memcpy(array, &blank, sizeof(*array));
> +	} else {
> +		CALLOC_ARRAY(array->v, st_add(alloc, 1));
> +		array->nr = 0;
> +		array->alloc = alloc + 1;
> +	}
>  }

We use the blank+memcpy approach so that we don't duplicate knowledge of
which elements are in the struct (and which might need to be
initialized). But now there's an implicit zero-ing happening when alloc
is non-zero. Can we write this as:

  struct strvec blank = STRVEC_INIT;
  memcpy(array, &blank, sizeof(*array));
  if (alloc) {
	CALLOC_ARRAY(array->v, st_add(alloc, 1));
	array->alloc = alloc + 1;
  }

The worst case is a useless write of a few struct elements, but I
suspect that an optimizing compiler can even get rid of those.

I doubt we are going to add new elements to a strvec, so this is
arguably just pedantry. It just feels like it's easy enough to do now
while we're thinking about it.

  As an aside, it is sad that we have to CALLOC() ourselves here, as
  there is no reusable "grow" operation. Probably not worth refactoring
  it out, though, though.

-Peff