Selaa lähdekoodia

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

Dave Gamble 10 vuotta sitten
vanhempi
commit
491cf029b2
2 muutettua tiedostoa jossa 32 lisäystä ja 23 poistoa
  1. 30 21
      cJSON_Utils.c
  2. 2 2
      test_utils.c

+ 30 - 21
cJSON_Utils.c

@@ -4,6 +4,13 @@
 #include <stdio.h>
 #include <stdio.h>
 #include "cJSON_Utils.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: */
 /* JSON Pointer implementation: */
 static int cJSONUtils_Pstrcasecmp(const char *a,const char *e)
 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;}
 	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. */
 						return (a || b)?-4:0;	/* array size mismatch. */
 	case cJSON_Object:
 	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;
 	default:			break;
 	}
 	}
 	return 0;
 	return 0;
@@ -251,22 +263,25 @@ static void cJSONUtils_CompareToPatch(cJSON *patches,const char *path,cJSON *fro
 
 
 	case cJSON_Object:
 	case cJSON_Object:
 	{
 	{
-		cJSON *a;
-		for (a=from->child;a;a=a->next)
-		{
-			if (!cJSON_GetObjectItem(to,a->string))	cJSONUtils_GeneratePatch(patches,"remove",path,a->string,0);
-		}
-		for (a=to->child;a;a=a->next)
+		cJSON *a,*b;
+		cJSONUtils_SortObject(from);
+		cJSONUtils_SortObject(to);
+		
+		a=from->child,b=to->child;
+		while (a || b)
 		{
 		{
-			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);
 				char *newpath=(char*)malloc(strlen(path)+cJSONUtils_PointerEncodedstrlen(a->string)+2);
 				cJSONUtils_PointerEncodedstrcpy(newpath+sprintf(newpath,"%s/",path),a->string);
 				cJSONUtils_PointerEncodedstrcpy(newpath+sprintf(newpath,"%s/",path),a->string);
-				cJSONUtils_CompareToPatch(patches,newpath,other,a);
+				cJSONUtils_CompareToPatch(patches,newpath,a,b);
 				free(newpath);
 				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;
 		return;
 	}
 	}
@@ -283,12 +298,6 @@ cJSON* cJSONUtils_GeneratePatches(cJSON *from,cJSON *to)
 	return patches;
 	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)
 static cJSON *cJSONUtils_SortList(cJSON *list)
 {
 {

+ 2 - 2
test_utils.c

@@ -101,9 +101,9 @@ int main()
 	{
 	{
 		buf[0]=random[i];cJSON_AddItemToObject(sortme,buf,cJSON_CreateNumber(1));
 		buf[0]=random[i];cJSON_AddItemToObject(sortme,buf,cJSON_CreateNumber(1));
 	}
 	}
-	before=cJSON_Print(sortme);
+	before=cJSON_PrintUnformatted(sortme);
 	cJSONUtils_SortObject(sortme);
 	cJSONUtils_SortObject(sortme);
-	after=cJSON_Print(sortme);
+	after=cJSON_PrintUnformatted(sortme);
 	printf("Before: [%s]\nAfter: [%s]\n\n",before,after);
 	printf("Before: [%s]\nAfter: [%s]\n\n",before,after);
 	free(before);free(after);cJSON_Delete(sortme);		
 	free(before);free(after);cJSON_Delete(sortme);		
 }
 }