From 491cf029b29ad819da210df05d14ed7dae4116c1 Mon Sep 17 00:00:00 2001 From: Dave Gamble Date: Fri, 13 Feb 2015 19:53:27 +0000 Subject: [PATCH] Rework cJSON_Utils object compare functions to use an O(N) algorithm on sorted lists. It's a bit of a shame to use the sorts, because cJSON is otherwise incredibly stable (json->cJSON->json is unmodified modulo formatting), but it means we get usable performance, rather than O(N^2) which will make CPUs cry. git-svn-id: svn://svn.code.sf.net/p/cjson/code@71 e3330c51-1366-4df0-8b21-3ccf24e3d50e --- cJSON_Utils.c | 51 ++++++++++++++++++++++++++++++--------------------- test_utils.c | 4 ++-- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/cJSON_Utils.c b/cJSON_Utils.c index 8b5cf64..85913c0 100644 --- a/cJSON_Utils.c +++ b/cJSON_Utils.c @@ -4,6 +4,13 @@ #include #include "cJSON_Utils.h" +static int cJSONUtils_strcasecmp(const char *s1,const char *s2) +{ + if (!s1) return (s1==s2)?0:1;if (!s2) return 1; + for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; + return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); +} + /* JSON Pointer implementation: */ static int cJSONUtils_Pstrcasecmp(const char *a,const char *e) { @@ -115,13 +122,18 @@ static int cJSONUtils_Compare(cJSON *a,cJSON *b) case cJSON_Array: for (a=a->child,b=b->child;a && b;a=a->next,b=b->next) {int err=cJSONUtils_Compare(a,b);if (err) return err;} return (a || b)?-4:0; /* array size mismatch. */ case cJSON_Object: - if (cJSON_GetArraySize(a)!=cJSON_GetArraySize(b)) return -5; /* object length mismatch. */ - for (a=a->child;a;a=a->next) + cJSONUtils_SortObject(a); + cJSONUtils_SortObject(b); + a=a->child,b=b->child; + while (a && b) { - int err=0;cJSON *s=cJSON_GetObjectItem(b,a->string); if (!s) return -6; /* missing object member. */ - err=cJSONUtils_Compare(a,s);if (err) return err; + int err; + if (cJSONUtils_strcasecmp(a->string,b->string)) return -6; /* missing member */ + err=cJSONUtils_Compare(a,b);if (err) return err; + a=a->next,b=b->next; } - return 0; + return (a || b)?-5:0; /* object length mismatch */ + default: break; } return 0; @@ -251,22 +263,25 @@ static void cJSONUtils_CompareToPatch(cJSON *patches,const char *path,cJSON *fro case cJSON_Object: { - cJSON *a; - for (a=from->child;a;a=a->next) + cJSON *a,*b; + cJSONUtils_SortObject(from); + cJSONUtils_SortObject(to); + + a=from->child,b=to->child; + while (a || b) { - if (!cJSON_GetObjectItem(to,a->string)) cJSONUtils_GeneratePatch(patches,"remove",path,a->string,0); - } - for (a=to->child;a;a=a->next) - { - cJSON *other=cJSON_GetObjectItem(from,a->string); - if (!other) cJSONUtils_GeneratePatch(patches,"add",path,a->string,a); - else + int diff=(!a)?1:(!b)?-1:cJSONUtils_strcasecmp(a->string,b->string); + if (!diff) { char *newpath=(char*)malloc(strlen(path)+cJSONUtils_PointerEncodedstrlen(a->string)+2); cJSONUtils_PointerEncodedstrcpy(newpath+sprintf(newpath,"%s/",path),a->string); - cJSONUtils_CompareToPatch(patches,newpath,other,a); + cJSONUtils_CompareToPatch(patches,newpath,a,b); free(newpath); + a=a->next; + b=b->next; } + else if (diff<0) {cJSONUtils_GeneratePatch(patches,"remove",path,a->string,0); a=a->next;} + else {cJSONUtils_GeneratePatch(patches,"add",path,b->string,b); b=b->next;} } return; } @@ -283,12 +298,6 @@ cJSON* cJSONUtils_GeneratePatches(cJSON *from,cJSON *to) return patches; } -static int cJSONUtils_strcasecmp(const char *s1,const char *s2) -{ - if (!s1) return (s1==s2)?0:1;if (!s2) return 1; - for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) if(*s1 == 0) return 0; - return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2); -} static cJSON *cJSONUtils_SortList(cJSON *list) { diff --git a/test_utils.c b/test_utils.c index e166c8c..e018081 100644 --- a/test_utils.c +++ b/test_utils.c @@ -101,9 +101,9 @@ int main() { buf[0]=random[i];cJSON_AddItemToObject(sortme,buf,cJSON_CreateNumber(1)); } - before=cJSON_Print(sortme); + before=cJSON_PrintUnformatted(sortme); cJSONUtils_SortObject(sortme); - after=cJSON_Print(sortme); + after=cJSON_PrintUnformatted(sortme); printf("Before: [%s]\nAfter: [%s]\n\n",before,after); free(before);free(after);cJSON_Delete(sortme); }