diff --git a/util/stack.c b/util/stack.c new file mode 100644 index 0000000..dd842d4 --- /dev/null +++ b/util/stack.c @@ -0,0 +1,71 @@ + +#include "stack.h" +#include "../runtime/stdio.h" +#include + + +void stack_InitBuffered(stack *s, void *buffer, uintptr_t size) { + s->data = buffer; + s->size = size; + s->top = buffer + size; +} + +void stack_PushByte(stack *s, const uint8_t b) { + if (s->top <= s->data) { + io_Printf("stack_PushByte: full[%llu bytes], discarding byte 0x%x\n", s->size, b); + return; + } + *(uint8_t *)--s->top = b; +} + +uint8_t stack_PopByte(stack *s) { + if (s->top == s->data + s->size) { + io_WriteConsoleASCII("stack_PopByte: popping an empty stack\n"); + return 0; + } + return *(uint8_t *)s->top++; +} + +void stack_Push(stack *s, const void *buffer, uintptr_t size) { + if (stack_Space(s) < size) { + io_Printf("stack_Push: insufficient space (%d/%d bytes, want %d bytes)\n", stack_Size(s), s->size, size); + return; + } + s->top -= size; + memcpy(s->top, buffer, size); +} + +uintptr_t stack_Pop(stack *s, void *buffer, uintptr_t size) { + if (stack_Size(s) < size) + return 0; + memcpy(buffer, s->top, size); + s->top += size; + return size; +} + +uint8_t stack_TopByte(stack *s) { + if (stack_Empty(s)) { + io_WriteConsoleASCII("stack_TopByte: called on an empty stack\n"); + return 0; + } + return *(uint8_t *)s->top; +} + +uintptr_t stack_Top(stack *s, void *buffer, uintptr_t size) { + if (stack_Size(s) < size) + return 0; + memcpy(buffer, s->top, size); + return size; +} + +bool stack_Empty(stack *s) { + return s->top == s->data + s->size; +} + +uintptr_t stack_Size(stack *s) { + return s->data + s->size - s->top; +} + +uintptr_t stack_Space(stack *s) { + return s->top - s->data; +} diff --git a/util/stack.h b/util/stack.h new file mode 100644 index 0000000..caa7274 --- /dev/null +++ b/util/stack.h @@ -0,0 +1,52 @@ +#pragma once + +#include "../main.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct { + void * data; // the data buffer + uintptr_t size; // size of data buffer + void * top; // top of the stack, the stack grows downward (from data+size to data) +} stack; + +// initialize a stack with a existing buffer +void stack_InitBuffered(stack *s, void *buffer, uintptr_t size); + +// pushes one byte to the stack, discarding if full +void stack_PushByte(stack *s, const uint8_t b); + +// pops one byte from the top of the stack, returning it +uint8_t stack_PopByte(stack *s); + +// pushes Size bytes to the stack, none written if there is not space for all the bytes +void stack_Push(stack *s, const void *buffer, uintptr_t size); + +// pops Size bytes from the stack, none popped if there are no enough data +// returns the number of bytes popped (either Size or 0) +uintptr_t stack_Pop(stack *s, void *buffer, uintptr_t size); + +// return the byte at the top of the stack +uint8_t stack_TopByte(stack *s); + +// copy the bytes at the top of the stack +// returns the number of bytes copied +uintptr_t stack_Top(stack *s, void *buffer, uintptr_t size); + +// tells if the stack is empty +bool stack_Empty(stack *s); + +// returns the number of bytes in the stack +uintptr_t stack_Size(stack *s); + +// returns the empty space left in the stack +uintptr_t stack_Space(stack *s); + + +#ifdef __cplusplus +} +#endif