#include <cassert>
#include <cstdlib>
#include <cstring>
#include "clo_vec.hpp"
struct clo_vec *
clo_vec_alloc(size_t size)
{
struct clo_vec *clovec = (struct clo_vec *)malloc(sizeof(*clovec));
assert(clovec != NULL);
TAILQ_INIT(&clovec->allocs);
TAILQ_INIT(&clovec->args);
clovec->nallocs = 0;
clovec->size = size;
struct clo_vec_args *args =
(struct clo_vec_args *)malloc(sizeof(*args));
assert(args != NULL);
args->args = calloc(1, size);
assert(args->args != NULL);
TAILQ_INSERT_TAIL(&clovec->args, args, next);
clovec->nargs = 1;
return clovec;
}
void
clo_vec_free(struct clo_vec *clovec)
{
assert(clovec != NULL);
while (!TAILQ_EMPTY(&clovec->allocs)) {
struct clo_vec_alloc *alloc = TAILQ_FIRST(&clovec->allocs);
TAILQ_REMOVE(&clovec->allocs, alloc, next);
free(alloc->ptr);
free(alloc);
}
while (!TAILQ_EMPTY(&clovec->args)) {
struct clo_vec_args *args = TAILQ_FIRST(&clovec->args);
TAILQ_REMOVE(&clovec->args, args, next);
free(args->args);
free(args);
}
free(clovec);
}
void *
clo_vec_get_args(struct clo_vec *clovec, size_t i)
{
if (i >= clovec->nargs)
return NULL;
size_t c = 0;
struct clo_vec_args *args;
TAILQ_FOREACH(args, &clovec->args, next)
{
if (c == i)
return args->args;
c++;
}
return NULL;
}
int
clo_vec_add_alloc(struct clo_vec *clovec, void *ptr)
{
struct clo_vec_alloc *alloc =
(struct clo_vec_alloc *)malloc(sizeof(*alloc));
assert(alloc != NULL);
alloc->ptr = ptr;
TAILQ_INSERT_TAIL(&clovec->allocs, alloc, next);
clovec->nallocs++;
return 0;
}
static void
clo_vec_grow(struct clo_vec *clovec, size_t new_len)
{
size_t nargs = new_len - clovec->nargs;
size_t i;
for (i = 0; i < nargs; i++) {
struct clo_vec_args *args =
(struct clo_vec_args *)calloc(1, sizeof(*args));
assert(args != NULL);
TAILQ_INSERT_TAIL(&clovec->args, args, next);
args->args = malloc(clovec->size);
assert(args->args != NULL);
void *argscpy = clo_vec_get_args(clovec, i % clovec->nargs);
assert(argscpy != NULL);
memcpy(args->args, argscpy, clovec->size);
}
clovec->nargs = new_len;
}
struct clo_vec_vlist *
clo_vec_vlist_alloc(void)
{
struct clo_vec_vlist *list =
(struct clo_vec_vlist *)malloc(sizeof(*list));
assert(list != NULL);
list->nvalues = 0;
TAILQ_INIT(&list->head);
return list;
}
void
clo_vec_vlist_free(struct clo_vec_vlist *list)
{
assert(list != NULL);
while (!TAILQ_EMPTY(&list->head)) {
struct clo_vec_value *val = TAILQ_FIRST(&list->head);
TAILQ_REMOVE(&list->head, val, next);
free(val->ptr);
free(val);
}
free(list);
}
void
clo_vec_vlist_add(struct clo_vec_vlist *list, void *ptr, size_t size)
{
struct clo_vec_value *val =
(struct clo_vec_value *)malloc(sizeof(*val));
assert(val != NULL);
val->ptr = malloc(size);
assert(val->ptr != NULL);
memcpy(val->ptr, ptr, size);
TAILQ_INSERT_TAIL(&list->head, val, next);
list->nvalues++;
}
int
clo_vec_memcpy(struct clo_vec *clovec, size_t off, size_t size, void *ptr)
{
if (off + size > clovec->size)
return -1;
size_t i;
for (i = 0; i < clovec->nargs; i++) {
char *args = (char *)clo_vec_get_args(clovec, i);
char *dptr = args + off;
memcpy(dptr, ptr, size);
}
return 0;
}
int
clo_vec_memcpy_list(struct clo_vec *clovec, size_t off, size_t size,
struct clo_vec_vlist *list)
{
if (off + size > clovec->size)
return -1;
size_t len = clovec->nargs;
if (list->nvalues > 1)
clo_vec_grow(clovec, clovec->nargs * list->nvalues);
struct clo_vec_value *value;
size_t value_i = 0;
size_t i;
TAILQ_FOREACH(value, &list->head, next)
{
for (i = value_i * len; i < (value_i + 1) * len; i++) {
char *args = (char *)clo_vec_get_args(clovec, i);
char *dptr = args + off;
memcpy(dptr, value->ptr, size);
}
value_i++;
}
return 0;
}