stack_str

Stack for strings
git clone git://www.tkruger.se/stack_str.git
Log | Files | Refs | README

commit 8822860aace4bcf868c1798d8ba019fb8c700191
Author: olikru <olikru@tkruger.se>
Date:   Mon,  8 Jan 2024 11:51:41 +0100

initial

Diffstat:
AMakefile | 40++++++++++++++++++++++++++++++++++++++++
AREADME | 14++++++++++++++
Astack_str.c | 38++++++++++++++++++++++++++++++++++++++
Astack_str.h | 70++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest_stack_str.c | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 249 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -0,0 +1,40 @@ +.SUFFIXES: .c .o .so +CC=clang +CFLAGS+=-std=c99 -pedantic -Wall -Werror -Wstrict-prototypes +CFLAGS+=-Wmissing-prototypes -Wmissing-declarations -Wshadow +CFLAGS+=-Wpointer-arith -Wcast-qual -Wsign-compare +CFLAGS+=-O2 -g +CFLAGS+=-fstack-protector-all -Wtype-limits -fno-common +CFLAGS+=-fno-builtin +CFLAGS+=-I/usr/local/include + +INSTALL_PATH=$(HOME)/.local +BUILD=build + +TEST_SOURCE=test_stack_str.c +HEADER=stack_str.h +OBJS=stack_str.o +SHARED=stack_str.so +LIBSHARED=libstack_str.so + +all: build $(OBJS) $(SHARED) test + +.c.o: + $(CC) $(CFLAGS) -c $< -o $(BUILD)/$@ + +.o.so: + $(CC) -shared -fPIC $(BUILD)/$< -o $(BUILD)/$@ + +test: $(TEST_SOURCE) + $(CC) $(CFLAGS) -o $(BUILD)/test $(TEST_SOURCE) $(BUILD)/$(OBJS) + +build: + mkdir -p $(BUILD) + +install: + cp $(BUILD)/$(SHARED) $(INSTALL_PATH)/lib/$(LIBSHARED) + chmod 644 $(INSTALL_PATH)/lib/$(LIBSHARED) + cp $(HEADER) $(INSTALL_PATH)/include/ + +clean: + rm -rf $(BUILD) diff --git a/README b/README @@ -0,0 +1,14 @@ +stack_str +========= + +Small library for stacks of stringss. This stack is only capable of +increasing it's allocated size, and never shrinking. The stack also +contains char pointers. Make sure the strings are nice and +null-terminated and with size implicitly known. + + typedef struct { + size_t nmemb; + size_t alloc; + + char **data; + } stack_str; diff --git a/stack_str.c b/stack_str.c @@ -0,0 +1,38 @@ +#include "stack_str.h" + +void stack_str_init(stack_str *d) { + d->nmemb = 0; + d->alloc = BASE_STACK_STR_SIZE; + + d->data = calloc(d->alloc, sizeof(*(d->data))); +} + +void stack_str_clear(stack_str *d) { + d->nmemb = 0; + free(d->data); + d->data = NULL; +} + +void stack_str_push(stack_str *d, char *x) { + if (d->alloc <= d->nmemb) { + d->alloc <<= 1; + d->data = realloc(d->data, d->alloc * sizeof(*(d->data))); + } + + d->data[d->nmemb] = x; + d->nmemb++; +} + +char *stack_str_get(const stack_str *d, const size_t i) { return d->data[i]; } + +char *stack_str_getlast(const stack_str *d) { + return stack_str_get(d, d->nmemb - 1); +} + +char *stack_str_pop(stack_str *d) { + if (d->nmemb == 0) + return STACK_STR_EMPTY_POP; + char *r = stack_str_getlast(d); + d->nmemb--; + return r; +} diff --git a/stack_str.h b/stack_str.h @@ -0,0 +1,70 @@ +#ifndef STACK_STR_H +#define STACK_STR_H + +#include <stdint.h> +#include <stdlib.h> + +#define BASE_STACK_STR_SIZE 256 +#define STACK_STR_EMPTY_POP (NULL) + +typedef struct { + size_t nmemb; + size_t alloc; + + char **data; +} stack_str; + +/** + * Initialization of stack. + * + * Initialises memory for the stack. Use clear. + * + * @param d pointer to the address where to write the new stack + */ +void stack_str_init(stack_str *d); + +/** + * Clear a stack + * + * @param d pointer to the stack to clear + */ +void stack_str_clear(stack_str *d); + +/** + * Pushes a string (char pointer) onto the stack. + * + * Note that this does not copy the string, it just pushes the pointer to the + * stack. + * + * @param d pointer to the stack + * @param x the string (char pointer) to push + */ +void stack_str_push(stack_str *d, char *x); + +/** + * Gets the element at index i in the stack. + * + * @param d pointer to the stack + * @param i the index to get element at + * @return the value (the char pointer) of the element at index i + */ +char *stack_str_get(const stack_str *d, const size_t i); + +/** + * Get the last (top) element of a stack. + * + * @param d pointer to the stack + */ +char *stack_str_getlast(const stack_str *d); + +/** + * Pop an element of the stack. + * + * Note that popping never decreases the amount of memory allocated. + * If memory is an issue the stacks have to be destroyed and replaced. + * + * @param d pointer to the stack + */ +char *stack_str_pop(stack_str *d); + +#endif diff --git a/test_stack_str.c b/test_stack_str.c @@ -0,0 +1,87 @@ +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <assert.h> +#include "stack_str.h" + +static void test_stack_str_init() { + stack_str t; + stack_str_init(&t); + + assert(t.nmemb == 0); + assert(t.alloc > 0); + assert(t.data != NULL); + + stack_str_clear(&t); +} + +static void test_stack_str_push() { + stack_str t; + stack_str_init(&t); + + uint64_t i; + char buf[2 * BASE_STACK_STR_SIZE][256]; + for (i = 0; i < 2 * BASE_STACK_STR_SIZE; i++) { + snprintf(buf[i], 256, "%llu", i); + stack_str_push(&t, buf[i]); + } + + assert(t.alloc == 2 * BASE_STACK_STR_SIZE); + assert(t.nmemb == 2 * BASE_STACK_STR_SIZE); + for (i = 0; i < 2 * BASE_STACK_STR_SIZE; i++) { + assert(strncmp(buf[i], t.data[i], 256) == 0); + } + + stack_str_clear(&t); +} + +static void test_stack_str_get_getlast() { + stack_str t; + stack_str_init(&t); + + uint64_t i; + char buf[2 * BASE_STACK_STR_SIZE][256]; + for (i = 0; i < 2 * BASE_STACK_STR_SIZE; i++) { + snprintf(buf[i], 256, "%llu", i); + stack_str_push(&t, buf[i]); + } + + for (i = 0; i < t.nmemb; i++) { + assert(stack_str_get(&t, i) == buf[i]); + } + assert(stack_str_getlast(&t) == buf[2 * BASE_STACK_STR_SIZE - 1]); + + stack_str_clear(&t); +} + +static void test_stack_str_pop() { + stack_str t; + stack_str_init(&t); + + char *strs[3] = {"hello", "world", "this is a msg"}; + + stack_str_push(&t, strs[0]); + stack_str_push(&t, strs[1]); + stack_str_push(&t, strs[2]); + + assert(t.nmemb == 3); + assert(stack_str_pop(&t) == strs[2]); + assert(t.nmemb == 2); + assert(stack_str_pop(&t) == strs[1]); + assert(t.nmemb == 1); + assert(stack_str_pop(&t) == strs[0]); + assert(t.nmemb == 0); + assert(stack_str_pop(&t) == STACK_STR_EMPTY_POP); + assert(t.nmemb == 0); + + stack_str_clear(&t); +} + +int main() { + test_stack_str_init(); + test_stack_str_push(); + test_stack_str_pop(); + test_stack_str_get_getlast(); + + printf("test ok\n"); +}