aboutsummaryrefslogtreecommitdiff
path: root/bowl.c
diff options
context:
space:
mode:
Diffstat (limited to 'bowl.c')
-rw-r--r--bowl.c828
1 files changed, 68 insertions, 760 deletions
diff --git a/bowl.c b/bowl.c
index 0f43db2..4eeeb59 100644
--- a/bowl.c
+++ b/bowl.c
@@ -1,815 +1,123 @@
-// Include our header file
#include "bowl.h"
+#include "array.h"
-// Runtime includes
#include <stdlib.h>
-#include <stdio.h>
#include <memory.h>
#include <stdbool.h>
-#define RDB_REC_DEF_SIZE 2
-#define RDB_REC_MULTIPLY 2
+#define ARRAY_START_SIZE 2
+#define HASH_START_SIZE 24
-#define ORIGINAL (short) 0
-#define SHALLOW (short) 1
-#define DEEP (short) 2
-
-/*** Forward declared functions ***/
-
-int list_search(struct bowl**, struct bowl*, struct bowl*);
-
-void list_print(struct bowl *data, const char *offset);
-
-/******/
-
-dt_err bowl_malloc(struct bowl *(*data))
-{
- (*data) = (struct bowl*) malloc(sizeof(struct bowl));
- if(*data == NULL) {
- printf("Creating bowl object FAILED");
- return MALLOC_FAILED;
- }
-
- memset(*data, 0, sizeof(struct bowl));
-
- (*data)->type = UNSET;
- return SUCCESS;
-}
-
-dt_err bowl_resettype(struct bowl *data)
-{
- if(data->type == LITERAL) {
- if(data->payload.literal) free(data->payload.literal);
-
- } else if(data->type == LIST || data->type == PAIR) {
-
- /* Iterate over all children and clear them */
- int i;
- dt_err err;
- for(i = 0; i < data->size; i++) {
- err = bowl_free(data->payload.list[i]);
- if(err) return err;
- }
- }
-
- /* Set the data type to unset */
- data->type = UNSET;
- data->encset = 0;
- data->size = 0;
- data->used = 0;
-
- /* Forcibly clean union memory to avoid bleeding data */
- memset(&data->payload, 0, sizeof(data->payload));
-
- return SUCCESS;
-}
-
-dt_err bowl_addliteral(struct bowl *data, const char *literal)
-{
- /* Make sure we are a literal or unset data object */
- if(data->type != UNSET)
- if(data->type != LITERAL) return INVALID_PAYLOAD;
-
- size_t length = REAL_STRLEN(literal);
-
- /* Get rid of previous data */
- if(data->payload.literal) free(data->payload.literal);
-
- /* Allocate space for the data */
- char *tmp = (char *) malloc(sizeof(char) * length);
- if(tmp == NULL) {
- printf("Allocating space for literal data FAILED");
- return MALLOC_FAILED;
- }
-
- /* Copy the string over and store it in the union */
- strcpy(tmp, literal);
- data->payload.literal = tmp;
- data->type = LITERAL;
- data->size = length;
- data->used = length;
-
- return SUCCESS;
-}
-
-
-dt_err bowl_addpointer(struct bowl *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 bowl_addnumeral(struct bowl *data, long numeral)
-{
- /* Make sure we are a literal or unset data object */
- if(data->type != UNSET)
- if(data->type != NUMERIC) return INVALID_PAYLOAD;
-
- data->payload.numeral = numeral;
- data->type = NUMERIC;
- data->size = sizeof(int);
- data->used = sizeof(int);
- return SUCCESS;
-}
-
-
-dt_err bowl_addboolean(struct bowl *data, bool b)
-{
- /* Make sure we are a literal or unset data object */
- if(data->type != UNSET)
- if(data->type != BOOLEAN) return INVALID_PAYLOAD;
-
- data->payload.boolean = b;
- data->type = BOOLEAN;
- data->size = sizeof(bool);
- data->used = sizeof(bool);
- return SUCCESS;
-}
-
-
-dt_err bowl_addlist(struct bowl *data, struct bowl *(*new_data))
-{
- /* Make sure we are a literal or unset data object */
- if(data->type != UNSET)
- if(data->type != LIST) return INVALID_PAYLOAD;
-
- dt_err err;
-
- /* This means elements already exist */
- if(data->size > 0) {
-
- /* Used should never > size */
- if(data->used >= data->size) {
- data->size += RDB_REC_MULTIPLY;
-
- // TODO Use Realloc
- struct bowl **tmp = (struct bowl**) malloc(sizeof(struct bowl*) * data->size);
- memcpy(tmp, data->payload.list, sizeof(struct bowl*) * data->used);
-
- /* Free the list WITHOUT the children! */
- free(data->payload.list);
- data->payload.list = tmp;
- }
-
- /* This means the data object is new */
- } else {
- struct bowl **tmp = (struct bowl**) malloc(sizeof(struct bowl*) * RDB_REC_DEF_SIZE);
- data->payload.list = tmp;
- data->type = LIST;
- data->used = 0;
- data->size = RDB_REC_DEF_SIZE;
- }
-
- err = bowl_malloc(new_data);
- if(err) return err;
-
- /* Reference the slot, assign it, then move our ctr */
- data->payload.list[data->used++] = *new_data;
-
- return SUCCESS;
-}
-
-
-dt_err bowl_addpair(struct bowl *data, struct bowl *(*key), struct bowl *(*value))
-{
- /* Make sure we are a literal or unset data object */
- if(data->type != UNSET) return INVALID_PAYLOAD;
-
- dt_err err;
-
- /* Malloc two nodes */
- err = bowl_malloc(key);
- if(err) goto cleanup;
-
- err = bowl_malloc(value);
- if(err) goto cleanup;
-
- /** Malloc space for PAIR */
- data->size = 2;
- struct bowl **tmp = (struct bowl**) malloc(sizeof(struct bowl*) * data->size);
- if(!tmp) goto cleanup;
-
- data->payload.list = tmp;
-
- { /* Assign data to new array */
- data->payload.list[data->used] = *key;
- data->used++;
- data->payload.list[data->used] = *value;
- data->used++;
- }
-
- /* Assign our new type and return */
- data->type = PAIR;
- return SUCCESS;
-
- /* Code we run when we can't allocate structs anymore */
- cleanup:
- free(*key);
- free(*value);
- free(tmp);
- return MALLOC_FAILED;
-}
-
-
-dt_err bowl_split_trees(struct bowl *data, struct bowl *sp)
-{
- /* Make sure we are a literal or unset data object */
- if(data->type == UNSET) return INVALID_PAYLOAD;
-
- /* Check that sp is really a child of data */
- struct bowl *dp;
- int ret = list_search(&dp, data, sp);
- if(ret != 0) return DATA_NOT_RELATED;
- if(dp == NULL) return NODE_NOT_FOUND;
-
- /* Find the exact list reference and remove it */
- int i;
- for(i = 0; i < dp->used; i++) {
- if(dp->payload.list[i] == NULL) continue;
-
- /* Manually remove the entry */
- if(dp->payload.list[i] == sp) {
- dp->used--;
- dp->payload.list[i] = NULL;
- }
- }
-
- return SUCCESS;
-}
-
-
-dt_err bowl_merge_trees(struct bowl *data, struct bowl *merge)
-{
- /* REALLY make sure the type is correct */
- if(data->type == UNSET) return INVALID_PARAMS;
- if(!(data->type == LIST || data->type == PAIR))
- return INVALID_PAYLOAD;
-
- /* This means elements already exist */
- if(data->size > 0) {
-
- /* Used should never > size */
- if(data->used >= data->size) {
- data->size += RDB_REC_MULTIPLY;
-
- struct bowl **tmp = (struct bowl**) malloc(sizeof(struct bowl*) * data->size);
- memcpy(tmp, data->payload.list, sizeof(struct bowl*) * data->used);
-
- /* Free the list WITHOUT the children! */
- free(data->payload.list);
- data->payload.list = tmp;
- }
-
- /* This means the data object is new */
- } else {
- struct bowl **tmp = (struct bowl**) malloc(sizeof(struct bowl*) * data->size);
- data->payload.list = tmp;
- data->type = LIST;
- data->used = 0;
- data->size = RDB_REC_DEF_SIZE;
- }
-
- /* Reference the slot, assign it, then move our ctr */
- data->payload.list[data->used] = merge;
- data->used++;
-
- return SUCCESS;
-}
-
-
-dt_err bowl_copy_deep(struct bowl *data, struct bowl *(*copy))
-{
- if(data == NULL) return INVALID_PARAMS;
- dt_err err = SUCCESS;
-
- int it_type = -1;
- bowl_t type = data->type;
-
- /* Check if we're the first call */
- if((*copy) == NULL) bowl_malloc(copy);
- (*copy)->copy = DEEP;
-
- switch(type) {
- case LITERAL:
- bowl_addliteral(*copy, data->payload.literal);
- break;
-
- case NUMERIC:
- bowl_addnumeral(*copy, data->payload.numeral);
- break;
-
- case BOOLEAN:
- bowl_addboolean(*copy, data->payload.boolean);
- break;
-
- case LIST:
- {
- int i;
- int num = (int) data->used;
-
- for(i = 0; i < num; i++) {
- struct bowl *node = data->payload.list[i];
-
- struct bowl *new;
- bowl_addlist(*copy, &new);
- bowl_copy_deep(node, &new);
- }
-
- break;
- }
-
- case PAIR:
- {
- struct bowl *key, *val;
- bowl_addpair(*copy, &key, &val);
-
- struct bowl *orig_key = data->payload.list[0];
- struct bowl *orig_val = data->payload.list[1];
-
- bowl_copy_deep(orig_key, &key);
- bowl_copy_deep(orig_val, &val);
-
- break;
- }
-
- case POINTER:
- bowl_addpointer(*copy, data->payload.pointer);
- break;
-
- default:
- err = INVALID_PAYLOAD;
- break;
- }
-
- return err;
-}
-
-
-dt_err bowl_parent(struct bowl *root, struct bowl *data, struct bowl **parent)
+void *_get_data(struct bowl *ptr)
{
- if(root == NULL || data == NULL) return INVALID_PARAMS;
-
- /* Blank the search pointer for easy error checking */
- (*parent) = NULL;
-
- switch(root->type) {
-
- /* Dead-end data stores automatically return @{NODE_NOT_FOUND} */
- case POINTER:
- case LITERAL:
- case BOOLEAN:
- case NUMERIC:
- return NODE_NOT_FOUND;
-
- case PAIR:
- case LIST:
- {
- int i;
- for(i = 0; i < root->used; i++) {
-
- /* Check if the node we're looking at is what we're searching for */
- if(root->payload.list[i] == data) {
- (*parent) = root;
- return SUCCESS;
- }
-
- dt_err err = bowl_parent(root->payload.list[i], data, parent);
- if(err == SUCCESS) return SUCCESS;
- }
- }
- break;
-
- default:
- return INVALID_PAYLOAD;
+ switch(ptr->type) {
+ case ARRAY | HASH: return ptr->_pl.array;
+ case LINKED: return ptr->_pl.linked;
+ case LEAF: return ptr->_pl.data;
+ default: return NULL;
}
-
- return NODE_NOT_FOUND;
}
-
-dt_err bowl_copy(struct bowl *data, struct bowl *(*copy))
+err_t bowl_malloc(struct bowl **ptr, bowl_t type)
{
- if(data == NULL) return INVALID_PARAMS;
- dt_err err = SUCCESS;
-
- /* Allocate a new node */
- err = bowl_malloc(copy);
- if(err) goto exit;
-
- /* Mark as shallow copy */
- (*copy)->copy = SHALLOW;
-
- /* Find out how to handle specific payloads */
- switch(data->type) {
- case LITERAL:
- err = bowl_addliteral(*copy, data->payload.literal);
- break;
+ CHECK((type != 0), INVALID_PARAMS)
- case NUMERIC:
- err = bowl_addnumeral(*copy, data->payload.numeral);
- break;
+ (*ptr) = malloc(sizeof(struct bowl));
+ CHECK(*ptr, MALLOC_FAILED)
- case BOOLEAN:
- err = bowl_addboolean(*copy, data->payload.boolean);
- break;
+ memset(*ptr, 0, sizeof(struct bowl));
+ (*ptr)->type = type;
- case LIST:
- (*copy)->type = LIST;
- (*copy)->payload.list = (struct bowl**) malloc(sizeof(struct bowl*) * data->size);
- memcpy((*copy)->payload.list, data->payload.list, sizeof(struct bowl*) * data->used);
- break;
-
- case PAIR:
- (*copy)->type = PAIR;
- (*copy)->payload.list = (struct bowl**) malloc(sizeof(struct bowl*) * data->size);
- memcpy((*copy)->payload.list, data->payload.list, sizeof(struct bowl*) * data->used);
- break;
-
- case POINTER:
- (*copy)->type = POINTER;
- memcpy((*copy)->payload.pointer, data->payload.pointer, sizeof(void*));
- break;
-
- default:
- return INVALID_PAYLOAD;
+ switch((*ptr)->type) {
+ case LEAF: return OK; // No further allocation needed
+ case ARRAY: return array_malloc(*ptr, ARRAY_START_SIZE);
+ default: return INVALID_STATE;
}
- exit:
- return err;
+ return OK;
}
-
-dt_err bowl_search_payload(struct bowl *data, struct bowl *(*found), void *payload, bowl_t type)
+err_t bowl_insert(struct bowl *self, struct bowl *new)
{
- if(data == NULL) return INVALID_PARAMS;
-
- /* Make sure our pointer is clean */
- *found = NULL;
-
- if(data->type == LIST|| data->type == PAIR) {
-
- int i;
- for(i = 0; i < data->used; i++) {
- dt_err err = bowl_search_payload(data->payload.list[i], found, payload, type);
- if(err == SUCCESS) return SUCCESS;
- }
-
- } else {
-
- /* Check the type aligns */
- if(data->type != type) return NODE_NOT_FOUND;
-
- switch(type) {
- case LITERAL:
- if(strcmp(data->payload.literal, (char*) payload) == 0)
- *found = data;
- break;
-
- case NUMERIC:
- if(data->payload.numeral == (long) payload)
- *found = data;
- break;
-
- case BOOLEAN:
- if(data->payload.boolean == (bool) payload)
- *found = data;
- break;
-
- case POINTER:
- if(data->payload.pointer == payload)
- *found = data;
- break;
-
- default: return NODE_NOT_FOUND;
- }
-
- }
-
- return (*found == NULL) ? NODE_NOT_FOUND : SUCCESS;
-}
-
-// FIXME: This is horrible. Do via context?
-static int reached = 0;
-dt_err bowl_search_keypayload(struct bowl *data, struct bowl *(*found), void *payload, bowl_t type, int depth)
-{
- if(data == NULL) return INVALID_PARAMS;
- if(reached++ >= depth) return QUERY_TOO_DEEP;
-
- /* Make sure our pointer is clean */
- *found = NULL;
-
- /* We can only search LISTed values or PAIRs */
- if(data->type == PAIR) {
- struct bowl *key = data->payload.list[0];
-
- bowl_t tt;
- int hit = -1;
-
- if(strcmp(key->payload.literal, (char*) payload) == 0) {
- tt = LITERAL;
- hit = 0;
- }
-
- if(key->payload.numeral == (long) payload) {
- tt = NUMERIC;
- hit = 0;
- }
-
- if(key->payload.boolean == (bool) payload) {
- tt = BOOLEAN;
- hit = 0;
- }
-
- if(hit == 0) *found = data->payload.list[1];
-
- } else if(data->type == LIST) {
-
- int i;
- for(i = 0; i < data->used; i++) {
- bowl_search_keypayload(data->payload.list[i], found, payload, type, depth);
- }
-
- } else {
-
-
- }
-
- if(data->type == LIST|| data->type == PAIR) {
-
- int i;
- for(i = 0; i < data->used; i++) {
- dt_err err = bowl_search_payload(data->payload.list[i], found, payload, type);
- if(err == SUCCESS) return SUCCESS;
- }
-
- } else {
-
- /* Check the type aligns */
- if(data->type != type) return NODE_NOT_FOUND;
-
- switch(type) {
- case LITERAL:
- if(strcmp(data->payload.literal, (char*) payload) == 0)
- *found = data;
- break;
-
- case NUMERIC:
- if(data->payload.numeral == (long) payload)
- *found = data;
- break;
+ CHECK(self, INVALID_PARAMS)
+ CHECK(new, INVALID_PARAMS)
- case BOOLEAN:
- if(data->payload.boolean == (bool) payload)
- *found = data;
-
- case POINTER:
- if(data->payload.pointer == payload)
- *found = data;
- break;
-
- default: return NODE_NOT_FOUND;
- }
+ switch(self->type) {
+ case LEAF: return INVALID_PARAMS;
+ case ARRAY: return array_insert(self, new);
+ default: return INVALID_STATE;
}
- return (*found == NULL) ? NODE_NOT_FOUND : SUCCESS;
+ return OK;
}
-
-void list_print(struct bowl *data, const char *offset)
+err_t bowl_insert_key(struct bowl *self, size_t idx, struct bowl *child)
{
- bowl_t type = data->type;
-
- switch(type) {
- case UNSET:
- printf("[NULL]\n");
- break;
-
- case LITERAL:
- printf("%s['%s']\n", offset, data->payload.literal);
- break;
-
- case NUMERIC:
- printf("%s[%lu]\n", offset, data->payload.numeral);
- break;
-
- case BOOLEAN:
- printf("%s['%s']\n", offset, (data->payload.boolean) ? "TRUE" : "FALSE");
- break;
-
- case PAIR:
- {
- bowl_t k_type = data->payload.list[0]->type;
- bowl_t v_type = data->payload.list[1]->type;
-
- if(k_type == LITERAL) printf("%s['%s']", offset, data->payload.list[0]->payload.literal);
- if(k_type == NUMERIC) printf("%s[%lu]", offset, data->payload.list[0]->payload.numeral);
- if(k_type == BOOLEAN) printf("%s[%s]", offset, (data->payload.list[0]->payload.boolean) ? "TRUE" : "FALSE");
-
- char new_offset[REAL_STRLEN(offset) + 2];
- strcpy(new_offset, offset);
- strcat(new_offset, " ");
-
- if(k_type == LIST || k_type == PAIR) list_print(data->payload.list[0], new_offset);
-
- /* Print the value now */
- if(v_type == LITERAL) printf(" => ['%s']\n", data->payload.list[1]->payload.literal);
- if(v_type== NUMERIC) printf(" => [%lu]\n", data->payload.list[1]->payload.numeral);
- if(v_type == BOOLEAN) printf(" => [%s]\n", (data->payload.list[1]->payload.boolean) ? "TRUE" : "FALSE");
-
- if(v_type == LIST || k_type == PAIR) list_print(data->payload.list[1], new_offset);
-
- break;
- }
-
- case LIST:
- {
- int i;
- printf("%s[LIST]\n", offset);
- for(i = 0; i < data->used; i++) {
- bowl_t t = data->payload.list[i]->type;
-
- /* Calculate the new offset */
- char new_offset[REAL_STRLEN(offset) + 2];
- strcpy(new_offset, offset);
- strcat(new_offset, " ");
-
- switch(t) {
- case LITERAL:
- case BOOLEAN:
- case NUMERIC:
- list_print(data->payload.list[i], new_offset);
- continue;
-
- case LIST:
- list_print(data->payload.list[i], new_offset);
- continue;
-
- case PAIR:
- printf("%s[PAIR] <==> ", new_offset);
- list_print(data->payload.list[i], new_offset);
- continue;
-
- default:
- break;
- }
- }
- break;
- }
+ CHECK(self, INVALID_PARAMS)
+ CHECK(child, INVALID_PARAMS)
+ CHECK((idx >= 0), INVALID_PARAMS)
- default:
- break;
+ switch(self->type) {
+ case LEAF: return INVALID_PARAMS;
+ case ARRAY: return array_insert_key(self, idx, child);
+ default: return INVALID_STATE;
}
}
-
-void bowl_print(struct bowl *data)
+err_t bowl_swap_key(struct bowl *self, size_t idx, struct bowl *child, struct bowl **prev)
{
- list_print(data, "");
-}
+ CHECK(self, INVALID_PARAMS)
+ CHECK(child, INVALID_PARAMS)
+ CHECK((idx >= 0), INVALID_PARAMS)
-dt_err bowl_get(struct bowl *data, void *(*val))
-{
- if(data->type == LITERAL) *val = data->payload.literal;
- if(data->type == NUMERIC) *val = &data->payload.numeral;
- if(data->type == BOOLEAN) *val = &data->payload.boolean;
- if(data->type == LIST || data->type == PAIR) *val = (struct bowl*) data->payload.list;
- return SUCCESS;
-}
-
-
-dt_err bowl_free(struct bowl *data)
-{
- if(data == NULL) return SUCCESS;
- if(data->copy == SHALLOW) return NODE_NOT_ORIGINAL;
+ switch(self->type) {
+ case LEAF: return INVALID_PARAMS;
+ case ARRAY: return array_swap_key(self, idx, child, prev);
- if(data->type == LITERAL) {
- if(data->payload.literal) free(data->payload.literal);
-
- } else if(data->type == LIST || data->type == PAIR) {
- int i;
- dt_err err;
- for(i = 0; i < data->used; i++) {
-
- err = bowl_free(data->payload.list[i]);
- if(err) return err;
- }
-
- free(data->payload.list);
-
- } else if(data->type == POINTER) {
- if(data->copy != SHALLOW && data->payload.pointer)
- free(data->payload.pointer);
+ default: return INVALID_STATE;
}
-
- free(data);
- return SUCCESS;
}
-
-dt_err bowl_free_shallow(struct bowl *data)
+err_t bowl_remove(struct bowl *self, struct bowl *child)
{
- if(data == NULL) return SUCCESS;
+ CHECK(self, INVALID_PARAMS)
+ CHECK(child, INVALID_PARAMS)
- if(data->type == LITERAL) {
- if(data->payload.literal) free(data->payload.literal);
- } else if(data->type == LIST || data->type == PAIR) {
- int i;
- dt_err err;
- for(i = 0; i < data->size; i++) {
- err = bowl_free(data->payload.list[i]);
- if(err) return err;
- }
+ switch(self->type) {
+ case LEAF: return INVALID_PARAMS;
+ case ARRAY: return array_remove(self, child);
- free(data->payload.list);
+ default: return INVALID_STATE;
}
-
- free(data);
- return SUCCESS;
}
-
-const char *bowl_dtype(struct bowl *data)
+err_t bowl_remove_key(struct bowl *self, size_t idx, struct bowl **prev)
{
- switch(data->type) {
- case LITERAL: return "Literal";
- case NUMERIC: return "Numeric";
- case BOOLEAN: return "Boolean";
- case LIST: return "List";
- case PAIR: return "Pair";
- case POINTER: return "Pointer";
- default: return "Unknown";
- }
-}
+ CHECK(self, INVALID_PARAMS)
+ CHECK((idx >= 0), INVALID_PARAMS)
+ switch(self->type) {
+ case LEAF: return INVALID_PARAMS;
+ case ARRAY: return array_remove_key(self, idx, prev);
-/**************** PRIVATE UTILITY FUNCTIONS ******************/
-
-
-/**
- * Steps down the list hirarchy of a dyntree node to
- * find a sub-child target. Returns 0 if it can be found.
- *
- * @param data
- * @param target
- * @return
- */
-int list_search(struct bowl **direct_parent, struct bowl *data, struct bowl *target)
-{
- /* Check if data is actually valid */
- if(data == NULL) return 1;
-
- /* Compare the pointers :) */
- if(data == target) return 0;
-
- int res = 1;
- if(data->type == LIST || data->type == PAIR) {
- int i;
- for(i = 0; i < data->used; i++) {
- res = list_search(direct_parent, data->payload.list[i], target);
- if(res == 0) {
-
- /* Save the node that contains our child for later */
- (*direct_parent) = data;
- return res;
- }
- }
+ default: return INVALID_STATE;
}
-
- return res;
}
-
-/**
- * Small utility function that checks if a datablock is valid to write into.
- * Potentially releases previously owned memory to prevent memory leaks
- *
- * @param data The bowl object to check
- * @return
- */
-dt_err data_check(struct bowl *data)
+err_t bowl_free(struct bowl *self)
{
- /* Check if the data block has children */
- if(data->type == LIST)
- {
- printf("Won't override heap payload with data!");
- return INVALID_PAYLOAD;
- }
+ CHECK(self, INVALID_PARAMS)
- /* Free the existing string */
- if(data->type == LITERAL)
- {
- if(data->payload.literal) free(data->payload.literal);
+ err_t e;
+ switch(self->type) {
+ case LEAF: e = data_free(self->_pl.data); break;
+ case ARRAY: e = array_free(self); break;
+ default: e = INVALID_STATE; break;
}
+ if(e) return e;
- return SUCCESS;
+ free(self);
+ return OK;
}