aboutsummaryrefslogtreecommitdiff
path: root/include/dtree/dtree.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/dtree/dtree.h')
-rw-r--r--include/dtree/dtree.h414
1 files changed, 414 insertions, 0 deletions
diff --git a/include/dtree/dtree.h b/include/dtree/dtree.h
new file mode 100644
index 0000000..b46b000
--- /dev/null
+++ b/include/dtree/dtree.h
@@ -0,0 +1,414 @@
+/*
+ * Please use the API to create and destroy objects as only this way
+ * memory-safety and memory leaks can be guaranteed.
+ *
+ * With the API you can easily create structures like the following:
+ *
+ * root [recursive]
+ * child1 [recursive]
+ * key [literal] - "Username"
+ * value [literal] - "spacekookie"
+ * child2 [recursive]
+ * key [literal] - "Age"
+ * value [numerical] - 23
+ * child3
+ * subchild [recursive]
+ * ...
+ *
+ * Freeing the root node will free all children
+ */
+
+#ifndef _DYNTREE_H_
+#define _DYNTREE_H_
+
+#include <memory.h>
+
+/* A helpful macro that can take care of \0 termated strings! */
+#define REAL_STRLEN(str) (strlen(str) + 1)
+
+#define DYNTREE_ENCODE_NONE 0x0
+#define DYNTREE_JSON_MINIFIED 0xA
+#define DYNTREE_JSON_HUMAN 0xB
+
+/* Also make sure we're _always_ interpreted as a C file */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* Type that determines what data is stored inside a tree-node */
+typedef enum dt_uni_t {
+ UNSET, LITERAL, NUMERAL, RECURSIVE, PAIR, POINTER
+} dt_uni_t;
+
+
+typedef struct dtree {
+ dt_uni_t type;
+ short encset;
+ size_t size, used;
+ short copy;
+ union {
+ char *literal;
+ long numeral;
+ struct dtree *(*recursive);
+ void *pointer;
+ } payload;
+} dtree;
+
+
+/** Define some generic error codes first that we can propagate **/
+typedef enum dt_err {
+
+ /* General purpose error codes */
+ FAILURE = -1,
+ SUCCESS = 0,
+
+ INVALID_PARAMS,
+ MALLOC_FAILED,
+ INVALID_PAYLOAD,
+ DATA_NOT_RELATED,
+ NODE_NOT_FOUND,
+
+} dt_err;
+
+
+/**
+ * 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
+ *
+ * @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);
+
+
+/**
+ * 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, long numeral);
+
+
+/**
+ * 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
+ *
+ * @param data Root reference
+ * @param new_data Reference pointer to a new dtree node
+ * @return
+ */
+dt_err dtree_addlist(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);
+
+
+/**
+ * This function takes two nodes as arguments. The nodes MUST be
+ * related or an error will be thrown. Both nodes will still
+ * be accessable after this operation but no longer be related to
+ * each other.
+ *
+ * The second node will be removed from the tree of the root node.
+ *
+ *
+ *
+ * @param data Root reference
+ * @param sp Subtree node related to root to split off
+ * @return
+ */
+dt_err dtree_split_trees(dtree *data, dtree *sp);
+
+
+/**
+ * This function is very simmilar to dt_err "dtree_addrecursive"
+ * with the difference that it doesn't allocate new memory but instead
+ * works with existing nodes.
+ *
+ * You need to provide a ROOT node which is of type recursive. It will
+ * procede to add the second (merge) node into the child-list of the
+ * root data node - essentially making them related.
+ *
+ * This allows for very efficient tree merging.
+ *
+ * @param data Root reference
+ * @param merge Second root reference to merge
+ * @return
+ */
+dt_err dtree_merge_trees(dtree *data, dtree *merge);
+
+
+/**
+ * Recursive tree search function that will return the first occurence match
+ * to a provided payload (with an exact type). If you have data duplication
+ * in your tree this _might_ return some false positives.
+ *
+ * @param data Root reference to search
+ * @param found Empty pointer to put found node into
+ * @param payload What should be found
+ * @param type What type of data should be found
+ * @return
+ */
+dt_err dtree_search_payload(dtree *data, dtree *(*found), void *payload, dt_uni_t type);
+
+
+/**
+ * Performs a deep copy of a data node hirarchy. Does not copy externally
+ * pointed structures. Does garuantee safety of hirarchy.
+ *
+ * @param data
+ * @param copy
+ * @return
+ */
+dt_err dtree_deep_copy(dtree *data, dtree *(*copy));
+
+
+/**
+ * Performs a copy operation on a single node. Copies the payload on a pointer
+ * level which means that strings and numbers will be duplicated whereas external
+ * pointers and lists will only be references to the original content.
+ *
+ * Freeing the copy has no effect on the original payloads stored in other
+ * nodes.
+ *
+ * @param data
+ * @param copy
+ * @return
+ */
+dt_err dtree_copy(dtree *data, dtree *(*copy));
+
+/**
+ * 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));
+
+
+/**
+ * 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 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);
+
+
+/**************************
+ *
+ * Error handling functions
+ *
+ **************************/
+
+const char *dtree_err_getmsg(dt_err *e);
+
+/***************************
+ *
+ * Encoding/ Decoding support hooks
+ *
+ ***************************/
+
+/**
+ * This function sets the wanted encoding setting on a
+ * root node (and assumes for children). Without setting flags via
+ * this function first the encode will fail.
+ *
+ * @param data Root reference
+ * @param setting Look at DYNTREE_JSON flags for options
+ * @return
+ */
+dt_err dtree_encode_set(dtree *data, short setting);
+
+/**
+ * A simple recursive node walker that encodes a dyn_tree node hirarchy
+ * into a json string. Requires the encoding setting to be set on the
+ * root node in order to successfully encode.
+ *
+ * Can throw errors and initialise NULL return string.
+ *
+ * @param data
+ * @param json_data
+ * @return
+ */
+dt_err dtree_encode_json(dtree *data, char *json_data);
+
+
+/**
+ * Decodes a json string into a dyn_tree node hirarchy while providing
+ * memory safety and error checking. Will gracefully return errors
+ * if the provided json string is invalid or contains errors.
+ *
+ * @param data New root reference
+ * @param json_data Input json string
+ * @return
+ */
+dt_err dtree_decode_json(dtree *(*data), const char *json_data);
+
+
+
+/*** Some helper functions for more non-C oriented developers ***/
+
+/**
+ * Shortcut function that allocates a new string node. Beware however:
+ *
+ * THIS FUNCTION DOES NOT RETURN WARNINGS OR ERROR CODES!
+ *
+ * @param string
+ * @return
+ */
+static dtree *dtree_alloc_literal(const char *string)
+{
+ dtree *node;
+ dtree_malloc(&node);
+ dtree_addliteral(node, string);
+ return node;
+}
+
+/**
+ * Shortcut function that allocates a new numerical node.
+ * Beware however:
+ *
+ * THIS FUNCTION DOES NOT RETURN WARNINGS OR ERROR CODES!
+ *
+ * @param num
+ * @return
+ */
+static dtree *dtree_alloc_numeral(const long num)
+{
+ dtree *node;
+ dtree_malloc(&node);
+ dtree_addnumeral(node, num);
+ return node;
+}
+
+/**
+ * Shortcut function which creates two nodes as pair under a root
+ * node which is returned. Beware however:
+ *
+ * THIS FUNCTION DOES NOT RETURN WARNINGS OR ERROR CODES!
+ *
+ @param key Will be the key node
+ * @param val Will be the value node
+ * @return New root node with key-val children
+ */
+static dtree *dtree_allocpair_new(dtree **key, dtree **val)
+{
+ dtree *root;
+ dtree_malloc(&root);
+ dtree_addpair(root, key, val);
+ return root;
+}
+
+
+/**
+ * Shortcut function which allocates a list of nodes in a list under
+ * a root node recursively.
+ *
+ * WARNING: Return value is allocated on heap. MUST FREE MANUALLY!
+ * WARNING: THIS FUNCTION DOES NOT RETURN WARNINGS OR ERROR CODES!
+ *
+ * @param root
+ * @param count
+ * @return
+ */
+static dtree **dtree_alloc_listlist(dtree **root, unsigned int count)
+{
+ dtree **nodes = malloc(sizeof(dtree**) * count);
+
+ dtree_malloc(root);
+
+ int i;
+ for(i = 0; i < count; i++)
+ dtree_addlist(*root, &nodes[i]);
+
+ return nodes;
+}
+
+#ifdef __cplusplus
+}
+#endif
+#endif //_DYNTREE_H_