aboutsummaryrefslogtreecommitdiffstats
path: root/src/stack.h
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2018-04-29 14:07:29 +0200
committerDavid Robillard <d@drobilla.net>2018-11-25 09:21:03 +0100
commitc8a91d6fcae2b5c7121f059f75e2a164735e56c1 (patch)
tree17ac52eddfb294bd8746fd1d6db046f6ef97ec98 /src/stack.h
parentf6511f88fe6cab53f6e9e2044926876fac59938b (diff)
downloadserd-c8a91d6fcae2b5c7121f059f75e2a164735e56c1.tar.gz
serd-c8a91d6fcae2b5c7121f059f75e2a164735e56c1.tar.bz2
serd-c8a91d6fcae2b5c7121f059f75e2a164735e56c1.zip
Clean up and separate internal headers
Diffstat (limited to 'src/stack.h')
-rw-r--r--src/stack.h113
1 files changed, 113 insertions, 0 deletions
diff --git a/src/stack.h b/src/stack.h
new file mode 100644
index 00000000..a8298c0d
--- /dev/null
+++ b/src/stack.h
@@ -0,0 +1,113 @@
+/*
+ Copyright 2011-2018 David Robillard <http://drobilla.net>
+
+ Permission to use, copy, modify, and/or distribute this software for any
+ purpose with or without fee is hereby granted, provided that the above
+ copyright notice and this permission notice appear in all copies.
+
+ THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef SERD_STACK_H
+#define SERD_STACK_H
+
+#include "serd_internal.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+
+/** An offset to start the stack at. Note 0 is reserved for NULL. */
+#define SERD_STACK_BOTTOM sizeof(void*)
+
+/** A dynamic stack in memory. */
+typedef struct {
+ char* buf; ///< Stack memory
+ size_t buf_size; ///< Allocated size of buf (>= size)
+ size_t size; ///< Conceptual size of stack in buf
+} SerdStack;
+
+static inline SerdStack
+serd_stack_new(size_t size)
+{
+ SerdStack stack;
+ stack.buf = (char*)calloc(1, size);
+ stack.buf_size = size;
+ stack.size = SERD_STACK_BOTTOM;
+ return stack;
+}
+
+static inline bool
+serd_stack_is_empty(SerdStack* stack)
+{
+ return stack->size <= SERD_STACK_BOTTOM;
+}
+
+static inline void
+serd_stack_free(SerdStack* stack)
+{
+ free(stack->buf);
+ stack->buf = NULL;
+ stack->buf_size = 0;
+ stack->size = 0;
+}
+
+static inline void*
+serd_stack_push(SerdStack* stack, size_t n_bytes)
+{
+ const size_t new_size = stack->size + n_bytes;
+ if (stack->buf_size < new_size) {
+ stack->buf_size += (stack->buf_size >> 1); // *= 1.5
+ stack->buf = (char*)realloc(stack->buf, stack->buf_size);
+ }
+ char* const ret = (stack->buf + stack->size);
+ stack->size = new_size;
+ return ret;
+}
+
+static inline void
+serd_stack_pop(SerdStack* stack, size_t n_bytes)
+{
+ assert(stack->size >= n_bytes);
+ stack->size -= n_bytes;
+}
+
+static inline void*
+serd_stack_push_aligned(SerdStack* stack, size_t n_bytes, size_t align)
+{
+ // Push one byte to ensure space for a pad count
+ serd_stack_push(stack, 1);
+
+ // Push padding if necessary
+ const uint8_t pad = align - stack->size % align;
+ if (pad > 0) {
+ serd_stack_push(stack, pad);
+ }
+
+ // Set top of stack to pad count so we can properly pop later
+ stack->buf[stack->size - 1] = pad;
+
+ // Push requested space at aligned location
+ return serd_stack_push(stack, n_bytes);
+}
+
+static inline void
+serd_stack_pop_aligned(SerdStack* stack, size_t n_bytes)
+{
+ // Pop requested space down to aligned location
+ serd_stack_pop(stack, n_bytes);
+
+ // Get amount of padding from top of stack
+ const uint8_t pad = stack->buf[stack->size - 1];
+
+ // Pop padding and pad count
+ serd_stack_pop(stack, pad + 1);
+}
+
+#endif // SERD_STACK_H