Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e9571115a | ||
|
|
3e1a785938 | ||
|
|
7b54b12e6e | ||
|
|
99cc9a5154 | ||
|
|
ffac4718e8 | ||
|
|
4b68e32298 | ||
|
|
07c07cc06b |
@@ -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
3
TODO
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
50
include/rjp_ordered_object.h
Normal file
50
include/rjp_ordered_object.h
Normal 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
|
||||
48
include/rjp_unordered_object.h
Normal file
48
include/rjp_unordered_object.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
49
src/output.c
49
src/output.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
34
src/rjp.c
34
src/rjp.c
@@ -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};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
305
src/rjp_object.c
305
src/rjp_object.c
@@ -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
144
src/rjp_ordered_object.c
Normal 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;
|
||||
}
|
||||
@@ -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
177
src/rjp_unordered_object.c
Normal 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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user