From 58045e8a341b066a1957cc2472cb91b0d39b28ef Mon Sep 17 00:00:00 2001 From: Katharina Fey Date: Sat, 30 Jul 2016 23:28:36 +0200 Subject: Changing the APi slightly and adding better comments for the api functions. - Also adding the ability to store custom pointers in a node --- include/dtree/dyn_tree.h | 125 +++++++++++++++++++++++++++++++++++++++++++---- lib/dyn_tree.c | 55 ++++++++++++++++++--- 2 files changed, 164 insertions(+), 16 deletions(-) diff --git a/include/dtree/dyn_tree.h b/include/dtree/dyn_tree.h index e1db1d6..cfd7239 100644 --- a/include/dtree/dyn_tree.h +++ b/include/dtree/dyn_tree.h @@ -30,8 +30,9 @@ extern "C" { #endif +/* Type that determines what data is stored inside a tree-node */ typedef enum { - UNSET, LITERAL, NUMERAL, RECURSIVE, PAIR + UNSET, LITERAL, NUMERAL, RECURSIVE, PAIR, POINTER } dt_uni_t; typedef struct dtree { @@ -40,35 +41,139 @@ typedef struct dtree { union { char *literal; int numeral; - struct dtree *(*recursive); + struct dtree *(*recursive); + void *pointer; } payload; } dtree; -/** Malloc a new dtree object */ + +/** + * Malloc a new dtree object + * + * @param data Reference pointer to dtree element + * @return + */ dt_err dtree_malloc(dtree *(*data)); + +/** + * Reset the type of a node and free child data + * + * @param data + * @return + */ dt_err dtree_resettype(dtree *data); -/** Set the data element to a literal and save it's length */ + +/** + * Set the data element to a literal and save it's length + * + * @param data Reference to a dtree object + * @param literal String to store + * @param length TRUE string length to use. + * @return + */ dt_err dtree_addliteral(dtree *data, const char *literal, size_t length); -/** Set the data element to a numeral */ + +/** + * Set the data element to a numeral + * + * @param data Reference to a dtree object + * @param numeral Number to store + * @return + */ dt_err dtree_addnumeral(dtree *data, int numeral); -/** Add two new elements as a PAIR node under an existing node */ + +/** + * Add two new elements as a PAIR node under an existing node + * + * @param data dtree node to become the sub-root + * @param key Reference pointer to the key node + * @param value Reference pointer to the value node + * @return + */ dt_err dtree_addpair(dtree *data, dtree *(*key), dtree *(*value)); -/** Add a new data element to the resursive data store */ + +/** + * Add a new data element to the resursive data store + * + * @param data Root reference + * @param new_data Reference pointer to a new dtree node + * @return + */ dt_err dtree_addrecursive(dtree *data, dtree *(*new_data)); + +/** + * This function enables you to store your own structures in a node. It however + * also requires you to do some of your own memory management. + * + * WARNING: Can leak memory if pointer is previously set! + * + * To make sure that this function CAN NOT leak memory you should run + * "dtree_resettype" on the root element to remove the pointer. + * + * Also make sure that no other part of your application will use the + * pointer at a later date! + * + * @param data Root reference + * @param ptr A pointer to store in this node + * @return + */ +dt_err dtree_addpointer(dtree *data, void *ptr); + + +/** + * A retrieve function to get data back from a node that doesn't require + * you to manually access parts of the struct. + * + * Needs to be provided with a reference to a pointer that can then be + * written to. You can make the reference type specific if you know + * what kind of data you're expecting or leave it as a void* to let + * libdyntree do the casting for you. + * + * @param data Node reference to access + * @param val Reference pointer to write into + * @return + */ dt_err dtree_get(dtree *data, void *(*val)); -const char *dtree_dtype(dt_uni_t type); -/** Prints*/ +/** + * Return the type of a node as plain text + * + * @param data + * @return + */ +const char *dtree_dtype(dtree *data); + + +/** + * Prints the data dtree object and all of its children + * + * @param data + */ void dtree_print(dtree *data); -/** Will free all memory allocated by this element and it's children */ +/** + * Will free the data reference and all of it's children. It will however NOT + * touch pointers to objects that weren't allocated by libdyntree! + * + * @param data + * @return + */ +dt_err dtree_free_shallow(dtree *data); + +/** + * Like #{dtree_free_shallow} but will also remove structs that + * weren't allocated by libdyntree + * + * @param data + * @return + */ dt_err dtree_free(dtree *data); #ifdef __cplusplus diff --git a/lib/dyn_tree.c b/lib/dyn_tree.c index 4665332..095d379 100644 --- a/lib/dyn_tree.c +++ b/lib/dyn_tree.c @@ -74,6 +74,21 @@ dt_err dtree_addliteral(dtree *data, const char *literal, size_t length) return SUCCESS; } + +dt_err dtree_addpointer(dtree *data, void *ptr) +{ + if(data->type != UNSET) + if(data->type != POINTER) return INVALID_PAYLOAD; + + data->payload.pointer = ptr; + data->type = POINTER; + data->size = sizeof(ptr); + data->used = sizeof(*ptr); + + return SUCCESS; +} + + dt_err dtree_addnumeral(dtree *data, int numeral) { /* Make sure we are a literal or unset data object */ @@ -130,6 +145,7 @@ dt_err dtree_addrecursive(dtree *data, dtree *(*new_data)) return SUCCESS; } + dt_err dtree_addpair(dtree *data, dtree *(*key), dtree *(*value)) { /* Make sure we are a literal or unset data object */ @@ -265,6 +281,7 @@ dt_err dtree_free(dtree *data) if(data->type == LITERAL) { if(data->payload.literal) free(data->payload.literal); + } else if(data->type == RECURSIVE || data->type == PAIR) { int i; dt_err err; @@ -274,19 +291,45 @@ dt_err dtree_free(dtree *data) } free(data->payload.recursive); + + } else if(data->type == POINTER) { + if(data->payload.pointer) free(data->payload.pointer); } free(data); return SUCCESS; } -const char *dtree_dtype(dt_uni_t type) +dt_err dtree_free_shallow(dtree *data) { - switch(type) { - case LITERAL: return "Literal"; - case NUMERAL: return "Numeral"; - case RECURSIVE: return "Recursive"; - default: return "Unknown"; + if(data == NULL) return SUCCESS; + + if(data->type == LITERAL) { + if(data->payload.literal) free(data->payload.literal); + } else if(data->type == RECURSIVE || data->type == PAIR) { + int i; + dt_err err; + for(i = 0; i < data->size; i++) { + err = dtree_free(data->payload.recursive[i]); + if(err) return err; + } + + free(data->payload.recursive); + } + + free(data); + return SUCCESS; +} + +const char *dtree_dtype(dtree *data) +{ + switch(data->type) { + case LITERAL: return "Literal"; + case NUMERAL: return "Numeral"; + case RECURSIVE: return "Recursive"; + case PAIR: return "Pair"; + case POINTER: return "Pointer"; + default: return "Unknown"; } } -- cgit v1.2.3