#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include "common/strbuild.h"

void sfdo_strbuild_init(struct sfdo_strbuild *strbuild) {
	strbuild->data = NULL;
	strbuild->len = strbuild->cap = 0;
}

void sfdo_strbuild_finish(struct sfdo_strbuild *strbuild) {
	free(strbuild->data);
}

void sfdo_strbuild_reset(struct sfdo_strbuild *strbuild) {
	strbuild->len = 0;
}

bool sfdo_strbuild_add(
		struct sfdo_strbuild *strbuild, const struct sfdo_string *items, size_t n_items) {
	size_t total_len = 0;
	for (size_t i = 0; i < n_items; i++) {
		const struct sfdo_string *item = &items[i];
		total_len += item->len;
	}

	size_t cap = strbuild->cap == 0 ? 4096 : strbuild->cap;
	// end must be strictly bigger than cap to have space for a null terminator
	size_t end = strbuild->len + total_len;
	while (end >= cap) {
		if (cap > SIZE_MAX / 2) {
			return false;
		}
		cap *= 2;
	}
	if (strbuild->cap != cap) {
		char *pb_data = realloc(strbuild->data, cap);
		if (pb_data == NULL) {
			return false;
		}
		strbuild->data = pb_data;
		strbuild->cap = cap;
	}

	for (size_t i = 0; i < n_items; i++) {
		const struct sfdo_string *item = &items[i];
		memcpy(&strbuild->data[strbuild->len], item->data, item->len);
		strbuild->len += item->len;
	}

	strbuild->data[strbuild->len] = '\0';

	return true;
}
