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
This commit is contained in:
Dave Gamble 2015-02-13 19:53:27 +00:00
parent c4ddd7aaa3
commit 491cf029b2
2 changed files with 32 additions and 23 deletions

View File

@ -4,6 +4,13 @@
#include <stdio.h>
#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)
{

View File

@ -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);
}