liblash

A bianry tree implementation used for game development from scratch
git clone git://holbrook.no/liblash.git
Log | Files | Refs | LICENSE

commit b7ac2db355af4d0d4724a969aa5044e3714d1865
Author: nolash <dev@holbrook.no>
Date:   Sun,  5 Jan 2020 21:36:17 +0100

initial commit

Diffstat:
AMakefile | 20++++++++++++++++++++
Alash_debug_log.c | 78++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alash_debug_log.h | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alash_debug_timer.c | 47+++++++++++++++++++++++++++++++++++++++++++++++
Alash_debug_timer.h | 29+++++++++++++++++++++++++++++
Alash_endian.c | 44++++++++++++++++++++++++++++++++++++++++++++
Alash_endian.h | 19+++++++++++++++++++
Alash_hex.c | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alash_hex.h | 8++++++++
Alash_tree3.c | 198+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alash_tree3.h | 135+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alash_tree3_dump.c | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alash_tree3_dump.h | 79+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atests/debuglog.c | 27+++++++++++++++++++++++++++
Atests/debuglogmaster.c | 8++++++++
Atests/debugtimer.c | 24++++++++++++++++++++++++
Atests/tree3.c | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atests/tree3_console.c | 74++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atests/tree3_shifttest.c | 84+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
19 files changed, 1130 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -0,0 +1,20 @@ +CFLAGS = -I.. + +src = $(wildcard *.c) + +all: liblash.a + +liblash.a: $(src:.c=.o) + ar cq $@ $^ + +#shared: +# $(CC) -Wall -I$(INCLUDE) -o lash_tree_lib.o -fPIC -c lash_tree3.c +# $(CC) -Wall -I$(INCLUDE) -o lash_tree_dump_lib.o -fPIC -c lash_tree3_dump.c +# $(CC) -shared -Wl,-soname,liblash.so.0 -o $(SHAREDOBJECTDIR)liblash.so lash_tree_lib.o lash_tree_dump_lib.o +# $(CC) -Wall -I$(INCLUDE) -o lash_debug_log_lib.o -fPIC -c lash_debug_log.c +# $(CC) -Wall -I$(INCLUDE) -o lash_debug_timer_lib.o -fPIC -c lash_debug_timer.c +# $(CC) -shared -Wl,-soname,liblashdebug.so.0 -o $(SHAREDOBJECTDIR)liblashdebug.so lash_debug_log_lib.o lash_debug_timer_lib.o + +.PHONY: clean +clean: + rm -rf *.a *.o $(TESTDIR)*.o $(TESTDIR)*_bin diff --git a/lash_debug_log.c b/lash_debug_log.c @@ -0,0 +1,78 @@ +#include <stdlib.h> +#include <stdio.h> +#include <time.h> + +#include "lash_debug_log.h" + +struct timespec _timecontainer; + +int lash_debugLogInit(lash_debug_log_t *log, int autoflush) { + + log->capacity = 0; + log->items = (lash_debug_log_item_t*)malloc(sizeof(lash_debug_log_item_t) * LASH_DEBUG_LOG_CAPACITY_CHUNK); + + if (log->items == NULL) { + log = NULL; + return 1; + } + + log->error_string_buffer = (char*)calloc(LASH_DEBUG_LOG_CAPACITY_DESCRIPTION, sizeof(char)); + + if (log->error_string_buffer == NULL) { + log = NULL; + return 1; + } + + log->capacity = LASH_DEBUG_LOG_CAPACITY_CHUNK; + log->count = 0; + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &_timecontainer); + log->ns_start = _timecontainer.tv_nsec; + log->autoflush = autoflush != 0 ? 1 : 0; + + return 0; +} + +/** + * TODO Auto extend memory for log if capacity runs out + */ + +int lash_debugLogAdd(lash_debug_log_t *log, char *origin, char level, char *description) { + if (log->count == log->capacity || log->capacity == 0) + return 1; + + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &_timecontainer); + (log->items+log->count)->ns = _timecontainer.tv_nsec; + (log->items+log->count)->level = level; + + if (description == NULL) + (log->items+log->count)->description = log->error_string_buffer; + else + (log->items+log->count)->description = description; + + + if (origin == NULL) + (log->items+log->count)->origin = log->origin_string_buffer; + else + (log->items+log->count)->origin = origin; + + + if (log->autoflush > 0) + fprintf(stderr, "%s: %s\n", (log->items+log->count)->origin, (log->items+log->count)->description); + + //*(log->error_string_buffer) = NULL; + //*(log->origin_string_buffer) = NULL; + log->error_string_buffer = NULL; + log->origin_string_buffer = NULL; + + log->count++; + + return 0; +} + +int lash_debugLogSetDescription(lash_debug_log_t *log, const char *d) { + log->error_string_buffer = d; +} + +int lash_debugLogSetOrigin(lash_debug_log_t *log, const char *o) { + log->origin_string_buffer = o; +} diff --git a/lash_debug_log.h b/lash_debug_log.h @@ -0,0 +1,57 @@ +#ifndef LASH_DEBUG_LOG_H_ +#define LASH_DEBUG_LOG_H_ + +#define LASH_DEBUG_LOG_CAPACITY_CHUNK 255 +#define LASH_DEBUG_LOG_CAPACITY_DESCRIPTION 255 + +#define LASH_DEBUG_LOG_LEVEL_CRITICAL 127 +#define LASH_DEBUG_LOG_LEVEL_WARNING 64 +#define LASH_DEBUG_LOG_LEVEL_MESSAGE -1 +#define LASH_DEBUG_LOG_LEVEL_DEBUG -64 +#define LASH_DEBUG_LOG_LEVEL_ALL -128 + +typedef struct lash_debug_log_item_t { + unsigned long ns; + char level; + char *origin; + char *description; +} lash_debug_log_item_t; + + +typedef struct lash_debug_log_t { + unsigned long ns_start; + unsigned short int count; + unsigned short int capacity; + lash_debug_log_item_t *items; + char *error_string_buffer; // used for sprintf, if no description in item is set the current error string buffer is used instead + char *origin_string_buffer; // used for sprintf, if no description in item is set the current error string buffer is used instead + int autoflush; +} lash_debug_log_t; + +#ifndef alog +#define alog 1; +lash_debug_log_t lash_logobj; +#line 31 __FILE__ +#define aloglevel(x) lash_debugLogInit(&lash_logobj, 1) +#define alogset(c, s) lash_debugLogSetDescription(&lash_logobj, s); lash_debugLogSetOrigin(&lash_logobj, c); +#define alogadd(l) lash_debugLogAdd(&lash_logobj, NULL, l, NULL); +#endif //lash_log + +#ifdef LASH_DEBUG_LOG_GLOBAL +#include <stdio.h> +lash_debug_log_t lash_log_global; +#endif + +#ifdef __cplusplus +extern "C" { +#endif +int lash_debugLogInit(lash_debug_log_t *log, int autoflush); +int lash_debugLogAdd(lash_debug_log_t *log, char *origin, char level, char *description); +int lash_debugLogSetDescription(lash_debug_log_t *log, const char *d); +int lash_debugLogSetOrigin(lash_debug_log_t *log, const char *o); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lash_debug_timer.c b/lash_debug_timer.c @@ -0,0 +1,47 @@ +#include "lash_debug_timer.h" +#include <time.h> + +void lash_debugTimerReset(lash_debug_timer_t *time) { + time->running = 0; + time->paused = 0; + time->count = 0; + time->total = 0; +} + +void lash_debugTimerStart(lash_debug_timer_t *time) { + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &(time->snap_start)); + time->running = 1; +} + +long lash_debugTimerPause(lash_debug_timer_t *time) { + if (!time->running) + return 0; + + if (time->paused) { + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &(time->snap_tmp)); + time->snap_start.tv_nsec += time->snap_tmp.tv_nsec - time->snap_end.tv_nsec; + time->paused = 0; + return time->snap_tmp.tv_nsec; + } else { + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &(time->snap_end)); + time->paused = 1; + return time->snap_end.tv_nsec; + } +} + +void lash_debugTimerStop(lash_debug_timer_t * time) { + if (time->running == 0) + return; + + if (!time->paused) + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &(time->snap_end)); + + time->total = time->snap_end.tv_nsec - time->snap_start.tv_nsec; + time->count++; + time->running = 0; + time->paused = 0; +} + +float lash_debugTimerGetAverage(lash_debug_timer_t *time) { + return time->total / (float)time->count; +} diff --git a/lash_debug_timer.h b/lash_debug_timer.h @@ -0,0 +1,29 @@ +#ifndef LASH_DEBUG_TIMER_H_ +#define LASH_DEBUG_TIMER_H_ + +#include <time.h> + +typedef struct lash_debug_timer_t { + unsigned int count; + long total; + struct timespec snap_start; + struct timespec snap_end; + struct timespec snap_tmp; + int running; + int paused; +} lash_debug_timer_t; + +#ifdef __cplusplus +extern "C" { +#endif +void lash_debugTimerReset(lash_debug_timer_t *time); +void lash_debugTimerStart(lash_debug_timer_t *time); +void lash_debugTimerStop(lash_debug_timer_t *time); +long lash_debugTimerPause(lash_debug_timer_t *time); +float lash_debugTimerGetAverage(lash_debug_timer_t *time); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/lash_endian.c b/lash_endian.c @@ -0,0 +1,44 @@ +#include "liblash/lash_endian.h" + +int is_le() { + short s = 42; + return *((unsigned char*)&s) == 42; +} + +// convert unsigned integer to little-endian representation +int to_endian(char direction, int l, void *n) { + union le un; + + if (l == 1 || is_le() == direction) { + return 0; + } + switch(l) { + case sizeof(long long): + un.ll = (long long*)n; + break; + case sizeof(int): + un.i = (int*)n; + break; + case sizeof(short): + un.s = (short*)n; + break; + default: + return 1; + } + flip_endian(l, &un); + + return 0; +} + +void flip_endian(int l, union le *n) { + int i; + char t; + char *ne; + + ne = (n->c)+(l-1); + for (i = 0; i < l/2; i++) { + t = *(n->c+i); + *((n->c)+i) = *(ne-i); + *(ne-i) = t; + } +} diff --git a/lash_endian.h b/lash_endian.h @@ -0,0 +1,19 @@ +#ifndef LASH_ENDIAN_H_ +#define LASH_ENDIAN_H_ + +#define CONVERT_BIGENDIAN 0x00 +#define CONVERT_LITTLEENDIAN 0x01 + +union le { + short *s; + int *i; + long long *ll; + unsigned char *c; +}; + +int le(int l, void *n); +int is_le(); +int to_endian(char direction, int l, void *n); +void flip_endian(int l, union le *n); + +#endif // LASH_ENDIAN_H_ diff --git a/lash_hex.c b/lash_hex.c @@ -0,0 +1,68 @@ +#include <string.h> +#include <stdio.h> +#include <stdlib.h> + +#include "liblash/lash_hex.h" + +/** +* \todo improve +*/ +int toHex(const unsigned char *data, size_t l, unsigned char *zHex, size_t *z) { + int i; + + if (*z < (l*2)+1) { + return 1; + } + + for (i = 0; i < l; i++) { + sprintf(zHex+(i*2), "%02x", *(data+i)); + } + *z = (i*2); + *(zHex+(*z)) = 0x0; + *z++; + return 0; +} + + +// cheekily stolen from https://nachtimwald.com/2017/09/24/hex-encode-and-decode-in-c/ +int hexchr2bin(const char hex, char *out) { + if (out == NULL) + return 0; + + if (hex >= '0' && hex <= '9') { + *out = hex - '0'; + } else if (hex >= 'A' && hex <= 'F') { + *out = hex - 'A' + 10; + } else if (hex >= 'a' && hex <= 'f') { + *out = hex - 'a' + 10; + } else { + return 0; + } + + return 1; +} + +size_t hex2bin(const char *hex, unsigned char **out) { + size_t len; + char b1; + char b2; + size_t i; + + if (hex == NULL || *hex == '\0' || out == NULL) + return 0; + + len = strlen(hex); + if (len % 2 != 0) + return 0; + len /= 2; + + *out = malloc(len); + memset(*out, 'A', len); + for (i=0; i<len; i++) { + if (!hexchr2bin(hex[i*2], &b1) || !hexchr2bin(hex[i*2+1], &b2)) { + return 0; + } + (*out)[i] = (b1 << 4) | b2; + } + return len; +} diff --git a/lash_hex.h b/lash_hex.h @@ -0,0 +1,8 @@ +#ifndef LASH_HEX_H_ +#define LASH_HEX_H_ + +int toHex(const unsigned char *data, size_t l, unsigned char *zHex, size_t *z); +int hexchr2bin(const char hex, char *out); +size_t hex2bin(const char *hex, unsigned char **out); + +#endif // LASH_HEX_H_ diff --git a/lash_tree3.c b/lash_tree3.c @@ -0,0 +1,198 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "liblash/lash_tree3.h" + + +lash_tree_t *lash_treeInit(lash_tree_t *tree, const unsigned int size) { + tree = (lash_tree_t*)malloc(sizeof(lash_tree_t)); + tree->key = (lash_tree_key_t**)malloc(sizeof(lash_tree_key_t*) * size + 1); + tree->item = (void*)malloc(sizeof(void*) * size + 1); + + if (tree->key == NULL || tree->item == NULL) + return NULL; + + tree->count = 0; + //tree->shiftpos = 0; + tree->capacity = size; + //tree->foldbackthreshold = tree->capacity / 2; + + return tree; +} + +void lash_treeFree(lash_tree_t *tree) { + if (tree == NULL) + return; + + if (tree->key != NULL) + free(tree->key); + + if (tree->item != NULL) + free(tree->item); + + free(tree); +} + +// key is optional, if NULL is passed, then tree assumes a lash_tree_key_t at first address of item pointer +int lash_treePush(lash_tree_t *tree, void *item, lash_tree_key_t *key) { + //printf("%p", item); + + if (tree->count == tree->capacity) + return -1; + + tree->count++; + + if (key != NULL) + *(tree->key + tree->count - 1) = key; + else + *(tree->key + tree->count - 1) = (lash_tree_key_t*)item; + + *(tree->item + tree->count - 1) = item; + + _lash_treeProcess(tree, tree->count, -1); + + return tree->count; +} + +int lash_treeShift(lash_tree_t *tree, void **item) { + return lash_treeRemove(tree, 0, item); +} + +int lash_treeRemove(lash_tree_t *tree, unsigned int position, void **item) { + + if (tree->count == 0) + return -1; + + // retrieve the values from the position from the argument + *item = *(tree->item + position); + + // move the values from the end of the tree to the position from the argument + *(tree->key + position) = *(tree->key + tree->count - 1); + *(tree->item + position) = *(tree->item + tree->count - 1); + + // reduce the count of the tree + tree->count--; + + // iterate the new value down the tree to its proper place + _lash_treeProcess(tree, position + 1, 1); + + return tree->count; +} + +int _lash_treeProcess(lash_tree_t *tree, unsigned int currentposition, int direction) { + + // towards end of pointer is downwards in the tree + // the direction to sort, -1 is from end towards start, 1 is from startposition towards end + + while (direction != 0) { + + lash_tree_key_t *currentkey = *(tree->key + currentposition - 1); + lash_tree_key_t *nextkey = NULL; + lash_tree_key_t *swapkey; + //lash_tree_key_t swapkey; + void *swapitem;; + void *currentitem; + void *nextitem; + + unsigned int nextposition; + + switch(direction) { + + // if there is still room to ascend in the tree, that is if the current position isn't 0 already. + case -1: + if (currentposition == 1) { + direction = 0; + } else { + nextposition = currentposition >> 1; + nextkey = *(tree->key + nextposition - 1); + if (*currentkey < *nextkey) { + /*swapkey = *currentkey; + *currentkey = *nextkey; + *nextkey = swapkey;*/ + + currentitem = *(tree->item + currentposition - 1); + nextitem = *(tree->item + nextposition - 1); + + swapkey = currentkey; + *(tree->key + currentposition - 1) = nextkey; + *(tree->key + nextposition - 1) = swapkey; + + // ORIGINALLY IT SEEMED LIKE WHEN THE ADDRESS WAS THE SAME THAT THIS WOULD SHIFT THINGS AROUND TWICE + // NOW IT WORKS IF THE ADDRESS OF THE KEY AND THE FIRST ADDRESS OF THE ITEM ARE THE SAME + // if the position of the key is not in the first address of the item we need to move it separately + // note that swapkey now holds the original currentkey + //if ((lash_tree_key_t *)currentitem != swapkey) { + swapitem = currentitem; + *(tree->item + currentposition - 1) = nextitem; + *(tree->item + nextposition - 1) = swapitem; + //} + + currentposition = nextposition; + } else { + direction = 0; + } + } + break; + + // if there is still room from the current position to descend one level in the tree): + // level 0 has 2^0 = entry 1 + // level 1 has 2^1 = entries 2-3 + // level 2 has 2^2 = entries 4-7 + // if we're at position 3, the check will be 3*2 = 6, which is within bounds of level 2, and points to elements 6 and 7 (the children of 3) + // If we're at position 4, the check will be 4*2 = 8, which is out of bounds of level 2. + + case 1: + nextposition = currentposition << 1; + + if (nextposition <= tree->count) { + + // compare both the child values, to pick the higher one + nextkey = *(tree->key + nextposition - 1); + if (*nextkey > **(tree->key + nextposition)) { + nextkey = *(tree->key + nextposition); + nextposition++; + } + + // compare the values, set nextkey back to null to stop the swapping if the value is not higher + if (*currentkey <= *nextkey) { + nextkey = NULL; + } + + if (nextkey != NULL) { + /*swapkey = *currentkey; + *currentkey = *nextkey; + *nextkey = swapkey;*/ + + currentitem = *(tree->item + currentposition - 1); + nextitem = *(tree->item + nextposition - 1); + + swapkey = currentkey; + *(tree->key + currentposition - 1) = nextkey; + *(tree->key + nextposition - 1) = swapkey; + + // ORIGINALLY IT SEEMED LIKE WHEN THE ADDRESS WAS THE SAME THAT THIS WOULD SHIFT THINGS AROUND TWICE + // NOW IT WORKS IF THE ADDRESS OF THE KEY AND THE FIRST ADDRESS OF THE ITEM ARE THE SAME + // if the position of the key is not in the first address of the item we need to move it separately + // note that swapkey holds the original currentkey value + //if ((lash_tree_key_t *)currentitem != swapkey) { + swapitem = currentitem; + *(tree->item + currentposition - 1) = nextitem; + *(tree->item + nextposition - 1) = swapitem; + //} + + currentposition = nextposition; + } else { + direction = 0; + } + } else { + direction = 0; + } + break; + default: + direction = 0; + } + } + + return currentposition; +} diff --git a/lash_tree3.h b/lash_tree3.h @@ -0,0 +1,135 @@ +#ifndef LASH_TREE_H_ +#define LASH_TREE_H_ + +typedef long int lash_tree_key_t; + +typedef struct lash_tree_t { + lash_tree_key_t **key; + void **item; + //unsigned int shiftpos; + unsigned int count; + unsigned int capacity; + //unsigned int foldbackthreshold; + int average; +} lash_tree_t; + +#ifdef __cplusplus +extern "C" { +#endif + +lash_tree_t * lash_treeInit(lash_tree_t *tree, const unsigned int size) ; +int lash_treePush(lash_tree_t *tree, void *item, lash_tree_key_t *key); +int lash_treeShift(lash_tree_t *tree, void **item); +int lash_treeRemove(lash_tree_t *tree, unsigned int position, void **item); +int _lash_treeProcess(lash_tree_t *tree, unsigned int currentposition, int direction); +void lash_treeFree(lash_tree_t *tree); +#ifdef __cplusplus +} +#endif + + +#endif // LASH_TREE_H_ + +/** + * \file lash_tree3.h + * \brief Implementation of binary tree for sorting generic objects + * + * \author Louis Holbrook + * \version 0.2 + * + * \todo Possibility to remove from other positions in the tree than start + * + * This library aims to be a fast and small way of storing generic structs (or even just integers) in a binary tree for fast retrieval in sorted order. + * It was written as a backend for A* pathfinding code + * + * Structs are stored as *void* pointers, which means they can reference anything at all. + * Every "entry" in the tree will have one *void* pointer and one pointer to the sort value. At least one member of the struct must be of `lash_tree_key_t` type, which this pointer will point to. + * Theoretically, different struct types can be stored in the different entries of the tree. + * + */ +/** + * \var typedef lash_tree_key_t + * \param lash_tree_key_t Sort value type for `lash_tree_t` + */ + +/** + * \var typedef lash_tree_t + * \param **key Pointers to the sort key values + * \param **item Pointers to the sorted data structures + * \param count Current amount of items in the tree + * \param capacity Maximum amount of items allocated + * \param average Sort value at the middle of the array (currently unused) + */ + +/** + * \struct lash_tree_t + * \param **key Pointers to the sort key values + * \param **item Pointers to the sorted data structures + * \param count Current amount of items in the tree + * \param capacity Maximum amount of items allocated + * \param average Sort value at the middle of the array (currently unused) + */ + + +/** + * \fn lash_treeInit(lash_tree_t *tree, const unsigned int size) + * \brief Allocates memory and initializes members + * + * \param *tree Pointer to allocate memory to + * \param size Amount of items to allocate + * \return NULL if not successful + * + */ + +/** + * \fn lash_treeFree(lash_tree_t *tree) + * \brief Frees up memory + * + * \param *tree Tree struct to free + * + */ + +/** + * \fn lash_treePush(lash_tree_t *tree, void *item, lash_tree_key_t *key) + * \brief Add a new item to the tree + * + * \param *tree Tree struct to add to + * \param *item Data structure to add + * \param *key Pointer to the sort key value in `*item` + * \return Number of items in the tree after adding. If tree is full -1 is returned. + * + * The data structure must have one member of type `lash_tree_key_t` + * if `*key` is omitted, it will be assumed that the first position at the address of `*item` is of this type, and will be used as the sort value for this item. + * The item is added to the end of the tree, and stepwise moved up the tree until it meets a lower value. + * + */ + +/** + * \fn lash_treeShift(lash_tree_t *tree, void **item) + * \brief Retrieves and removes the first item from the tree + * + * \param *tree Tree struct to shift from + * \param **item Pointer to pass the retrieved data structure pointer in + * \return Wrapper for `lash_treeRemove` with position argument 0 + * + * \sa lash_treeRemove + * + */ + +/** + * \fn lash_treeRemove(lash_tree_t *tree, unsigned int position, void **item) + * \brief Retrieves and removes an item from the tree + * + * \param *tree Tree struct to shift from + * \param position What sort position to remove from. + * \param **item Pointer to pass the retrieved data structure pointer in + * \return Number of items in the tree after removal. If the tree was already empty -1 is returned. + * + * \sa lash_treePush + * + * \warning Currently only position 0 is tested. Setting another value causes undefined behavior and will probably not work. + * + * After the item is retrieved, the item at the end of the tree is moved up to replace it, and stepwise moved down the tree until meets a higher value. + * + * + */ diff --git a/lash_tree3_dump.c b/lash_tree3_dump.c @@ -0,0 +1,66 @@ +#include "liblash/lash_tree3_dump.h" +#include "liblash/lash_tree3.h" +#include <stdio.h> +#include <stdlib.h> + +unsigned int lash_tree_dump_monitor_capacity; +unsigned int lash_tree_dump_monitor_count; + +void lash_treeDump(lash_tree_t *tree, char *comment) { + int i; + int j; + + lash_tree_t *currenttree; + + for (i = 0; i < lash_tree_dump_monitor_count; i++) { + currenttree = *(lash_tree_dump_monitor.tree + i); + if (tree != NULL) + if (tree != currenttree) + continue; + + printf("'%s' size %d", *(lash_tree_dump_monitor.name + i), currenttree->count); + if (comment != NULL) + printf(" (%s)", comment); + printf(":\n"); + + for (j = 0; j < currenttree->count; j++) { + printf("i:%2d v:%3li\n", j, (long int)**(currenttree->key + j)); + } + } +} + +int lash_treeDumpInit(unsigned int count) { + + lash_tree_dump_monitor.tree = (lash_tree_t**)malloc(sizeof(lash_tree_t*) * count); + if (lash_tree_dump_monitor.tree == NULL) + return 1; + + lash_tree_dump_monitor.name = (char**)malloc(sizeof(char) * 128 * count); + if (lash_tree_dump_monitor.name == NULL) + return 1; + + lash_tree_dump_monitor_capacity = count; + lash_tree_dump_monitor_count = 0; + + return 0; +} + +int lash_treeDumpAdd(lash_tree_t *tree, char *name) { + if (lash_tree_dump_monitor_count == lash_tree_dump_monitor_capacity) + return 1; + + *(lash_tree_dump_monitor.tree + lash_tree_dump_monitor_count) = tree; + *(lash_tree_dump_monitor.name + lash_tree_dump_monitor_count) = name; + + lash_tree_dump_monitor_count++; + + return 0; +} + +void lash_treeDumpFree() { + if (lash_tree_dump_monitor.tree != NULL) + free(lash_tree_dump_monitor.tree); + + if (lash_tree_dump_monitor.name != NULL) + free(lash_tree_dump_monitor.name); +} diff --git a/lash_tree3_dump.h b/lash_tree3_dump.h @@ -0,0 +1,79 @@ +#ifndef LASH_TREE_DUMP_H_ +#define LASH_TREE_DUMP_H_ + +#include "liblash/lash_tree3.h" + +struct lash_tree_dump_monitor { + lash_tree_t **tree; + char **name; +} lash_tree_dump_monitor; + +#ifdef __cplusplus +extern "C" { +#endif +void lash_treeDump(lash_tree_t *tree, char *comment); +int lash_treeDumpInit(unsigned int count); +int lash_treeDumpAdd(lash_tree_t *tree, char *name); +void lash_treeDumpFree(); + +#ifdef __cplusplus +} +#endif + +#endif // LASH_TREE_DUMP_H_ + +/** + * \file lash_tree3_dump.h + * \brief Dump contents of `lash_tree3` objects + * + * \author Louis Holbrook + * \version 0.2 + * + */ + +/** + * + * \struct lash_tree_dump_monitor + * \brief Container pointing to trees elegible for dumping + * \var **tree Pointers to trees + * \var **name Name of tree to display when dumping + * + */ + +/** + * \fn lash_treeDump(lash_tree_t *tree, char *comment) + * \brief Dumps content of tree in sort order to **STDOUT** + * + * \param *tree Tree to dump. + * \param *comment Optional text string to display in front of dump + * + * If `*tree` is specified, only this tree will be dumped. + * Note that trees have to be added to `lash_tree_dump_monitor` by `lash_treeDumpAdd` or they will be skipped. + * + * \todo Parametric output formatting + */ + +/** + * \fn lash_treeDumpInit(unsigned int count) + * \brief Memory allocation + * + * \param count number of trees to allocate + * \return 1 if allocation failed, 0 if no error. + */ + +/** + * \fn lash_treeDumpAdd(lash_tree_t *tree, char *name) + * \brief Add tree to the list of trees for dumping + * + * \param *tree Tree to add + * \param *name Name to display in front of output + * \return 1 if capacity is exceeded, 0 otherwise + * + */ + +/** + * \fn lash_treeDumpFree() + * \brief Free memory from `lash_tree_dump_monitor` + * + * \param *tree Tree to free + */ diff --git a/tests/debuglog.c b/tests/debuglog.c @@ -0,0 +1,27 @@ +#include "../lash_debug_log.h" +#include <stdio.h> + +int main() { + lash_debug_log_t log; + lash_debug_log_t log2; + if (lash_debugLogInit(&log, 0) != 0) + return 1; + + if (lash_debugLogInit(&log2, 1) != 0) + return 1; + + lash_debugLogAdd(&log, "main", LASH_DEBUG_LOG_LEVEL_CRITICAL, "Test of description"); + lash_debugLogAdd(&log, "main 2", LASH_DEBUG_LOG_LEVEL_MESSAGE, "Test of description 2"); + + lash_debugLogAdd(&log2, "main 3", LASH_DEBUG_LOG_LEVEL_MESSAGE, "Test of description with autoflush"); + + sprintf(log2.error_string_buffer, "Test of buffer %d", 123); + lash_debugLogAdd(&log2, "main 4", LASH_DEBUG_LOG_LEVEL_MESSAGE, NULL); + + sprintf(log2.error_string_buffer, "Test of buffer %d", 456); + lash_debugLogAdd(&log2, "main 5", LASH_DEBUG_LOG_LEVEL_MESSAGE, "Test of description override buffer"); + + lash_debugLogAdd(&log2, "main 6", LASH_DEBUG_LOG_LEVEL_MESSAGE, NULL); + + return 0; +} diff --git a/tests/debuglogmaster.c b/tests/debuglogmaster.c @@ -0,0 +1,8 @@ +#define LASH_DEBUG_LOG_GLOBAL 1 + +#include "../lash_debug_log.h" + +int main() { + lash_debugLogInit(&lash_log_global, 1); + return 0; +} diff --git a/tests/debugtimer.c b/tests/debugtimer.c @@ -0,0 +1,24 @@ +// debugtimer + +#include "../lash_debug_timer.h" +#include <stdio.h> + +int main() { + int i; + lash_debug_timer_t time; + lash_debugTimerReset(&time); + for (i=0;i<10;i++) { + lash_debugTimerStart(&time); + lash_debugTimerStop(&time); + } + printf("Average: %f\n", lash_debugTimerGetAverage(&time)); + for (i=0;i<10;i++) { + lash_debugTimerStart(&time); + printf("(paused at %li) ", lash_debugTimerPause(&time)); + lash_debugTimerPause(&time); + printf("(resumed at %li)\n", lash_debugTimerPause(&time)); + lash_debugTimerStop(&time); + } + printf("Average: %f\n", lash_debugTimerGetAverage(&time)); + return 0; +} diff --git a/tests/tree3.c b/tests/tree3.c @@ -0,0 +1,65 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "../lash_tree3.h" +#include "../lash_tree3_dump.h" + +typedef struct treeitem { + char *something; + lash_tree_key_t val; +} treeitem; + +typedef struct treeitem2 { + lash_tree_key_t val; + char *something; +} treeitem2; + +// Simple push and pull test + +int main() { + lash_tree_t *tree = NULL; + lash_tree_t *tree2 = NULL; + treeitem passitem; + treeitem2 passitem2; + void *resultitem; + + char teststring[255]; + char teststring2[255]; + + tree = lash_treeInit(tree, 10); + if (tree == NULL) + return 1; + + tree2 = lash_treeInit(tree2, 10); + if (tree2 == NULL) + return 1; + + lash_treeDumpInit(2); + lash_treeDumpAdd(tree2, "treetwo"); + lash_treeDumpAdd(tree, "treeone"); + + sprintf(teststring, "one"); + sprintf(teststring2, "two"); + + passitem.val = 20; + passitem.something = teststring2; + + passitem2.val = 10; + passitem2.something = teststring; + + lash_treePush(tree, &passitem2, NULL); + lash_treePush(tree, &passitem, &passitem.val); + + lash_treeDump(NULL, "dump of both trees"); + + lash_treeShift(tree, &resultitem); + + lash_treeDump(tree, "dump of specified tree"); + + lash_treeDumpFree(); + + lash_treeFree(tree); + lash_treeFree(tree2); + + return 0; +} diff --git a/tests/tree3_console.c b/tests/tree3_console.c @@ -0,0 +1,74 @@ +#include "../lash_tree3.h" +#include "../lash_tree3_dump.h" +#include <stdlib.h> +#include <stdio.h> + +typedef struct teststructure { + lash_tree_key_t val; + char *nothing; +} teststructure; + +int main(int argc, char **argv) { + int run = 1; + int dump = 1; + char buf[1024]; + int pushes = 0; + + lash_tree_t *tree = NULL; + tree = lash_treeInit(tree, 100); + if (tree == NULL) + return 1; + + teststructure *ts = (teststructure*)malloc(sizeof(teststructure)*1000); + if (ts == NULL) + return 1; + + teststructure *result; + + lash_treeDumpInit(1); + lash_treeDumpAdd(tree, "tree"); + + while (run) { + char cmd; + long int val1 = -1; + unsigned int pos = 0; + printf(">> "); + fflush(stdout); + fgets(buf, 1024, stdin); + sscanf(buf, "%c", &cmd); + + switch(cmd) { + case 'p': + printf("value: "); + fflush(stdout); + fgets(buf, 1024, stdin); + sscanf(buf, "%li", &val1); + if (val1 != -1) { + (ts+pushes)->val = val1; + pos = lash_treePush(tree, (ts+pushes), NULL); + printf("pos: %u\n", pos); + pushes++; + } + break; + case 's': + if (tree->count == 0) { + printf("Nothing to shift\n"); + } else { + lash_treeShift(tree, (void**)&result); + printf("val1: %li, val2: %p\n", result->val, result); + } + break; + case 'd': + dump ^= 1; + printf(dump ? "(Dump on)\n" : "(Dump off)\n"); + break; + case 'q': + run = 0; + break; + } + + if (dump) + lash_treeDump(tree, NULL); + } + return 0; +} diff --git a/tests/tree3_shifttest.c b/tests/tree3_shifttest.c @@ -0,0 +1,84 @@ +#include "../lash_tree3.h" +#include "../lash_tree3_dump.h" +#include <stdlib.h> +#include <stdio.h> +#include <limits.h> +#include <time.h> + +#define TREE_CAPACITY 100 +#define HEAP_RANGE 1000 + +typedef struct teststructure { + lash_tree_key_t key; + unsigned int localvalue; +} teststructure; + +typedef struct teststructure2 { + unsigned int localvalue; + lash_tree_key_t key; +} teststructure2; + + +// insert TREE_CAPACITY number of items with random sort values into the tree, while shifting every second item + +/// \todo write alternating inserts with teststructure 2, to test the movement of items when the addresses of key and first address of item are not the same (see comment in lash_treeProcess()) + +int main(int argc, char **argv) { + time_t t; + lash_tree_t *tree = NULL; + int i; + int j; + char pushvaluestring[255]; + long int lastnumber; + teststructure *result; + + srand((unsigned) time(&t)); + + tree = lash_treeInit(tree, TREE_CAPACITY); + if (tree == NULL) + return 1; + + teststructure *ts = (teststructure*)malloc(sizeof(teststructure) * TREE_CAPACITY); + if (ts == NULL) + return 1; + + lash_treeDumpInit(1); + lash_treeDumpAdd(tree, "tree"); + + i = 0; + for (j = 0; j < TREE_CAPACITY; j++) { + (ts+j)->key = -1; + (ts+j)->localvalue = j; + + if (j > 0) + (ts+j)->key = rand() % HEAP_RANGE; + + if (i % 2 == 0 && i > 0) { + fprintf(stderr, "Shifting!\n"); + lash_treeShift(tree, (void**)&result); + fprintf(stderr, "Shift yield n%li l%d\n", result->key, result->localvalue); + j--; + } + + sprintf(pushvaluestring, "before push [%li]", (ts+j)->key); + fprintf(stderr, "pushing %li\n", (ts+j)->key); + lash_treeDump(tree, pushvaluestring); + lash_treePush(tree, (ts+j), NULL); + lash_treeDump(tree, "after push"); + i++; + } + + printf("Unpacking\n"); + + lastnumber = -1; + for (i = 0; i < TREE_CAPACITY; i++) { + lash_treeShift(tree, (void**)&result); + printf("%li ", result->key); + if (result->key < lastnumber) + printf("SORTERROR! "); + lastnumber = result->key; + } + printf("\n"); + + return 0; +}