/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "ucx/stack.h" #include 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) { // skip the memset by using malloc void *space = ucx_stack_malloc(stack, nelem*elsize); if (space) { memcpy(space, data, nelem*elsize); } return space; }