/* Copyright © Charliecloud contributors.

   Facilities for typed, heap or stack arrays terminated by an all-zeroes
   element. These are convenient to use because they are normal arrays and
   compatible with lots of APIs. They also eliminate the need for a wrapper
   struct that remembers anything, e.g. number and/or size of elements, and
   generic containers are very hard in C. Disadvantages do include
   (1) all-zero elements cannot be stored, (2) aggressive typecasting is often
   needed, (3) the size of elements must be separately managed.

   Use these lists in Charliecloud unless there is a good justification
   otherwise. (Note that performance is unlikely to be an issue at the lengths
   we have.)

   Iteration example:

     struct foo { int a; float b; };
     struct foo *bar = ...;
     for (int i = 0; bar[i].a != 0; i++)
       do_stuff(bar[i]);

   Note the conditional checks only one field of the struct (`a`) for zero;
   this loop leverages knowledge of this specific data structure that checking
   only `a` is sufficient.

   Setting on stack via literal:

     struct foo bar[] = { {1, 2.0}, {3, 4.0}, {0, 0.0} };

   Heap creation via functions in this interface:

     struct foo baz;
     struct foo *qux = list_new(sizeof(struct foo), 0);
     baz.a = 1;
     baz.b = 2.0;
     list_append((void **)&qux, &baz, sizeof(struct foo));
     list_append((void **)&qux, &((struct foo){3, 4.0}), sizeof(struct foo));

   These two examples create an equivalent list. Note also the C99 trick to
   avoid creating `struct foo` variable for the second append. */

#define _GNU_SOURCE
#pragma once

#include <stddef.h>


/** Function prototypes **/

void list_append(void **ar, void *new, size_t size);
void list_cat(void **dst, void *src, size_t size);
void *list_copy(void *src, size_t size);
size_t list_count(void *ar, size_t size);
void list_dedup_strings(char **ar);
void *list_new_strings(char delim, const char *s);
void *list_new(size_t ct, size_t size);
char *list_stringify(void *list, char delim);
