#include "ucx/stack.h"
#include <string.h>
static size_t ucx_stack_align(
size_t n) {
int align = n %
sizeof(
void*);
if (align) {
n +=
sizeof(
void*) - align;
}
return n;
}
void ucx_stack_init(UcxStack *stack,
char* space,
size_t size) {
stack->size = size - size %
sizeof(
void*);
stack->space = space;
stack->top =
NULL;
stack->allocator.pool = stack;
stack->allocator.malloc = (ucx_allocator_malloc) ucx_stack_malloc;
stack->allocator.calloc = (ucx_allocator_calloc) ucx_stack_calloc;
stack->allocator.realloc = (ucx_allocator_realloc) ucx_stack_realloc;
stack->allocator.free = (ucx_allocator_free) ucx_stack_free;
}
void *ucx_stack_malloc(UcxStack *stack,
size_t n) {
if (ucx_stack_avail(stack) < ucx_stack_align(n)) {
return NULL;
}
else {
char *prev = stack->top;
if (stack->top) {
stack->top += ucx_stack_align(ucx_stack_topsize(stack));
}
else {
stack->top = stack->space;
}
((
struct ucx_stack_metadata*)stack->top)->prev = prev;
((
struct ucx_stack_metadata*)stack->top)->size = n;
stack->top +=
sizeof(
struct ucx_stack_metadata);
return stack->top;
}
}
void *ucx_stack_calloc(UcxStack *stack,
size_t nelem,
size_t elsize) {
void *mem = ucx_stack_malloc(stack, nelem*elsize);
memset(mem,
0, nelem*elsize);
return mem;
}
void *ucx_stack_realloc(UcxStack *stack,
void *ptr,
size_t n) {
if (ptr == stack->top) {
if (stack->size - (stack->top - stack->space) < ucx_stack_align(n)) {
return NULL;
}
else {
((
struct ucx_stack_metadata*)stack->top -
1)->size = n;
return ptr;
}
}
else {
if (ucx_stack_align(((
struct ucx_stack_metadata*)ptr -
1)->size) <
ucx_stack_align(n)) {
void *nptr = ucx_stack_malloc(stack, n);
if (nptr) {
memcpy(nptr, ptr, n);
ucx_stack_free(stack, ptr);
return nptr;
}
else {
return NULL;
}
}
else {
((
struct ucx_stack_metadata*)ptr -
1)->size = n;
return ptr;
}
}
}
void ucx_stack_free(UcxStack *stack,
void *ptr) {
if (ptr == stack->top) {
stack->top = ((
struct ucx_stack_metadata*) stack->top -
1)->prev;
}
else {
struct ucx_stack_metadata *next = (
struct ucx_stack_metadata*)(
(
char*)ptr +
ucx_stack_align(((
struct ucx_stack_metadata*) ptr -
1)->size)
);
next->prev = ((
struct ucx_stack_metadata*) ptr -
1)->prev;
}
}
void ucx_stack_popn(UcxStack *stack,
void *dest,
size_t n) {
if (ucx_stack_empty(stack)) {
return;
}
if (dest) {
size_t len = ucx_stack_topsize(stack);
if (len > n) {
len = n;
}
memcpy(dest, stack->top, len);
}
ucx_stack_free(stack, stack->top);
}
size_t ucx_stack_avail(UcxStack *stack) {
size_t avail = ((stack->top ? (stack->size
- (stack->top - stack->space)
- ucx_stack_align(ucx_stack_topsize(stack)))
: stack->size));
if (avail >
sizeof(
struct ucx_stack_metadata)) {
return avail -
sizeof(
struct ucx_stack_metadata);
}
else {
return 0;
}
}
void *ucx_stack_push(UcxStack *stack,
size_t n,
const void *data) {
void *space = ucx_stack_malloc(stack, n);
if (space) {
memcpy(space, data, n);
}
return space;
}
void *ucx_stack_pusharr(UcxStack *stack,
size_t nelem,
size_t elsize,
const void *data) {
void *space = ucx_stack_malloc(stack, nelem*elsize);
if (space) {
memcpy(space, data, nelem*elsize);
}
return space;
}