From 994ad317aeddf31909ef9b59fa3bf8bb870edbe1 Mon Sep 17 00:00:00 2001 From: Xie Han <63350856@qq.com> Date: Sun, 27 Apr 2025 18:11:46 +0800 Subject: [PATCH] Do not sort object for better parsing speed. --- .editorconfig | 3 - Makefile | 6 +- README.md | 2 +- json_parser.c | 50 +------ rbtree.c | 387 -------------------------------------------------- rbtree.h | 150 ------------------- xmake.lua | 4 +- 7 files changed, 13 insertions(+), 589 deletions(-) delete mode 100644 rbtree.c delete mode 100644 rbtree.h diff --git a/.editorconfig b/.editorconfig index 3eb5966..96b19b5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -8,6 +8,3 @@ indent_size = 4 [list.h] indent_style = tab indent_size = 8 -[rbtree.*] -indent_style = tab -indent_size = 8 diff --git a/Makefile b/Makefile index 665d195..244e24f 100644 --- a/Makefile +++ b/Makefile @@ -9,12 +9,12 @@ LD = gcc all: test_speed parse_json -json_parser.o: json_parser.c json_parser.h list.h rbtree.h +json_parser.o: json_parser.c json_parser.h list.h -test_speed: json_parser.o rbtree.o test_speed.o +test_speed: json_parser.o test_speed.o $(LD) -o test_speed $^ -parse_json: json_parser.o rbtree.o test.o +parse_json: json_parser.o test.o $(LD) -o parse_json $^ clean: diff --git a/README.md b/README.md index 01266b0..b0140fb 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,7 @@ int json_object_size(const json_object_t *obj); /* Find the JSON value under the key @name. Returns NULL if @name can not be found. The time complexity of this function is - O(log(n)), where n is the size of the JSON object. + O(n), where n is the size of the JSON object. @name: The key to find @obj: JSON object Note: The returned pointer to JSON value is const. */ diff --git a/json_parser.c b/json_parser.c index be34a9f..d6a5289 100644 --- a/json_parser.c +++ b/json_parser.c @@ -5,7 +5,6 @@ #include #include #include "list.h" -#include "rbtree.h" #include "json_parser.h" #define JSON_DEPTH_LIMIT 1024 @@ -13,7 +12,6 @@ struct __json_object { struct list_head head; - struct rb_root root; int size; }; @@ -38,7 +36,6 @@ struct __json_value struct __json_member { struct list_head list; - struct rb_node rb; json_value_t value; char name[1]; }; @@ -448,28 +445,6 @@ static int __parse_json_number(const char *cursor, const char **end, return 0; } -static void __insert_json_member(json_member_t *memb, struct list_head *pos, - json_object_t *obj) -{ - struct rb_node **p = &obj->root.rb_node; - struct rb_node *parent = NULL; - json_member_t *entry; - - while (*p) - { - parent = *p; - entry = rb_entry(*p, json_member_t, rb); - if (strcmp(memb->name, entry->name) < 0) - p = &(*p)->rb_left; - else - p = &(*p)->rb_right; - } - - rb_link_node(&memb->rb, parent, p); - rb_insert_color(&memb->rb, &obj->root); - list_add(&memb->list, pos); -} - static int __parse_json_value(const char *cursor, const char **end, int depth, json_value_t *val); @@ -540,7 +515,7 @@ static int __parse_json_members(const char *cursor, const char **end, return ret; } - __insert_json_member(memb, obj->head.prev, obj); + list_add_tail(&memb->list, &obj->head); cnt++; while (isspace(*cursor)) @@ -584,7 +559,6 @@ static int __parse_json_object(const char *cursor, const char **end, return -3; INIT_LIST_HEAD(&obj->head); - obj->root.rb_node = NULL; ret = __parse_json_members(cursor, end, depth + 1, obj); if (ret < 0) { @@ -834,7 +808,6 @@ static void __move_json_value(json_value_t *src, json_value_t *dest) case JSON_VALUE_OBJECT: INIT_LIST_HEAD(&dest->value.object.head); list_splice(&src->value.object.head, &dest->value.object.head); - dest->value.object.root.rb_node = src->value.object.root.rb_node; dest->value.object.size = src->value.object.size; break; @@ -878,7 +851,6 @@ static int __set_json_value(int type, va_list ap, json_value_t *val) case JSON_VALUE_OBJECT: INIT_LIST_HEAD(&val->value.object.head); - val->value.object.root.rb_node = NULL; val->value.object.size = 0; break; @@ -940,7 +912,7 @@ static int __copy_json_members(const json_object_t *src, json_object_t *dest) } memcpy(memb->name, entry->name, len + 1); - __insert_json_member(memb, dest->head.prev, dest); + list_add_tail(&memb->list, &dest->head); } return src->size; @@ -995,7 +967,6 @@ static int __copy_json_value(const json_value_t *src, json_value_t *dest) case JSON_VALUE_OBJECT: INIT_LIST_HEAD(&dest->value.object.head); - dest->value.object.root.rb_node = NULL; ret = __copy_json_members(&src->value.object, &dest->value.object); if (ret < 0) { @@ -1086,19 +1057,13 @@ json_array_t *json_value_array(const json_value_t *val) const json_value_t *json_object_find(const char *name, const json_object_t *obj) { - struct rb_node *p = obj->root.rb_node; + struct list_head *pos; json_member_t *memb; - int n; - while (p) + list_for_each(pos, &obj->head) { - memb = rb_entry(p, json_member_t, rb); - n = strcmp(name, memb->name); - if (n < 0) - p = p->rb_left; - else if (n > 0) - p = p->rb_right; - else + memb = list_entry(pos, json_member_t, list); + if (strcmp(name, memb->name) == 0) return &memb->value; } @@ -1200,7 +1165,7 @@ static const json_value_t *__json_object_insert(const char *name, return NULL; } - __insert_json_member(memb, pos, obj); + list_add(&memb->list, pos); obj->size++; return &memb->value; } @@ -1266,7 +1231,6 @@ json_value_t *json_object_remove(const json_value_t *val, return NULL; list_del(&memb->list); - rb_erase(&memb->rb, &obj->root); obj->size--; __move_json_value(&memb->value, (json_value_t *)val); diff --git a/rbtree.c b/rbtree.c deleted file mode 100644 index 5b6ccb8..0000000 --- a/rbtree.c +++ /dev/null @@ -1,387 +0,0 @@ -/* - Red Black Trees - (C) 1999 Andrea Arcangeli - (C) 2002 David Woodhouse - - 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 2 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - linux/lib/rbtree.c -*/ - -#include "rbtree.h" - -static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) -{ - struct rb_node *right = node->rb_right; - - if ((node->rb_right = right->rb_left)) - right->rb_left->rb_parent = node; - right->rb_left = node; - - if ((right->rb_parent = node->rb_parent)) - { - if (node == node->rb_parent->rb_left) - node->rb_parent->rb_left = right; - else - node->rb_parent->rb_right = right; - } - else - root->rb_node = right; - node->rb_parent = right; -} - -static void __rb_rotate_right(struct rb_node *node, struct rb_root *root) -{ - struct rb_node *left = node->rb_left; - - if ((node->rb_left = left->rb_right)) - left->rb_right->rb_parent = node; - left->rb_right = node; - - if ((left->rb_parent = node->rb_parent)) - { - if (node == node->rb_parent->rb_right) - node->rb_parent->rb_right = left; - else - node->rb_parent->rb_left = left; - } - else - root->rb_node = left; - node->rb_parent = left; -} - -void rb_insert_color(struct rb_node *node, struct rb_root *root) -{ - struct rb_node *parent, *gparent; - - while ((parent = node->rb_parent) && parent->rb_color == RB_RED) - { - gparent = parent->rb_parent; - - if (parent == gparent->rb_left) - { - { - register struct rb_node *uncle = gparent->rb_right; - if (uncle && uncle->rb_color == RB_RED) - { - uncle->rb_color = RB_BLACK; - parent->rb_color = RB_BLACK; - gparent->rb_color = RB_RED; - node = gparent; - continue; - } - } - - if (parent->rb_right == node) - { - register struct rb_node *tmp; - __rb_rotate_left(parent, root); - tmp = parent; - parent = node; - node = tmp; - } - - parent->rb_color = RB_BLACK; - gparent->rb_color = RB_RED; - __rb_rotate_right(gparent, root); - } else { - { - register struct rb_node *uncle = gparent->rb_left; - if (uncle && uncle->rb_color == RB_RED) - { - uncle->rb_color = RB_BLACK; - parent->rb_color = RB_BLACK; - gparent->rb_color = RB_RED; - node = gparent; - continue; - } - } - - if (parent->rb_left == node) - { - register struct rb_node *tmp; - __rb_rotate_right(parent, root); - tmp = parent; - parent = node; - node = tmp; - } - - parent->rb_color = RB_BLACK; - gparent->rb_color = RB_RED; - __rb_rotate_left(gparent, root); - } - } - - root->rb_node->rb_color = RB_BLACK; -} - -static void __rb_erase_color(struct rb_node *node, struct rb_node *parent, - struct rb_root *root) -{ - struct rb_node *other; - - while ((!node || node->rb_color == RB_BLACK) && node != root->rb_node) - { - if (parent->rb_left == node) - { - other = parent->rb_right; - if (other->rb_color == RB_RED) - { - other->rb_color = RB_BLACK; - parent->rb_color = RB_RED; - __rb_rotate_left(parent, root); - other = parent->rb_right; - } - if ((!other->rb_left || - other->rb_left->rb_color == RB_BLACK) - && (!other->rb_right || - other->rb_right->rb_color == RB_BLACK)) - { - other->rb_color = RB_RED; - node = parent; - parent = node->rb_parent; - } - else - { - if (!other->rb_right || - other->rb_right->rb_color == RB_BLACK) - { - register struct rb_node *o_left; - if ((o_left = other->rb_left)) - o_left->rb_color = RB_BLACK; - other->rb_color = RB_RED; - __rb_rotate_right(other, root); - other = parent->rb_right; - } - other->rb_color = parent->rb_color; - parent->rb_color = RB_BLACK; - if (other->rb_right) - other->rb_right->rb_color = RB_BLACK; - __rb_rotate_left(parent, root); - node = root->rb_node; - break; - } - } - else - { - other = parent->rb_left; - if (other->rb_color == RB_RED) - { - other->rb_color = RB_BLACK; - parent->rb_color = RB_RED; - __rb_rotate_right(parent, root); - other = parent->rb_left; - } - if ((!other->rb_left || - other->rb_left->rb_color == RB_BLACK) - && (!other->rb_right || - other->rb_right->rb_color == RB_BLACK)) - { - other->rb_color = RB_RED; - node = parent; - parent = node->rb_parent; - } - else - { - if (!other->rb_left || - other->rb_left->rb_color == RB_BLACK) - { - register struct rb_node *o_right; - if ((o_right = other->rb_right)) - o_right->rb_color = RB_BLACK; - other->rb_color = RB_RED; - __rb_rotate_left(other, root); - other = parent->rb_left; - } - other->rb_color = parent->rb_color; - parent->rb_color = RB_BLACK; - if (other->rb_left) - other->rb_left->rb_color = RB_BLACK; - __rb_rotate_right(parent, root); - node = root->rb_node; - break; - } - } - } - if (node) - node->rb_color = RB_BLACK; -} - -void rb_erase(struct rb_node *node, struct rb_root *root) -{ - struct rb_node *child, *parent; - int color; - - if (!node->rb_left) - child = node->rb_right; - else if (!node->rb_right) - child = node->rb_left; - else - { - struct rb_node *old = node, *left; - - node = node->rb_right; - while ((left = node->rb_left)) - node = left; - child = node->rb_right; - parent = node->rb_parent; - color = node->rb_color; - - if (child) - child->rb_parent = parent; - if (parent) - { - if (parent->rb_left == node) - parent->rb_left = child; - else - parent->rb_right = child; - } - else - root->rb_node = child; - - if (node->rb_parent == old) - parent = node; - node->rb_parent = old->rb_parent; - node->rb_color = old->rb_color; - node->rb_right = old->rb_right; - node->rb_left = old->rb_left; - - if (old->rb_parent) - { - if (old->rb_parent->rb_left == old) - old->rb_parent->rb_left = node; - else - old->rb_parent->rb_right = node; - } else - root->rb_node = node; - - old->rb_left->rb_parent = node; - if (old->rb_right) - old->rb_right->rb_parent = node; - goto color; - } - - parent = node->rb_parent; - color = node->rb_color; - - if (child) - child->rb_parent = parent; - if (parent) - { - if (parent->rb_left == node) - parent->rb_left = child; - else - parent->rb_right = child; - } - else - root->rb_node = child; - - color: - if (color == RB_BLACK) - __rb_erase_color(child, parent, root); -} - -/* - * This function returns the first node (in sort order) of the tree. - */ -struct rb_node *rb_first(struct rb_root *root) -{ - struct rb_node *n; - - n = root->rb_node; - if (!n) - return (struct rb_node *)0; - while (n->rb_left) - n = n->rb_left; - return n; -} - -struct rb_node *rb_last(struct rb_root *root) -{ - struct rb_node *n; - - n = root->rb_node; - if (!n) - return (struct rb_node *)0; - while (n->rb_right) - n = n->rb_right; - return n; -} - -struct rb_node *rb_next(struct rb_node *node) -{ - /* If we have a right-hand child, go down and then left as far - as we can. */ - if (node->rb_right) { - node = node->rb_right; - while (node->rb_left) - node = node->rb_left; - return node; - } - - /* No right-hand children. Everything down and left is - smaller than us, so any 'next' node must be in the general - direction of our parent. Go up the tree; any time the - ancestor is a right-hand child of its parent, keep going - up. First time it's a left-hand child of its parent, said - parent is our 'next' node. */ - while (node->rb_parent && node == node->rb_parent->rb_right) - node = node->rb_parent; - - return node->rb_parent; -} - -struct rb_node *rb_prev(struct rb_node *node) -{ - /* If we have a left-hand child, go down and then right as far - as we can. */ - if (node->rb_left) { - node = node->rb_left; - while (node->rb_right) - node = node->rb_right; - return node; - } - - /* No left-hand children. Go up till we find an ancestor which - is a right-hand child of its parent */ - while (node->rb_parent && node == node->rb_parent->rb_left) - node = node->rb_parent; - - return node->rb_parent; -} - -void rb_replace_node(struct rb_node *victim, struct rb_node *newnode, - struct rb_root *root) -{ - struct rb_node *parent = victim->rb_parent; - - /* Set the surrounding nodes to point to the replacement */ - if (parent) { - if (victim == parent->rb_left) - parent->rb_left = newnode; - else - parent->rb_right = newnode; - } else { - root->rb_node = newnode; - } - if (victim->rb_left) - victim->rb_left->rb_parent = newnode; - if (victim->rb_right) - victim->rb_right->rb_parent = newnode; - - /* Copy the pointers/colour from the victim to the replacement */ - *newnode = *victim; -} - diff --git a/rbtree.h b/rbtree.h deleted file mode 100644 index 6cd7862..0000000 --- a/rbtree.h +++ /dev/null @@ -1,150 +0,0 @@ -/* - Red Black Trees - (C) 1999 Andrea Arcangeli - - 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 2 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, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - - linux/include/linux/rbtree.h - - To use rbtrees you'll have to implement your own insert and search cores. - This will avoid us to use callbacks and to drop drammatically performances. - I know it's not the cleaner way, but in C (not in C++) to get - performances and genericity... - - Some example of insert and search follows here. The search is a plain - normal search over an ordered tree. The insert instead must be implemented - int two steps: as first thing the code must insert the element in - order as a red leaf in the tree, then the support library function - rb_insert_color() must be called. Such function will do the - not trivial work to rebalance the rbtree if necessary. - ------------------------------------------------------------------------ -static inline struct page * rb_search_page_cache(struct inode * inode, - unsigned long offset) -{ - rb_node_t * n = inode->i_rb_page_cache.rb_node; - struct page * page; - - while (n) - { - page = rb_entry(n, struct page, rb_page_cache); - - if (offset < page->offset) - n = n->rb_left; - else if (offset > page->offset) - n = n->rb_right; - else - return page; - } - return NULL; -} - -static inline struct page * __rb_insert_page_cache(struct inode * inode, - unsigned long offset, - rb_node_t * node) -{ - rb_node_t ** p = &inode->i_rb_page_cache.rb_node; - rb_node_t * parent = NULL; - struct page * page; - - while (*p) - { - parent = *p; - page = rb_entry(parent, struct page, rb_page_cache); - - if (offset < page->offset) - p = &(*p)->rb_left; - else if (offset > page->offset) - p = &(*p)->rb_right; - else - return page; - } - - rb_link_node(node, parent, p); - - return NULL; -} - -static inline struct page * rb_insert_page_cache(struct inode * inode, - unsigned long offset, - rb_node_t * node) -{ - struct page * ret; - if ((ret = __rb_insert_page_cache(inode, offset, node))) - goto out; - rb_insert_color(node, &inode->i_rb_page_cache); - out: - return ret; -} ------------------------------------------------------------------------ -*/ - -#ifndef _LINUX_RBTREE_H -#define _LINUX_RBTREE_H - -#pragma pack(1) -struct rb_node -{ - struct rb_node *rb_parent; - struct rb_node *rb_right; - struct rb_node *rb_left; - char rb_color; -#define RB_RED 0 -#define RB_BLACK 1 -}; -#pragma pack() - -struct rb_root -{ - struct rb_node *rb_node; -}; - -#define RB_ROOT (struct rb_root){ (struct rb_node *)0, } -#define rb_entry(ptr, type, member) \ - ((type *)((char *)(ptr)-(size_t)(&((type *)0)->member))) - -#ifdef __cplusplus -extern "C" -{ -#endif - -extern void rb_insert_color(struct rb_node *node, struct rb_root *root); -extern void rb_erase(struct rb_node *node, struct rb_root *root); - -/* Find logical next and previous nodes in a tree */ -extern struct rb_node *rb_next(struct rb_node *); -extern struct rb_node *rb_prev(struct rb_node *); -extern struct rb_node *rb_first(struct rb_root *); -extern struct rb_node *rb_last(struct rb_root *); - -/* Fast replacement of a single node without remove/rebalance/add/rebalance */ -extern void rb_replace_node(struct rb_node *victim, struct rb_node *newnode, - struct rb_root *root); - -#ifdef __cplusplus -} -#endif - -static inline void rb_link_node(struct rb_node *node, struct rb_node *parent, - struct rb_node **link) -{ - node->rb_parent = parent; - node->rb_color = RB_RED; - node->rb_left = node->rb_right = (struct rb_node *)0; - - *link = node; -} - -#endif diff --git a/xmake.lua b/xmake.lua index 4f06a76..f701f60 100644 --- a/xmake.lua +++ b/xmake.lua @@ -1,5 +1,5 @@ set_project("json-parser") -set_version("1.2.4") +set_version("1.3.0") if is_mode("release") then set_optimize("faster") @@ -14,7 +14,7 @@ set_warnings("all") target("json-parser") set_kind("$(kind)") - add_files("rbtree.c", "json_parser.c") + add_files("json_parser.c") target("test_speed") set_kind("binary")