diff --git a/include/rjp.h b/include/rjp.h index 7028a14..c064e54 100644 --- a/include/rjp.h +++ b/include/rjp.h @@ -74,14 +74,23 @@ typedef struct RJP_string{ }RJP_string; //Forward declarations -struct RJP_object_member; struct RJP_array_element; +typedef struct RJP_tree_node RJP_tree_node; + +typedef struct RJP_tree_stack{ + RJP_tree_node** data; + int size; + int pos; +}RJP_tree_stack; +typedef struct RJP_object_iterator{ + RJP_tree_stack stack; + RJP_tree_node* current; +}RJP_object_iterator; //Represents a json object typedef struct RJP_object{ - struct RJP_object_member* members; //linked list of members - struct RJP_object_member* last; //final member of linked list - size_t num_members; + struct RJP_tree_node* root; + int num_members; }RJP_object; //Represents a json array @@ -162,7 +171,7 @@ RJP_value rjp_object(void); RJP_value rjp_array(void); //Access first member of a json object -RJP_value* rjp_get_member(const RJP_value* object); +RJP_value* rjp_get_member(RJP_object_iterator* object); //Access next member of a json object given the previous member RJP_value* rjp_next_member(const RJP_value* member); //Return number of members in the object @@ -172,13 +181,10 @@ char* rjp_member_name(const RJP_value* member); //Return the object member's key name length excluding null terminator size_t rjp_member_name_length(const RJP_value* member); //Search for an object member with given key -RJP_search_res rjp_search_member(const RJP_value* object, const char* search, size_t skip); +RJP_value* rjp_search_member(const RJP_value* object, const char* search); //Search for first occurance of multiple keys. Returns first occurance of each. //Assumes dest is large enough to hold maximum num items. -size_t rjp_search_members(const RJP_value* object, size_t num, const char* const* searches, RJP_search_res* dest, size_t skip); -//Search for multiple occurances of multiple keys. Returns pointer to list of matches. -//Returned pointer must be freed using rjp_free -RJP_search_res* rjp_search_members_multi(const RJP_value* object, size_t num, const char* const* searches, size_t* rsize, size_t skip); +size_t rjp_search_members(const RJP_value* object, size_t num, const char* const* searches, RJP_value** dest); //Access first element of a json array RJP_value* rjp_get_element(const RJP_value* array); //Access next element of a json array given the previous element diff --git a/include/rjp_internal.h b/include/rjp_internal.h index 5a6022b..1b5bb18 100644 --- a/include/rjp_internal.h +++ b/include/rjp_internal.h @@ -39,15 +39,8 @@ typedef struct RJP_array_element{ struct RJP_value value; struct RJP_array_element* next; }RJP_array_element; -//A member of an object -typedef struct RJP_object_member{ - struct RJP_value value; - struct RJP_string name; - struct RJP_object_member* next; -}RJP_object_member; void irjp_add_element(RJP_array* j); -void irjp_add_member(RJP_object* j, const char* str, size_t len); void irjp_add_member_no_alloc(RJP_object* j, char* str, size_t len); - +void irjp_delete_value(RJP_value* root); #endif diff --git a/include/tree.h b/include/tree.h index 21f4acc..7529317 100644 --- a/include/tree.h +++ b/include/tree.h @@ -22,14 +22,15 @@ struct RJP_tree_node{ unsigned color:1; }; -RJP_tree_node* irjp_new_node(RJP_object_member value); -RJP_tree_node* irjp_tree_insert_value(RJP_tree_node* root, RJP_object_member value, int* status); -RJP_tree_node* irjp_tree_remove_value(RJP_tree_node* root, RJP_object_member value, int* status); -RJP_tree_node* irjp_tree_search_value(RJP_tree_node* root, RJP_object_member value); -RJP_tree_node* irjp_copy_tree(RJP_tree_node* root); + +RJP_tree_node* irjp_new_node(RJP_object_member* value); +RJP_tree_node* irjp_tree_insert_value(RJP_tree_node* root, RJP_object_member* value, int* status); +RJP_tree_node* irjp_tree_remove_value(RJP_tree_node* root, const char* key, int* status); +RJP_tree_node* irjp_tree_search_value(RJP_tree_node* root, const char* key); +RJP_tree_node* irjp_copy_tree(const RJP_tree_node* root); void irjp_free_tree(RJP_tree_node* root); -int irjp_init_object_iterator(RJP_object_iterator* it, RJP_tree_node* root); +int irjp_init_object_iterator(RJP_object_iterator* it, const RJP_tree_node* root); void irjp_delete_object_iterator(RJP_object_iterator* it); RJP_tree_node* irjp_object_iterator_next(RJP_object_iterator* it); RJP_tree_node* irjp_object_iterator_current(RJP_object_iterator* it); diff --git a/src/memory.c b/src/memory.c index 362c346..6c56094 100644 --- a/src/memory.c +++ b/src/memory.c @@ -18,6 +18,7 @@ #include "rjp_internal.h" #include "strings.h" +#include "tree.h" #include #include @@ -35,14 +36,6 @@ void rjp_free(void* data){ free(data); } -static void irjp_copy_object(RJP_value* dest, const RJP_value* src){ - dest->object.members = dest->object.last = 0; - for(RJP_value* curr = rjp_get_member(src);curr;curr = rjp_next_member(curr)){ - RJP_value copy_mem; - rjp_copy_value(©_mem, curr); - rjp_add_member(dest, rjp_member_name(curr), rjp_member_name_length(curr), copy_mem); - } -} static void irjp_copy_array(RJP_value* dest, const RJP_value* src){ dest->array.elements = dest->array.last = 0; for(RJP_value* curr = rjp_get_element(src);curr;curr = rjp_next_element(curr)){ @@ -57,7 +50,8 @@ void rjp_copy_value(RJP_value* dest, const RJP_value* src){ switch(src->type){ case rjp_json_object: - irjp_copy_object(dest, src); + irjp_free_tree(dest->object.root); + dest->object.root = irjp_copy_tree(src->object.root); break; case rjp_json_array: irjp_copy_array(dest, src); @@ -79,13 +73,12 @@ void rjp_copy_value(RJP_value* dest, const RJP_value* src){ }; } -static void irjp_free_object_recurse(RJP_value* root); static void irjp_free_array(RJP_value* root){ RJP_array_element* arr = root->array.elements; for(RJP_array_element* i = arr;i != NULL;i = arr){ arr = arr->next; if(i->value.type == rjp_json_object){ - irjp_free_object_recurse(&i->value); + irjp_free_tree(i->value.object.root); }else if(i->value.type == rjp_json_array){ irjp_free_array(&i->value); }else if(i->value.type == rjp_json_string){ @@ -94,32 +87,18 @@ static void irjp_free_array(RJP_value* root){ free(i); } } -//Recursively free JSON objects -static void irjp_free_object_recurse(RJP_value* root){ - RJP_object_member* next; - for(RJP_object_member* m = root->object.members;m;m = next){ - next = m->next; - if(m->value.type == rjp_json_object) - irjp_free_object_recurse(&m->value); - else if(m->value.type == rjp_json_string) - free(m->value.string.value); - else if(m->value.type == rjp_json_array) - irjp_free_array(&m->value); - if(m->name.value) - free(m->name.value); - free(m); - } -} -//Same as recurse but also frees root node +void irjp_delete_value(RJP_value* root){ + if((root->type) == rjp_json_object) + irjp_free_tree(root->object.root); + else if((root->type) == rjp_json_array) + irjp_free_array(root); + else if((root->type) == rjp_json_string) + rjp_free(root->string.value); +} void rjp_free_value(RJP_value* root){ if(!root) return; - - if((root->type) == rjp_json_object) - irjp_free_object_recurse(root); - else if((root->type) == rjp_json_array) - irjp_free_array(root); - + irjp_delete_value(root); free(root); } diff --git a/src/rjp.c b/src/rjp.c index b4b1013..fe52349 100644 --- a/src/rjp.c +++ b/src/rjp.c @@ -17,6 +17,7 @@ */ #include "rjp_internal.h" +#include "tree.h" #include //strncpy, strlen @@ -30,49 +31,31 @@ void irjp_add_element(RJP_array* j){ j->last = j->last->next; } } -//create member of the object as a linked list member and assign a name with name allocation -void irjp_add_member(RJP_object* j, const char* str, size_t len){ - ++j->num_members; - if(!j->members){ - j->members = rjp_calloc(1, sizeof(RJP_object_member)); - j->last = j->members; - }else{ - j->last->next = rjp_calloc(1, sizeof(RJP_object_member)); - j->last = j->last->next; - } - j->last->name.value = rjp_alloc(len + 1); - strncpy(j->last->name.value, str, len); - j->last->name.value[len] = 0; - j->last->name.length = len; -} -void irjp_add_member_no_alloc(RJP_object* j, char* str, size_t len){ - ++j->num_members; - if(!j->members){ - j->members = rjp_calloc(1, sizeof(RJP_object_member)); - j->last = j->members; - }else{ - j->last->next = rjp_calloc(1, sizeof(RJP_object_member)); - j->last = j->last->next; - } - j->last->name.value = str; - j->last->name.length = len; -} RJP_value* rjp_add_member(RJP_value* dest, const char* key, size_t keylen, RJP_value value){ if(!keylen) keylen = strlen(key); - irjp_add_member(&dest->object, key, keylen); - dest->object.last->value = value; - dest->object.last->value.parent = dest; - return &dest->object.last->value; + ++dest->object.num_members; + RJP_object_member mem; + mem.name.value = rjp_alloc(keylen+1); + strncpy(mem.name.value, key, keylen); + mem.name.value[keylen] = 0; + mem.name.length = keylen; + mem.value = value; + + int status; + return &irjp_tree_insert_value(dest->object.root, &mem, &status)->data.value; } RJP_value* rjp_add_member_no_alloc(RJP_value* dest, char* key, size_t keylen, RJP_value value){ if(!keylen) keylen = strlen(key); - irjp_add_member_no_alloc(&dest->object, key, keylen); - dest->object.last->value = value; - dest->object.last->value.parent = dest; - return &dest->object.last->value; + RJP_object_member mem; + mem.name.value = key; + mem.name.length = keylen; + mem.value = value; + + int status; + return &irjp_tree_insert_value(dest->object.root, &mem, &status)->data.value; } RJP_value* rjp_add_element(RJP_value* dest, RJP_value value){ irjp_add_element(&dest->array); @@ -140,12 +123,16 @@ RJP_value rjp_array(void){ } -RJP_value* rjp_get_member(const RJP_value* object){ - return &object->object.members->value; +RJP_value* rjp_get_member(RJP_object_iterator* it){ + return &it->current->data.value; } -RJP_value* rjp_next_member(const RJP_value* member){ - //polymorphism - return (RJP_value*)(((RJP_object_member*)member)->next); +RJP_object_iterator rjp_get_object_iterator(const RJP_value* object){ + RJP_object_iterator it; + irjp_init_object_iterator(&it, object->object.root); + return it; +} +void rjp_object_iterator_next(RJP_object_iterator* it){ + irjp_object_iterator_next(it); } size_t rjp_num_members(const RJP_value* object){ return object->object.num_members; @@ -157,75 +144,27 @@ size_t rjp_member_name_length(const RJP_value* member){ return ((RJP_object_member*)member)->name.length; } -RJP_search_res rjp_search_member(const RJP_value* object, const char* search, size_t skip){ - RJP_value* member = rjp_get_member(object); - size_t i = 0; - for(;i < skip && member;member = rjp_next_member(member),++i); - - for(;member;member = rjp_next_member(member),++i){ - if(!strcmp(((RJP_object_member*)member)->name.value, search)){ - return (RJP_search_res){member, 0, i}; - } - } - return (RJP_search_res){0}; +RJP_value* rjp_search_member(const RJP_value* object, const char* search){ + RJP_tree_node* n = irjp_tree_search_value(object->object.root, search); + if(!n) + return NULL; + return &n->data.value; } -size_t rjp_search_members(const RJP_value* object, size_t num, const char* const* searches, RJP_search_res* dest, size_t skip){ - for(size_t i = 0;i < num;++i){ - dest[i] = (RJP_search_res){0}; - } - RJP_value* member = rjp_get_member(object); - size_t objindex = 0; - for(;objindex < skip && member;member = rjp_next_member(member),++objindex); +size_t rjp_search_members(const RJP_value* object, size_t num, const char* const* searches, RJP_value** dest){ size_t matches = 0; - for(;member;member = rjp_next_member(member),++objindex){ - for(size_t i = 0;i < num;++i){ - if(dest[i].value != NULL) - continue; - if(!strcmp(((RJP_object_member*)member)->name.value, searches[i])){ - dest[i].value = member; - dest[i].searchindex = i; - dest[i].objindex = objindex; - ++matches; - break; - } + for(size_t i = 0;i < num;++i){ + RJP_tree_node* n = irjp_tree_search_value(object->object.root, searches[i]); + if(!n){ + dest[i] = NULL; + }else{ + dest[i] = &n->data.value; + ++matches; } } return matches; } -RJP_search_res* rjp_search_members_multi(const RJP_value* object, size_t num, const char* const* searches, size_t* rsize, size_t skip){ - RJP_search_res* ret = rjp_alloc(num*sizeof(RJP_search_res)); - size_t ret_size = num; - size_t j = 0; - - RJP_value* member = rjp_get_member(object); - size_t objindex = 0; - for(;objindex < skip && member;member = rjp_next_member(member),++objindex); - - for(;member;member = rjp_next_member(member),++objindex){ - for(size_t i = 0;i < num;++i){ - if(!strcmp(((RJP_object_member*)member)->name.value, searches[i])){ - ret[j].value = member; - ret[j].searchindex = i; - ret[j].objindex = objindex; - ++j; - if(j == ret_size){ - ret_size *= 2; - ret = rjp_realloc(ret, ret_size*sizeof(RJP_search_res)); - } - break; - } - } - } - if(rsize) - *rsize = j; - if(j == 0){ - rjp_free(ret); - return NULL; - } - return ret; -} RJP_value* rjp_get_element(const RJP_value* array){ return &array->array.elements->value; diff --git a/src/strings.c b/src/strings.c index e3be018..a88a40d 100644 --- a/src/strings.c +++ b/src/strings.c @@ -21,6 +21,7 @@ #include "strings.h" #include "rjp_internal.h" +#include "tree.h" #include //fprintf #include //malloc, free @@ -325,33 +326,43 @@ size_t irjp_array_strlen_pretty(const RJP_value* arr, int depth){ size_t irjp_object_strlen(const RJP_value* root){ size_t count = 2; //{} - const RJP_object* root_obj = &root->object; - const RJP_object_member* member_list = root_obj->members; - for(;member_list;member_list = member_list->next){ - if(member_list->name.length == 0 || member_list->name.value[0] == 0) + RJP_object_iterator it; + irjp_init_object_iterator(&it, root->object.root); + RJP_tree_node* current = irjp_object_iterator_current(&it); + while(current){ + RJP_object_member* mem = ¤t->data; + if(mem->name.length == 0 || mem->name.value[0] == 0){ + irjp_delete_object_iterator(&it); return 0; - count += member_list->name.length + 3; //"": - count += irjp_value_strlen(&member_list->value); - if(member_list->next) + } + count += mem->name.length + 3; //"": + count += irjp_value_strlen(&mem->value); + if((current = irjp_object_iterator_next(&it))) ++count; //, } + irjp_delete_object_iterator(&it); return count; } size_t irjp_object_strlen_pretty(const RJP_value* root, int depth){ size_t count = 3 + depth; //{\n\t} ++depth; - const RJP_object* root_obj = &root->object; - const RJP_object_member* member_list = root_obj->members; - for(;member_list;member_list = member_list->next){ - if(member_list->name.length == 0 || member_list->name.value[0] == 0) + RJP_object_iterator it; + irjp_init_object_iterator(&it, root->object.root); + RJP_tree_node* current = irjp_object_iterator_current(&it); + while(current){ + RJP_object_member* mem = ¤t->data; + if(mem->name.length == 0 || mem->name.value[0] == 0){ + irjp_delete_object_iterator(&it); return 0; - count += member_list->name.length + 4; //"":space - count += irjp_value_strlen_pretty(&member_list->value, depth); + } + count += mem->name.length + 4; //"":space + count += irjp_value_strlen_pretty(&mem->value, depth); count += depth; //tabs ++count; //newline - if(member_list->next) + if((current = irjp_object_iterator_next(&it))) ++count; //, } + irjp_delete_object_iterator(&it); return count; } diff --git a/src/tree.c b/src/tree.c index 0b3c4a8..7981649 100644 --- a/src/tree.c +++ b/src/tree.c @@ -5,30 +5,14 @@ #include #include "strings.h" +#include "rjp_internal.h" #define BLACK 0 #define RED 1 -//TMP -#define rjp_malloc malloc -#define rjp_free free -#define rjp_free_value(x) -#define irjp_strcpy(dest, src) do{(dest)->value = rjp_malloc((src)->length + 1);strcpy((dest)->value, (src)->value);(dest)->value[(src)->length] = 0;(dest)->length = (src)->length;}while(0); -#define rjp_copy_value(dest, src) ((dest)->integer = (src)->integer) #define RJP_TREE_ITERATOR_STACK_START_SIZE 32 -//Internal use only structs -typedef struct RJP_tree_stack{ - RJP_tree_node** data; - int size; - int pos; -}RJP_tree_stack; -typedef struct RJP_object_iterator{ - RJP_tree_stack stack; - RJP_tree_node* current; -}RJP_object_iterator; - //Forward declare static functions static inline RJP_tree_node* irjp_grandparent(RJP_tree_node* n); static inline RJP_tree_node* irjp_sibling(RJP_tree_node* n); @@ -40,8 +24,8 @@ static inline int irjp_is_inside_right(RJP_tree_node* n); static void irjp_replace_node(RJP_tree_node *restrict node, RJP_tree_node *restrict child); static void irjp_copy_node_data(RJP_tree_node *restrict dest, RJP_tree_node *restrict src); -static RJP_tree_node* irjp_clone_node(RJP_tree_node* src, RJP_tree_node* parent); -static RJP_tree_node* irjp_copy_node(RJP_tree_node* root, RJP_tree_node* parent); +static RJP_tree_node* irjp_clone_node(const RJP_tree_node* src, RJP_tree_node* parent); +static RJP_tree_node* irjp_copy_node(const RJP_tree_node* root, RJP_tree_node* parent); static void irjp_free_node(RJP_tree_node* node); static void irjp_delete_node(RJP_tree_node* node); @@ -131,24 +115,24 @@ static void irjp_replace_node(RJP_tree_node *restrict node, RJP_tree_node *restr } //Node construction / destruction -RJP_tree_node* irjp_new_node(RJP_object_member value){ - RJP_tree_node* node = rjp_malloc(sizeof(RJP_tree_node)); - node->data.name = value.name; - node->data.value = value.value; +RJP_tree_node* irjp_new_node(RJP_object_member* value){ + RJP_tree_node* node = rjp_alloc(sizeof(RJP_tree_node)); + node->data.name = value->name; + node->data.value = value->value; node->parent = node->left = node->right = NULL; return node; } static void irjp_copy_node_data(RJP_tree_node *restrict dest, RJP_tree_node *restrict src){ dest->data = src->data; } -static RJP_tree_node* irjp_clone_node(RJP_tree_node* src, RJP_tree_node* parent){ - RJP_tree_node* dest = rjp_malloc(sizeof(RJP_tree_node)); +static RJP_tree_node* irjp_clone_node(const RJP_tree_node* src, RJP_tree_node* parent){ + RJP_tree_node* dest = rjp_alloc(sizeof(RJP_tree_node)); rjp_copy_value(&dest->data.value, &src->data.value); irjp_strcpy(&dest->data.name, &src->data.name); dest->parent = parent; return dest; } -static RJP_tree_node* irjp_copy_node(RJP_tree_node* root, RJP_tree_node* parent){ +static RJP_tree_node* irjp_copy_node(const RJP_tree_node* root, RJP_tree_node* parent){ if(!root){ return NULL; } @@ -163,14 +147,14 @@ static void irjp_free_node(RJP_tree_node* node){ } static void irjp_delete_node(RJP_tree_node* node){ rjp_free(node->data.name.value); - rjp_free_value(&node->data.value); + irjp_delete_value(&node->data.value); } /* TREE STACK */ //Stack construction / destruction static int irjp_init_tree_stack(RJP_tree_stack* stack){ - stack->data = rjp_malloc(sizeof(RJP_tree_node*)*RJP_TREE_ITERATOR_STACK_START_SIZE); + stack->data = rjp_alloc(sizeof(RJP_tree_node*)*RJP_TREE_ITERATOR_STACK_START_SIZE); stack->size = RJP_TREE_ITERATOR_STACK_START_SIZE; stack->pos = 0; return 0; @@ -180,7 +164,7 @@ static void irjp_delete_tree_stack(RJP_tree_stack* stack){ } static void irjp_resize_tree_stack(RJP_tree_stack* stack){ int newsize = stack->size*2; - RJP_tree_node** newdata = rjp_malloc(sizeof(RJP_tree_node*)*newsize); + RJP_tree_node** newdata = rjp_alloc(sizeof(RJP_tree_node*)*newsize); for(int i = 0;i < stack->size;++i){ newdata[i] = stack->data[i]; } @@ -203,9 +187,9 @@ static RJP_tree_node* irjp_peek_tree_stack(RJP_tree_stack* stack){ /* TREE ITERATOR */ //Iterator construction / destruction -int irjp_init_object_iterator(RJP_object_iterator* it, RJP_tree_node* root){ +int irjp_init_object_iterator(RJP_object_iterator* it, const RJP_tree_node* root){ irjp_init_tree_stack(&it->stack); - it->current = root; + it->current = (RJP_tree_node*)root; while(it->current){ irjp_push_tree_stack(&it->stack, it->current); it->current = it->current->left; @@ -230,7 +214,7 @@ RJP_tree_node* irjp_object_iterator_current(RJP_object_iterator* it){ /* TREE */ //Tree construction / destruction -RJP_tree_node* irjp_copy_tree(RJP_tree_node* root){ +RJP_tree_node* irjp_copy_tree(const RJP_tree_node* root){ return irjp_copy_node(root, NULL); } void irjp_free_tree(RJP_tree_node* root){ @@ -241,7 +225,7 @@ void irjp_free_tree(RJP_tree_node* root){ irjp_free_node(root); } //Tree operations -RJP_tree_node* irjp_tree_insert_value(RJP_tree_node* root, RJP_object_member value, int* status){ +RJP_tree_node* irjp_tree_insert_value(RJP_tree_node* root, RJP_object_member* value, int* status){ *status = RJP_TREE_SUCCESS; if(!root){ root = irjp_new_node(value); @@ -318,9 +302,9 @@ static RJP_tree_node* irjp_tree_repair(RJP_tree_node* node){ } } -RJP_tree_node* irjp_tree_search_value(RJP_tree_node* root, RJP_object_member value){ +RJP_tree_node* irjp_tree_search_value(RJP_tree_node* root, const char* key){ while(root != NULL){ - int cmpval = strcmp(value.name.value, root->data.name.value); + int cmpval = strcmp(key, root->data.name.value); if(cmpval < 0){ root = root->left; }else if(cmpval > 0){ @@ -398,12 +382,12 @@ void irjp_dbg_print_tree_bfs(RJP_tree_node* root){ #undef pop #undef push -RJP_tree_node* irjp_tree_remove_value(RJP_tree_node* root, RJP_object_member value, int* status){ +RJP_tree_node* irjp_tree_remove_value(RJP_tree_node* root, const char* key, int* status){ if(!root){ *status = RJP_TREE_ERR_NULL_ROOT; return root; } - RJP_tree_node* n = irjp_tree_search_value(root, value); + RJP_tree_node* n = irjp_tree_search_value(root, key); if(!n){ *status = RJP_TREE_ERR_NOT_FOUND; return root;