7 Commits

Author SHA1 Message Date
rexy712
2e9571115a Fix API function mk2 2020-02-29 13:07:05 -08:00
rexy712
3e1a785938 Add missing API function 2020-02-29 13:01:12 -08:00
rexy712
7b54b12e6e Add ordered objects using linked lists. Add wrapper for auto selecting functions to call given either object type. Add conversion functions between object types. 2020-02-29 11:58:11 -08:00
rexy712
99cc9a5154 Fix pretty printing 2020-02-27 10:17:33 -08:00
rexy712
ffac4718e8 Update TODO 2020-02-26 18:31:20 -08:00
rexy712
4b68e32298 Version update 2020-02-26 18:24:39 -08:00
rexy712
07c07cc06b Fix object iterator skipping values 2020-02-26 18:24:18 -08:00
15 changed files with 668 additions and 197 deletions

View File

@@ -4,8 +4,8 @@ include(GNUInstallDirs)
cmake_minimum_required(VERSION 3.0.2)
project(rjp)
set(rjp_VERSION_MAJOR 0)
set(rjp_VERSION_MINOR 8)
set(rjp_VERSION_REVISION 2)
set(rjp_VERSION_MINOR 9)
set(rjp_VERSION_REVISION 0)
set(INCLUDE_PATH ${CMAKE_SOURCE_DIR}/include)
configure_file(
"${INCLUDE_PATH}/config.h.in"
@@ -16,7 +16,7 @@ include_directories("${INCLUDE_PATH}")
option(ENABLE_DIAGNOSTICS "Print diagnostic messages when parsing json to help identify issues" ON)
option(ENABLE_SHARED "Build shared library" OFF)
set(SOURCE_LIST "src/input.c" "src/output.c" "src/rjp_array.c" "src/rjp.c" "src/rjp_object.c" "src/rjp_string.c" "src/tree.c")
set(SOURCE_LIST "src/rjp_ordered_object.c" "src/rjp_unordered_object.c" "src/input.c" "src/output.c" "src/rjp_array.c" "src/rjp.c" "src/rjp_object.c" "src/rjp_string.c" "src/tree.c")
if(ENABLE_SHARED)
add_library(rjp SHARED ${SOURCE_LIST})
set_target_properties(rjp PROPERTIES SOVERSION "${rjp_VERSION_MAJOR}.${rjp_VERSION_MINOR}.${rjp_VERSION_REVISION}")

3
TODO
View File

@@ -2,5 +2,4 @@ Change string handling to work with chunked reading
Change numeral handling to work with chunked reading
handle scientific notation
modularize internal object management. eg tree.h should only be needed in object.c and tree.c
Add ability to specify object order explicitly

View File

@@ -51,13 +51,14 @@ extern "C"{
//type of data
typedef enum RJP_data_type{
rjp_json_object = 0,
rjp_json_string,
rjp_json_integer,
rjp_json_dfloat,
rjp_json_boolean,
rjp_json_array,
rjp_json_null
rjp_json_object = 1,
rjp_json_ordered_object = 3,
rjp_json_string = 2,
rjp_json_integer = 4,
rjp_json_dfloat = 8,
rjp_json_boolean = 16,
rjp_json_array = 32,
rjp_json_null = 64
}RJP_data_type;
@@ -72,7 +73,11 @@ typedef struct RJP_string{
//Forward declarations
struct RJP_object_iterator_impl;
typedef struct RJP_object_iterator{
struct RJP_object_iterator_impl* it;
union{
struct RJP_object_iterator_impl* it;
RJP_value* current;
};
RJP_data_type type;
}RJP_object_iterator;
typedef struct RJP_array_iterator{
@@ -110,6 +115,7 @@ RJP_value* rjp_new_bool(RJP_bool val);
RJP_value* rjp_new_string_copy(const char* val, RJP_index length);
RJP_value* rjp_new_string(char* val, RJP_index length);
RJP_value* rjp_new_object(void);
RJP_value* rjp_new_ordered_object(void);
RJP_value* rjp_new_array(void);
//Deallocate RJP_value
@@ -129,6 +135,7 @@ RJP_value* rjp_set_bool(RJP_value* v, RJP_bool val);
RJP_value* rjp_set_string_copy(RJP_value* v, const char* val, RJP_index length);
RJP_value* rjp_set_string(RJP_value* v, char* val, RJP_index length);
RJP_value* rjp_set_object(RJP_value* v);
RJP_value* rjp_set_ordered_object(RJP_value* v);
RJP_value* rjp_set_array(RJP_value* v);
RJP_float rjp_get_float(const RJP_value* value);
@@ -168,6 +175,9 @@ const RJP_string* rjp_member_key(const RJP_value* member);
//Search for an object member with given key
RJP_value* rjp_search_member(const RJP_value* object, const char* search);
RJP_value* rjp_object_to_ordered(RJP_value* object);
RJP_value* rjp_object_to_unordered(RJP_value* object);
/***************** OBJECT ITERATOR OPERATIONS *******************/
//Access first member of a json object
void rjp_init_object_iterator(RJP_object_iterator* iter, const RJP_value* object);

View File

@@ -49,6 +49,7 @@ RJP_value irjp_string(char* c, RJP_index len);
RJP_value irjp_string_copy(const char* c);
RJP_value irjp_null(void);
RJP_value irjp_object(void);
RJP_value irjp_ordered_object(void);
RJP_value irjp_array(void);

View File

@@ -19,15 +19,10 @@
#ifndef RJP_OBJECT_H
#define RJP_OBJECT_H
#include "rjp_unordered_object.h"
#include "rjp_ordered_object.h"
#include "rjp_internal.h"
struct RJP_tree_node;
typedef struct RJP_object{
struct RJP_tree_node* root;
RJP_index num_members;
}RJP_object;
void irjp_copy_object(RJP_value* dest, const RJP_value* src);
void irjp_delete_object(RJP_value* obj);

View File

@@ -0,0 +1,50 @@
/**
rjp
Copyright (C) 2018-2020 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RJP_ORDERED_OBJECT_H
#define RJP_ORDERED_OBJECT_H
#include "rjp_internal.h"
struct RJP_ordered_member;
typedef struct RJP_ordered_object{
struct RJP_ordered_member* members;
struct RJP_ordered_member* last;
RJP_index num_members;
}RJP_ordered_object;
void irjp_copy_ordered_object(RJP_value* dest, const RJP_value* src);
void irjp_delete_ordered_object(RJP_value* obj);
void irjp_copy_ordered_object(RJP_value* dest, const RJP_value* src);
void irjp_delete_ordered_object(RJP_value* obj);
RJP_value* irjp_add_ordered_member(RJP_value* dest, char* key, RJP_index keylen);
RJP_value* irjp_remove_ordered_member(RJP_value* obj, RJP_value* member);
void irjp_ordered_set_key(RJP_value* dest, char* key, RJP_index keylen);
RJP_index irjp_ordered_num_members(const RJP_value* object);
RJP_value* irjp_ordered_search_member(const RJP_value* object, const char* search);
void irjp_init_ordered_object_iterator(RJP_object_iterator* it, const RJP_value* object);
void irjp_delete_ordered_object_iterator(RJP_object_iterator* it);
RJP_value* irjp_ordered_object_iterator_current(const RJP_object_iterator* it);
RJP_value* irjp_ordered_object_iterator_next(RJP_object_iterator* it);
RJP_value* irjp_ordered_object_iterator_peek(const RJP_object_iterator* it);
RJP_index irjp_dump_ordered_object(const RJP_value* root, char* dest);
#endif

View File

@@ -0,0 +1,48 @@
/**
rjp
Copyright (C) 2018-2020 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef RJP_UNORDERED_OBJECT_H
#define RJP_UNORDERED_OBJECT_H
#include "rjp_internal.h"
struct RJP_tree_node;
struct RJP_object_member;
typedef struct RJP_unordered_object{
struct RJP_tree_node* root;
RJP_index num_members;
}RJP_unordered_object;
void irjp_copy_unordered_object(RJP_value* dest, const RJP_value* src);
void irjp_delete_unordered_object(RJP_value* obj);
RJP_value* irjp_add_unordered_member(RJP_value* dest, char* key, RJP_index keylen);
RJP_value* irjp_remove_unordered_member(RJP_value* obj, RJP_value* member);
void irjp_unordered_set_key(RJP_value* dest, char* key, RJP_index keylen);
RJP_index irjp_unordered_num_members(const RJP_value* object);
RJP_value* irjp_unordered_search_member(const RJP_value* object, const char* search);
void irjp_init_unordered_object_iterator(RJP_object_iterator* it, const RJP_value* object);
void irjp_delete_unordered_object_iterator(RJP_object_iterator* it);
RJP_value* irjp_unordered_object_iterator_current(const RJP_object_iterator* it);
RJP_value* irjp_unordered_object_iterator_next(RJP_object_iterator* it);
RJP_value* irjp_unordered_object_iterator_peek(const RJP_object_iterator* it);
RJP_index irjp_dump_unordered_object(const RJP_value* root, char* dest);
#endif

View File

@@ -31,9 +31,10 @@ typedef struct RJP_value{
RJP_int integer;
RJP_float dfloat;
RJP_bool boolean;
struct RJP_object object;
struct RJP_string string;
struct RJP_array array;
RJP_ordered_object orobject;
RJP_unordered_object object;
RJP_string string;
RJP_array array;
};
struct RJP_value* parent; //pointer to parent (either an array or object or NULL)
enum RJP_data_type type; //flag to determine active member of union

View File

@@ -75,6 +75,11 @@ RJP_value* rjp_new_object(void){
ret->type = rjp_json_object;
return ret;
}
RJP_value* rjp_new_ordered_object(void){
RJP_value* ret = rjp_calloc(1, sizeof(RJP_value));
ret->type = rjp_json_ordered_object;
return ret;
}
RJP_value* rjp_new_array(void){
RJP_value* ret = rjp_calloc(1, sizeof(RJP_value));
ret->type = rjp_json_array;
@@ -126,15 +131,23 @@ RJP_value* rjp_set_object(RJP_value* v){
if(v->type == rjp_json_object)
return v;
irjp_delete_value(v);
memset(&v->object, 0, sizeof(RJP_object));
memset(&v->object, 0, sizeof(RJP_unordered_object));
v->type = rjp_json_object;
return v;
}
RJP_value* rjp_set_ordered_object(RJP_value* v){
if(v->type == rjp_json_ordered_object)
return v;
irjp_delete_value(v);
memset(&v->orobject, 0, sizeof(RJP_ordered_object));
v->type = rjp_json_ordered_object;
return v;
}
RJP_value* rjp_set_array(RJP_value* v){
if(v->type == rjp_json_array)
return v;
irjp_delete_value(v);
memset(&v->object, 0, sizeof(RJP_array));
memset(&v->array, 0, sizeof(RJP_array));
v->type = rjp_json_array;
return v;
}
@@ -161,6 +174,7 @@ static RJP_index irjp_write_value(char* dest, const RJP_value* val){
ret = rjp_dump_array(val, dest);
break;
case rjp_json_object:
case rjp_json_ordered_object:
ret = rjp_dump_object(val, dest);
break;
default:
@@ -173,9 +187,17 @@ static RJP_index irjp_write_value_pretty(char* dest, const RJP_value* val, int d
static RJP_index irjp_dump_array_pretty(const RJP_value* arr, char* dest, int depth){
RJP_array_iterator it;
rjp_init_array_iterator(&it, arr);
RJP_index pos = 2;
sprintf(dest, "[\n");
for(RJP_value* current = rjp_array_iterator_current(&it);current;current = rjp_array_iterator_next(&it)){
RJP_index pos = 0;
RJP_value* current = rjp_array_iterator_current(&it);
if(!current){
pos += sprintf(dest, "[]");
rjp_delete_array_iterator(&it);
return pos;
}
pos += sprintf(dest+pos, "[\n");
for(;current;current = rjp_array_iterator_next(&it)){
for(int i = 0;i < (depth+1);++i)
pos += sprintf(dest+pos, "\t");
pos += irjp_write_value_pretty(dest+pos, current, depth+1);
@@ -187,15 +209,23 @@ static RJP_index irjp_dump_array_pretty(const RJP_value* arr, char* dest, int de
for(int i = 0;i < depth;++i)
pos += sprintf(dest+pos, "\t");
pos += sprintf(dest+pos, "]");
rjp_delete_array_iterator(&it);
return pos;
}
static RJP_index irjp_dump_object_pretty(const RJP_value* root, char* dest, int depth){
RJP_object_iterator it;
rjp_init_object_iterator(&it, root);
RJP_index pos = 2;
sprintf(dest, "{\n");
RJP_index pos = 0;
RJP_value* current = rjp_object_iterator_current(&it);
if(!current){
pos += sprintf(dest+pos, "{}");
rjp_delete_object_iterator(&it);
return pos;
}
pos += sprintf(dest, "{\n");
for(RJP_value* current = rjp_object_iterator_current(&it);current;current = rjp_object_iterator_next(&it)){
for(;current;current = rjp_object_iterator_next(&it)){
for(int i = 0;i < (depth+1);++i)
pos += sprintf(dest+pos, "\t");
pos += sprintf(dest+pos, "\"%s\": ", rjp_member_key(current)->value);
@@ -208,6 +238,7 @@ static RJP_index irjp_dump_object_pretty(const RJP_value* root, char* dest, int
for(int i = 0;i < depth;++i)
pos += sprintf(dest+pos, "\t");
pos += sprintf(dest+pos, "}");
rjp_delete_object_iterator(&it);
return pos;
}
@@ -233,6 +264,7 @@ static RJP_index irjp_write_value_pretty(char* dest, const RJP_value* val, int d
ret = irjp_dump_array_pretty(val, dest, depth);
break;
case rjp_json_object:
case rjp_json_ordered_object:
ret = irjp_dump_object_pretty(val, dest, depth);
break;
default:
@@ -256,6 +288,7 @@ RJP_index rjp_dump_array(const RJP_value* arr, char* dest){
break;
}
pos += sprintf(dest+pos, "]");
rjp_delete_array_iterator(&it);
return pos;
}

View File

@@ -50,6 +50,9 @@ RJP_value* rjp_copy_value(RJP_value* dest, const RJP_value* src){
case rjp_json_object:
irjp_copy_object(ret, src);
break;
case rjp_json_ordered_object:
irjp_copy_ordered_object(ret, src);
break;
case rjp_json_array:
irjp_copy_array(ret, src);
break;
@@ -82,30 +85,24 @@ static void irjp_delete_array(RJP_value* root){
for(RJP_value* current = next;current;current = next){
next = rjp_array_iterator_next(&it);
switch(current->type){
case rjp_json_object:
irjp_delete_object(current);
break;
case rjp_json_array:
irjp_delete_array(current);
break;
case rjp_json_string:
free(current->string.value);
break;
default:
break;
};
free(current);
rjp_free_value(current);
}
}
void irjp_delete_value(RJP_value* root){
if((root->type) == rjp_json_object)
switch(root->type){
case rjp_json_object:
case rjp_json_ordered_object:
irjp_delete_object(root);
else if((root->type) == rjp_json_array)
break;
case rjp_json_array:
irjp_delete_array(root);
else if((root->type) == rjp_json_string)
break;
case rjp_json_string:
rjp_free(root->string.value);
break;
default: break;
};
}
void rjp_free_value(RJP_value* root){
if(!root)
@@ -163,6 +160,9 @@ RJP_value irjp_null(void){
RJP_value irjp_object(void){
return (RJP_value){.object = {0}, .type = rjp_json_object};
}
RJP_value irjp_ordered_object(void){
return (RJP_value){.object = {0}, .type = rjp_json_ordered_object};
}
RJP_value irjp_array(void){
return (RJP_value){.array = {0}, .type = rjp_json_array};
}

View File

@@ -46,9 +46,9 @@ RJP_value* rjp_add_element(RJP_value* dest){
return &dest->array.last->value;
}
RJP_value* rjp_remove_element(RJP_value* dest, RJP_value* value){
RJP_array* j = &dest->array;
if(!j->num_elements)
if(value->parent != dest)
return NULL;
RJP_array* j = &dest->array;
--j->num_elements;
RJP_array_element* elem = (RJP_array_element*)value;

View File

@@ -19,125 +19,40 @@
#include "rjp_internal.h"
#include "tree.h"
#include "rjp_object.h"
#include "rjp_object_member.h"
#include <string.h> //strlen, strncpy
#define RJP_TREE_ITERATOR_STACK_START_SIZE 32
typedef struct RJP_tree_stack{
RJP_tree_node** data;
int size;
int pos;
}RJP_tree_stack;
typedef struct RJP_object_iterator_impl{
RJP_tree_stack stack;
}RJP_object_iterator_impl;
static int irjp_init_tree_stack(RJP_tree_stack* stack);
static void irjp_delete_tree_stack(RJP_tree_stack* stack);
static void irjp_resize_tree_stack(RJP_tree_stack* stack);
static void irjp_push_tree_stack(RJP_tree_stack* stack, RJP_tree_node* value);
static RJP_tree_node* irjp_pop_tree_stack(RJP_tree_stack* stack);
static RJP_tree_node* irjp_peek_tree_stack(RJP_tree_stack* stack);
static int irjp_init_object_iterator(RJP_object_iterator_impl* it, const RJP_tree_node* root);
static void irjp_delete_object_iterator(RJP_object_iterator_impl* it);
static RJP_tree_node* irjp_object_iterator_next(RJP_object_iterator_impl* it);
static RJP_tree_node* irjp_object_iterator_peek(RJP_object_iterator_impl* it);
static RJP_tree_node* irjp_object_iterator_current(RJP_object_iterator_impl* it);
/* TREE STACK */
//Stack construction / destruction
static int irjp_init_tree_stack(RJP_tree_stack* stack){
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;
}
static void irjp_delete_tree_stack(RJP_tree_stack* stack){
rjp_free(stack->data);
}
static void irjp_resize_tree_stack(RJP_tree_stack* stack){
int newsize = stack->size*2;
RJP_tree_node** newdata = rjp_alloc(sizeof(RJP_tree_node*)*newsize);
for(int i = 0;i < stack->size;++i){
newdata[i] = stack->data[i];
}
rjp_free(stack->data);
stack->data = newdata;
stack->size = newsize;
}
//Stack operations
static void irjp_push_tree_stack(RJP_tree_stack* stack, RJP_tree_node* value){
stack->data[stack->pos++] = value;
if(stack->pos == stack->size)
irjp_resize_tree_stack(stack);
}
static RJP_tree_node* irjp_pop_tree_stack(RJP_tree_stack* stack){
return stack->data[--stack->pos];
}
static RJP_tree_node* irjp_peek_tree_stack(RJP_tree_stack* stack){
return (stack->pos > 0) ? (stack->data[stack->pos-1]) : NULL;
}
static RJP_tree_node* irjp_double_peek_tree_stack(RJP_tree_stack* stack){
return (stack->pos > 1) ? (stack->data[stack->pos-2]) : NULL;
}
/* TREE ITERATOR */
//Iterator construction / destruction
static int irjp_init_object_iterator(RJP_object_iterator_impl* it, const RJP_tree_node* root){
irjp_init_tree_stack(&it->stack);
RJP_tree_node* current = (RJP_tree_node*)root;
while(current){
irjp_push_tree_stack(&it->stack, current);
current = current->left;
}
return 0;
}
static void irjp_delete_object_iterator(RJP_object_iterator_impl* it){
irjp_delete_tree_stack(&it->stack);
}
//Iterator operations
static RJP_tree_node* irjp_object_iterator_next(RJP_object_iterator_impl* it){
RJP_tree_node* last = irjp_pop_tree_stack(&it->stack);
if(last->right){
irjp_push_tree_stack(&it->stack, last->right);
}
return irjp_object_iterator_current(it);
}
static RJP_tree_node* irjp_object_iterator_peek(RJP_object_iterator_impl* it){
RJP_tree_node* n = irjp_peek_tree_stack(&it->stack)->right;
if(n)
return n;
return irjp_double_peek_tree_stack(&it->stack);
}
static RJP_tree_node* irjp_object_iterator_current(RJP_object_iterator_impl* it){
return irjp_peek_tree_stack(&it->stack);
}
/* RJP_OBJECT */
void irjp_copy_object(RJP_value* dest, const RJP_value* src){
irjp_free_tree(dest->object.root);
dest->object.root = irjp_copy_tree(src->object.root);
switch(src->type){
case rjp_json_object:
irjp_copy_unordered_object(dest, src);
break;
case rjp_json_ordered_object:
irjp_copy_ordered_object(dest, src);
break;
default: break;
};
}
void irjp_delete_object(RJP_value* obj){
irjp_free_tree(obj->object.root);
}
static RJP_value* irjp_add_member_impl(RJP_value* dest, char* key, RJP_index keylen){
++dest->object.num_members;
int status;
RJP_value* retval;
dest->object.root = irjp_tree_insert_value(dest->object.root, key, keylen, &retval, &status);
retval->parent = dest;
return retval;
switch(obj->type){
case rjp_json_object:
irjp_delete_unordered_object(obj);
break;
case rjp_json_ordered_object:
irjp_delete_ordered_object(obj);
break;
default: break;
};
}
RJP_value* rjp_add_member(RJP_value* dest, char* key, RJP_index keylen){
if(!keylen)
keylen = strlen(key);
return irjp_add_member_impl(dest, key, keylen);
switch(dest->type){
case rjp_json_object:
return irjp_add_unordered_member(dest, key, keylen);
case rjp_json_ordered_object:
return irjp_add_ordered_member(dest, key, keylen);
default: break;
};
return NULL;
}
RJP_value* rjp_add_member_key_copy(RJP_value* dest, const char* key, RJP_index keylen){
if(!keylen)
@@ -145,7 +60,7 @@ RJP_value* rjp_add_member_key_copy(RJP_value* dest, const char* key, RJP_index k
char* newkey = rjp_alloc(keylen+1);
rjp_escape_strcpy(newkey, key);
newkey[keylen] = 0;
return irjp_add_member_impl(dest, newkey, keylen);
return rjp_add_member(dest, newkey, keylen);
}
RJP_value* rjp_remove_member_by_key(RJP_value* obj, const char* key){
RJP_value* member = rjp_search_member(obj, key);
@@ -154,10 +69,16 @@ RJP_value* rjp_remove_member_by_key(RJP_value* obj, const char* key){
return rjp_remove_member(obj, member);
}
RJP_value* rjp_remove_member(RJP_value* obj, RJP_value* member){
RJP_tree_node* removed_node = NULL;
obj->object.root = irjp_tree_remove_value(obj->object.root, (RJP_tree_node*)member, &removed_node);
rjp_free(((RJP_object_member*)removed_node)->name.value);
return member;
if(member->parent != obj)
return NULL;
switch(obj->type){
case rjp_json_object:
return irjp_remove_unordered_member(obj, member);
case rjp_json_ordered_object:
return irjp_remove_ordered_member(obj, member);
default: break;
};
return NULL;
}
void rjp_free_member_by_key(RJP_value* obj, const char* key){
RJP_value* removed = rjp_remove_member_by_key(obj, key);
@@ -188,55 +109,145 @@ void rjp_set_key(RJP_value* dest, char* key, RJP_index keylen){
}else{
keylen = 0;
}
RJP_value* parent = dest->parent;
RJP_tree_node* removed_node = NULL;
parent->object.root = irjp_tree_remove_value(parent->object.root, (RJP_tree_node*)dest, &removed_node);
rjp_free(((RJP_object_member*)removed_node)->name.value);
((RJP_object_member*)removed_node)->name.value = key;
((RJP_object_member*)removed_node)->name.length = keylen;
parent->object.root = irjp_tree_insert_node(parent->object.root, removed_node);
switch(dest->parent->type){
case rjp_json_object:
irjp_unordered_set_key(dest, key, keylen);
break;
case rjp_json_ordered_object:
irjp_ordered_set_key(dest, key, keylen);
break;
default: break;
};
}
RJP_index rjp_num_members(const RJP_value* object){
return object->object.num_members;
switch(object->type){
case rjp_json_object:
return irjp_unordered_num_members(object);
case rjp_json_ordered_object:
return irjp_ordered_num_members(object);
default: break;
};
return 0;
}
const RJP_string* rjp_member_key(const RJP_value* member){
return &(((RJP_object_member*)member)->name);
}
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;
switch(object->type){
case rjp_json_object:
return irjp_unordered_search_member(object, search);
case rjp_json_ordered_object:
return irjp_ordered_search_member(object, search);
default: break;
};
return NULL;
}
void rjp_init_object_iterator(RJP_object_iterator* it, const RJP_value* object){
it->it = rjp_alloc(sizeof(RJP_object_iterator_impl));
irjp_init_object_iterator(it->it, object->object.root);
switch(object->type){
case rjp_json_object:
irjp_init_unordered_object_iterator(it, object);
it->type = rjp_json_object;
break;
case rjp_json_ordered_object:
irjp_init_ordered_object_iterator(it, object);
it->type = rjp_json_ordered_object;
break;
default: break;
};
}
void rjp_delete_object_iterator(RJP_object_iterator* it){
irjp_delete_object_iterator(it->it);
rjp_free(it->it);
it->it = NULL;
switch(it->type){
case rjp_json_object:
irjp_delete_unordered_object_iterator(it);
break;
case rjp_json_ordered_object:
irjp_delete_ordered_object_iterator(it);
break;
default: break;
};
}
RJP_value* rjp_object_iterator_current(const RJP_object_iterator* it){
RJP_tree_node* n = irjp_object_iterator_current(it->it);
if(!n)
return NULL;
return &n->data.value;
switch(it->type){
case rjp_json_object:
return irjp_unordered_object_iterator_current(it);
break;
case rjp_json_ordered_object:
return irjp_ordered_object_iterator_current(it);
break;
default: break;
};
return NULL;
}
RJP_value* rjp_object_iterator_next(RJP_object_iterator* it){
RJP_tree_node* n = irjp_object_iterator_next(it->it);
if(!n)
return NULL;
return &n->data.value;
switch(it->type){
case rjp_json_object:
return irjp_unordered_object_iterator_next(it);
break;
case rjp_json_ordered_object:
return irjp_ordered_object_iterator_next(it);
break;
default: break;
};
return NULL;
}
RJP_value* rjp_object_iterator_peek(const RJP_object_iterator* it){
RJP_tree_node* n = irjp_object_iterator_peek(it->it);
if(!n)
return NULL;
return &n->data.value;
switch(it->type){
case rjp_json_object:
return irjp_unordered_object_iterator_peek(it);
break;
case rjp_json_ordered_object:
return irjp_ordered_object_iterator_peek(it);
break;
default: break;
};
return NULL;
}
RJP_value* rjp_object_to_ordered(RJP_value* object){
if(object->type == rjp_json_ordered_object)
return object;
RJP_value newobj = {0};
newobj.type = rjp_json_ordered_object;
RJP_object_iterator it;
irjp_init_unordered_object_iterator(&it, object);
RJP_value* next = irjp_unordered_object_iterator_current(&it);
for(RJP_value* current = next;current;current = next){
RJP_value* newcur = irjp_add_ordered_member(&newobj, rjp_member_key(current)->value, rjp_member_key(current)->length);
((RJP_object_member*)current)->name.value = NULL;
rjp_move_value(newcur, current);
next = irjp_unordered_object_iterator_next(&it);
rjp_free(current);
}
irjp_delete_unordered_object_iterator(&it);
object->type = rjp_json_ordered_object;
object->orobject = newobj.orobject;
return object;
}
RJP_value* rjp_object_to_unordered(RJP_value* object){
if(object->type == rjp_json_object)
return object;
RJP_value newobj = {0};
newobj.type = rjp_json_object;
RJP_object_iterator it;
irjp_init_ordered_object_iterator(&it, object);
RJP_value* next = irjp_ordered_object_iterator_current(&it);
for(RJP_value* current = next;current;current = next){
RJP_value* newcur = irjp_add_unordered_member(&newobj, rjp_member_key(current)->value, rjp_member_key(current)->length);
((RJP_object_member*)current)->name.value = NULL;
rjp_move_value(newcur, current);
next = irjp_ordered_object_iterator_next(&it);
rjp_free(current);
}
irjp_delete_ordered_object_iterator(&it);
object->type = rjp_json_object;
object->object = newobj.object;
return object;
}

144
src/rjp_ordered_object.c Normal file
View File

@@ -0,0 +1,144 @@
/**
rjp
Copyright (C) 2018-2020 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "rjp_internal.h"
#include "rjp_ordered_object.h"
#include "rjp_object_member.h"
#include "rjp_value.h"
#include "rjp_string.h"
#include <string.h> //strcmp
typedef struct RJP_ordered_member{
RJP_object_member member;
struct RJP_ordered_member* prev;
struct RJP_ordered_member* next;
}RJP_ordered_member;
static void irjp_copy_ordered_member(RJP_ordered_member* dest, const RJP_ordered_member* src){
irjp_strcpy(&dest->member.name, &src->member.name);
rjp_copy_value(&dest->member.value, &src->member.value);
}
void irjp_copy_ordered_object(RJP_value* dest, const RJP_value* src){
irjp_delete_ordered_object(dest);
dest->orobject.num_members = 0;
RJP_object_iterator it;
irjp_init_ordered_object_iterator(&it, src);
for(const RJP_value* current = irjp_ordered_object_iterator_current(&it);current;current = irjp_ordered_object_iterator_next(&it)){
RJP_string keycopy;
irjp_strcpy(&keycopy, &((RJP_object_member*)current)->name);
RJP_ordered_member* newmemb = (RJP_ordered_member*)irjp_add_ordered_member(dest, keycopy.value, keycopy.length);
irjp_copy_ordered_member(newmemb, (RJP_ordered_member*)current);
}
irjp_delete_ordered_object_iterator(&it);
}
void irjp_delete_ordered_object(RJP_value* obj){
RJP_object_iterator it;
irjp_init_ordered_object_iterator(&it, obj);
RJP_value* next = irjp_ordered_object_iterator_current(&it);
for(RJP_value* current = next;current;current = next){
next = irjp_ordered_object_iterator_next(&it);
rjp_free(((RJP_object_member*)current)->name.value);
rjp_free_value(current);
}
irjp_delete_ordered_object_iterator(&it);
}
static RJP_ordered_member* irjp_append_ordered_member(RJP_ordered_object* dest, RJP_ordered_member* newmemb){
++dest->num_members;
if(!dest->members){
dest->members = dest->last = newmemb;
newmemb->next = newmemb->prev = NULL;
return dest->members;
}
dest->last->next = newmemb;
newmemb->prev = dest->last;
newmemb->next = NULL;
dest->last = newmemb;
return newmemb;
}
RJP_value* irjp_add_ordered_member(RJP_value* dest, char* key, RJP_index keylen){
RJP_ordered_member* newmemb = rjp_calloc(1, sizeof(RJP_ordered_member));
irjp_append_ordered_member((RJP_ordered_object*)dest, newmemb);
irjp_ordered_set_key((RJP_value*)newmemb, key, keylen);
((RJP_value*)newmemb)->parent = dest;
((RJP_value*)newmemb)->type = rjp_json_null;
return (RJP_value*)newmemb;
}
RJP_value* irjp_remove_ordered_member(RJP_value* obj, RJP_value* member){
RJP_ordered_member* current = (RJP_ordered_member*)member;
RJP_ordered_member* prev = current->prev;
RJP_ordered_member* next = current->next;
--obj->orobject.num_members;
if(prev)
prev->next = next;
else
obj->orobject.members = next;
if(next)
next->prev = prev;
else
obj->orobject.last = prev;
member->parent = NULL;
return member;
}
void irjp_ordered_set_key(RJP_value* dest, char* key, RJP_index keylen){
RJP_object_member* mem = (RJP_object_member*)dest;
rjp_free(mem->name.value);
mem->name.value = key;
mem->name.length = keylen;
}
RJP_index irjp_ordered_num_members(const RJP_value* object){
return object->orobject.num_members;
}
RJP_value* irjp_ordered_search_member(const RJP_value* object, const char* search){
RJP_value* retval = NULL;
RJP_object_iterator it;
irjp_init_ordered_object_iterator(&it, object);
for(RJP_value* current = irjp_ordered_object_iterator_current(&it);current;current = irjp_ordered_object_iterator_next(&it)){
if(!strcmp(((RJP_object_member*)current)->name.value, search)){
retval = current;
break;
}
}
irjp_delete_ordered_object_iterator(&it);
return retval;
}
void irjp_init_ordered_object_iterator(RJP_object_iterator* it, const RJP_value* object){
it->current = &(object->orobject.members->member.value);
it->type = rjp_json_ordered_object;
}
void irjp_delete_ordered_object_iterator(RJP_object_iterator* it){
it->current = NULL;
}
RJP_value* irjp_ordered_object_iterator_current(const RJP_object_iterator* it){
return it->current;
}
RJP_value* irjp_ordered_object_iterator_next(RJP_object_iterator* it){
RJP_ordered_member* curr = (RJP_ordered_member*)it->current;
it->current = curr ? &(curr->next->member.value) : NULL;
return it->current;
}
RJP_value* irjp_ordered_object_iterator_peek(const RJP_object_iterator* it){
RJP_ordered_member* curr = (RJP_ordered_member*)it->current;
return curr ? &(curr->next->member.value) : NULL;
}

View File

@@ -385,6 +385,7 @@ RJP_index irjp_value_strlen(const RJP_value* root){
case rjp_json_array:
return irjp_array_strlen(root);
case rjp_json_object:
case rjp_json_ordered_object:
return irjp_object_strlen(root);
default:
return 0;
@@ -405,6 +406,7 @@ RJP_index irjp_value_strlen_pretty(const RJP_value* root, int depth){
case rjp_json_array:
return irjp_array_strlen_pretty(root, depth);
case rjp_json_object:
case rjp_json_ordered_object:
return irjp_object_strlen_pretty(root, depth);
default:
return 0;

177
src/rjp_unordered_object.c Normal file
View File

@@ -0,0 +1,177 @@
/**
rjp
Copyright (C) 2018-2020 rexy712
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "rjp_internal.h"
#include "rjp_unordered_object.h"
#include "rjp_value.h"
#include "rjp_string.h"
#include "tree.h"
#include <string.h> //strlen
#define RJP_TREE_ITERATOR_STACK_START_SIZE 32
typedef struct RJP_tree_stack{
RJP_tree_node** data;
int size;
int pos;
}RJP_tree_stack;
typedef struct RJP_object_iterator_impl{
RJP_tree_stack stack;
}RJP_object_iterator_impl;
static int irjp_init_tree_stack(RJP_tree_stack* stack);
static void irjp_delete_tree_stack(RJP_tree_stack* stack);
static void irjp_resize_tree_stack(RJP_tree_stack* stack);
static void irjp_push_tree_stack(RJP_tree_stack* stack, RJP_tree_node* value);
static RJP_tree_node* irjp_pop_tree_stack(RJP_tree_stack* stack);
static RJP_tree_node* irjp_peek_tree_stack(RJP_tree_stack* stack);
/* TREE STACK */
//Stack construction / destruction
static int irjp_init_tree_stack(RJP_tree_stack* stack){
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;
}
static void irjp_delete_tree_stack(RJP_tree_stack* stack){
rjp_free(stack->data);
}
static void irjp_resize_tree_stack(RJP_tree_stack* stack){
int newsize = stack->size*2;
RJP_tree_node** newdata = rjp_alloc(sizeof(RJP_tree_node*)*newsize);
for(int i = 0;i < stack->size;++i){
newdata[i] = stack->data[i];
}
rjp_free(stack->data);
stack->data = newdata;
stack->size = newsize;
}
//Stack operations
static void irjp_push_tree_stack(RJP_tree_stack* stack, RJP_tree_node* value){
stack->data[stack->pos++] = value;
if(stack->pos == stack->size)
irjp_resize_tree_stack(stack);
}
static RJP_tree_node* irjp_pop_tree_stack(RJP_tree_stack* stack){
return stack->data[--stack->pos];
}
static RJP_tree_node* irjp_peek_tree_stack(RJP_tree_stack* stack){
return (stack->pos > 0) ? (stack->data[stack->pos-1]) : NULL;
}
static RJP_tree_node* irjp_double_peek_tree_stack(RJP_tree_stack* stack){
return (stack->pos > 1) ? (stack->data[stack->pos-2]) : NULL;
}
/* RJP_OBJECT */
void irjp_copy_unordered_object(RJP_value* dest, const RJP_value* src){
dest->object.root = irjp_copy_tree(src->object.root);
}
void irjp_delete_unordered_object(RJP_value* obj){
irjp_free_tree(obj->object.root);
}
RJP_value* irjp_add_unordered_member(RJP_value* dest, char* key, RJP_index keylen){
if(!keylen)
keylen = strlen(key);
++dest->object.num_members;
int status;
RJP_value* retval;
dest->object.root = irjp_tree_insert_value(dest->object.root, key, keylen, &retval, &status);
retval->parent = dest;
retval->type = rjp_json_null;
return retval;
}
RJP_value* irjp_remove_unordered_member(RJP_value* obj, RJP_value* member){
RJP_tree_node* removed_node = NULL;
obj->object.root = irjp_tree_remove_value(obj->object.root, (RJP_tree_node*)member, &removed_node);
rjp_free(((RJP_object_member*)removed_node)->name.value);
member->parent = NULL;
--obj->object.num_members;
return member;
}
void irjp_unordered_set_key(RJP_value* dest, char* key, RJP_index keylen){
RJP_value* parent = dest->parent;
RJP_tree_node* removed_node = NULL;
parent->object.root = irjp_tree_remove_value(parent->object.root, (RJP_tree_node*)dest, &removed_node);
rjp_free(((RJP_object_member*)removed_node)->name.value);
((RJP_object_member*)removed_node)->name.value = key;
((RJP_object_member*)removed_node)->name.length = keylen;
parent->object.root = irjp_tree_insert_node(parent->object.root, removed_node);
}
RJP_index irjp_unordered_num_members(const RJP_value* object){
return object->object.num_members;
}
RJP_value* irjp_unordered_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;
}
void irjp_init_unordered_object_iterator(RJP_object_iterator* it, const RJP_value* object){
it->it = rjp_alloc(sizeof(RJP_object_iterator_impl));
RJP_object_iterator_impl* itimpl = it->it;
RJP_tree_node* root = object->object.root;
irjp_init_tree_stack(&itimpl->stack);
RJP_tree_node* current = (RJP_tree_node*)root;
while(current){
irjp_push_tree_stack(&itimpl->stack, current);
current = current->left;
}
}
void irjp_delete_unordered_object_iterator(RJP_object_iterator* it){
irjp_delete_tree_stack(&it->it->stack);
rjp_free(it->it);
it->it = NULL;
}
RJP_value* irjp_unordered_object_iterator_current(const RJP_object_iterator* it){
RJP_tree_node* n = irjp_peek_tree_stack(&it->it->stack);
if(!n)
return NULL;
return &n->data.value;
}
RJP_value* irjp_unordered_object_iterator_next(RJP_object_iterator* it){
RJP_object_iterator_impl* itimp = it->it;
RJP_tree_node* last = irjp_pop_tree_stack(&itimp->stack);
if(last->right){
irjp_push_tree_stack(&itimp->stack, last->right);
last = last->right;
while(last->left){
irjp_push_tree_stack(&itimp->stack, last->left);
last = last->left;
}
}
return irjp_unordered_object_iterator_current(it);
}
RJP_value* irjp_unordered_object_iterator_peek(const RJP_object_iterator* it){
RJP_object_iterator_impl* itimp = it->it;
RJP_tree_node* n = irjp_peek_tree_stack(&itimp->stack)->right;
if(n)
return &n->data.value;
n = irjp_double_peek_tree_stack(&itimp->stack);
if(!n)
return NULL;
return &n->data.value;
}