#ifndef noreturn
#if __STDC_VERSION__ >= 202311L
#define noreturn [[noreturn]]
#elif __STDC_VERSION__ >= 201112L
#define noreturn _Noreturn
#else
#define noreturn
#endif
#endif

struct list {
	struct list *prev, *next;
};

struct array {
	void *val;
	size_t len, cap;
};

struct treenode {
	unsigned long long key;
	void *child[2];
	int height;
	bool new;  /* set by treeinsert if this node was newly allocated */
};

extern char *argv0;

#ifndef countof
#define countof(a) (sizeof(a) / sizeof((a)[0]))
#endif
#define ALIGNDOWN(x, n) ((x) & -(n))
#define ALIGNUP(x, n) ALIGNDOWN((x) + (n) - 1, n)

void warn(const char *, ...);
noreturn void fatal(const char *fmt, ...);

void *reallocarray(void *, size_t, size_t);
void *xreallocarray(void *, size_t, size_t);
void *xmalloc(size_t);

char *progname(char *, char *);

void listinsert(struct list *, struct list *);
void listremove(struct list *);
#define listelement(list, type, member) (type *)((char *)list - offsetof(type, member))

void *arrayadd(struct array *, size_t);
void arrayaddptr(struct array *, void *);
void *arraysetptr(struct array *, size_t, void *);
void *arraygetptr(struct array *, size_t);
void arrayaddbuf(struct array *, const void *, size_t);
void *arraylast(struct array *, size_t);
#define arrayforeach(a, m) for (m = (a)->val; m != (void *)((char *)(a)->val + (a)->len); ++m)

/* map */

struct map {
	size_t len, cap;
	struct mapkey *keys;
	union mapval *vals;
};

struct mapkey {
	unsigned long hash;
	const void *str;
	size_t len;
};

union mapval {
	void *p;
	int i;
};

void mapkey(struct mapkey *, const void *, size_t);
void mapinit(struct map *, size_t);
void mapfree(struct map *, void (*)(void *));
bool mapput(struct map *, struct mapkey *, size_t *);
void *mapget(struct map *, struct mapkey *, size_t *);

/* tree */

void *treeinsert(void **, unsigned long long, size_t);
