Przeglądaj źródła

2006-08-19 Aaron Bockover <[email protected]>

    * src/gstring.c: optimize and generalize reallocation by providing
    a GROW_IF_NECESSARY macro, do not use strcpy/strcat as they are
    very, very slow; GString is now much closer to GLib's implementation
    in terms of performance

    * test/string.c: added speed-specific tests to beat on reallocation code

    * test/test-both: run make if the test drivers don't exist


svn path=/trunk/mono/; revision=64075
Aaron Bockover 19 lat temu
rodzic
commit
bc434b09d7
4 zmienionych plików z 124 dodań i 148 usunięć
  1. 11 0
      eglib/ChangeLog
  2. 63 136
      eglib/src/gstring.c
  3. 46 12
      eglib/test/string.c
  4. 4 0
      eglib/test/test-both

+ 11 - 0
eglib/ChangeLog

@@ -1,3 +1,14 @@
+2006-08-19  Aaron Bockover  <[email protected]>
+
+	* src/gstring.c: optimize and generalize reallocation by providing
+	a GROW_IF_NECESSARY macro, do not use strcpy/strcat as they are 
+	very, very slow; GString is now much closer to GLib's implementation
+	in terms of performance
+
+	* test/string.c: added speed-specific tests to beat on reallocation code
+
+	* test/test-both: run make if the test drivers don't exist
+
 2006-08-19  Jonathan Chambers  <[email protected]>
 
 	* src/gmodule.c: Add gmodule support for windows and fix

+ 63 - 136
eglib/src/gstring.c

@@ -3,6 +3,7 @@
  *
  * Author:
  *   Miguel de Icaza ([email protected])
+ *   Aaron Bockover ([email protected])
  *
  * (C) 2006 Novell, Inc.
  *
@@ -29,23 +30,11 @@
 #include <stdio.h>
 #include <glib.h>
 
-GString *
-g_string_new (const gchar *init)
-{
-	GString *ret = g_new (GString, 1);
-	int len, alloc;
-
-	len = strlen (init);
-	if (len < 15)
-		alloc = 16;
-	else
-		alloc = len+1;
-	ret->str = g_malloc (alloc);
-	ret->len = len;
-	ret->allocated_len = alloc;
-	strcpy (ret->str, init);
-
-	return ret;
+#define GROW_IF_NECESSARY(s,l) { \
+	if(s->len + l >= s->allocated_len) { \
+		s->allocated_len = (s->allocated_len + l + 16) * 2; \
+		s->str = g_realloc(s->str, s->allocated_len); \
+	} \
 }
 
 GString *
@@ -53,16 +42,21 @@ g_string_new_len (const gchar *init, gssize len)
 {
 	GString *ret = g_new (GString, 1);
 
-	ret->str = g_malloc (len+1);
-	ret->allocated_len = len + 1;
-	ret->len = len;
+	ret->len = len < 0 ? strlen(init) : len;
+	ret->allocated_len = MAX(ret->len + 1, 16);
+	ret->str = g_malloc(ret->allocated_len);
+	memcpy(ret->str, init, ret->len);
+	ret->str[ret->len] = 0;
 
-	memcpy (ret->str, init, len);
-	ret->str [len] = 0;
-	
 	return ret;
 }
 
+GString *
+g_string_new (const gchar *init)
+{
+	return g_string_new_len(init, -1);
+}
+
 GString *
 g_string_sized_new (gsize default_size)
 {
@@ -79,106 +73,79 @@ g_string_sized_new (gsize default_size)
 gchar *
 g_string_free (GString *string, gboolean free_segment)
 {
-	char *data;
+	gchar *data;
+	
 	g_return_val_if_fail (string != NULL, NULL);
 
 	data = string->str;
-	if (free_segment)
-		g_free (data);
-	g_free (string);
-
-	if (free_segment)
-		return NULL;
-	else
-		return data;
+	g_free(string);
 	
+	if(!free_segment) {
+		return data;
+	}
+
+	g_free(data);
+	return NULL;
 }
 
 GString *
-g_string_append (GString *string, const gchar *val)
+g_string_append_len (GString *string, const gchar *val, gssize len)
 {
-	int len, size;
-	char *new;
-	
-	g_return_val_if_fail (string != NULL, NULL);
-	g_return_val_if_fail (val != NULL, string);
-	
-	len = strlen (val);
-	if ((string->len + len) < string->allocated_len){
-		strcat (string->str, val);
-		string->len += len;
-		return string;
+	g_return_val_if_fail(string != NULL, NULL);
+	g_return_val_if_fail(val != NULL, string);
+
+	if(len < 0) {
+		len = strlen(val);
 	}
-	size = (len + string->len + 16) * 2;
-	new = g_malloc (size);
-	memcpy (new, string->str, string->len);
-	memcpy (new + string->len, val, len);
-	g_free (string->str);
-	string->str = new;
-	string->allocated_len = size;
+
+	GROW_IF_NECESSARY(string, len);
+	memcpy(string->str + string->len, val, len);
 	string->len += len;
-	new [string->len] = 0;
-	
+	string->str[string->len] = 0;
+
 	return string;
 }
 
+GString *
+g_string_append (GString *string, const gchar *val)
+{
+	g_return_val_if_fail(string != NULL, NULL);
+	g_return_val_if_fail(val != NULL, string);
+
+	return g_string_append_len(string, val, -1);
+}
+
 GString *
 g_string_append_c (GString *string, gchar c)
 {
-	gsize size;
-	char *new;
-	
-	g_return_val_if_fail (string != NULL, NULL);
+	g_return_val_if_fail(string != NULL, NULL);
 
-	if (string->len + 1 < string->allocated_len){
-		string->str [string->len] = c;
-		string->str [string->len+1] = 0;
-		string->len++;
-		return string;
-	}
-	size = (string->allocated_len + 16) * 2;
-	new = g_malloc (size);
-	memcpy (new, string->str, string->len);
-	new [string->len] = c;
-	new [string->len+1] = 0;
+	GROW_IF_NECESSARY(string, 1);
 	
-	g_free (string->str);
-	string->allocated_len = size;
+	string->str[string->len] = c;
+	string->str[string->len + 1] = 0;
 	string->len++;
-	string->str = new;
 
 	return string;
 }
 
 GString *
-g_string_append_len (GString *string, const gchar *val, gssize len)
+g_string_prepend (GString *string, const gchar *val)
 {
-	int size;
-	char *new;
+	gssize len;
 	
-	g_return_val_if_fail (string != NULL, NULL);
+	g_return_val_if_fail (string != NULL, string);
 	g_return_val_if_fail (val != NULL, string);
-	if (len < 0)
-		return g_string_append (string, val);
-	
-	if ((string->len + len) < string->allocated_len){
-		memcpy (string->str+string->len, val, len);
-		string->len += len;
-		return string;
-	}
-	size = (len + string->len + 16) * 2;
-	new = g_malloc (size);
-	memcpy (new, string->str, string->len);
-	memcpy (new + string->len, val, len);
-	g_free (string->str);
-	string->str = new;
-	string->allocated_len = size;
-	string->len += len;
-	new [string->len] = 0;
+
+	len = strlen (val);
 	
+	GROW_IF_NECESSARY(string, len);	
+	memmove(string->str + len, string->str, string->len + 1);
+	memcpy(string->str, val, len);
+
 	return string;
 }
-	
+
 void
 g_string_append_printf (GString *string, const gchar *format, ...)
 {
@@ -220,52 +187,12 @@ g_string_truncate (GString *string, gsize len)
 	g_return_val_if_fail (string != NULL, string);
 
 	/* Silent return */
-	if (len < 0)
-		return string;
-	
-	if (len >= string->len)
+	if (len < 0 || len >= string->len) {
 		return string;
-	string->len = len;
-	string->str [len] = 0;
-	return string;
-}
-
-GString *
-g_string_prepend (GString *string, const gchar *val)
-{
-	int vallen;
-	g_return_val_if_fail (string != NULL, string);
-	g_return_val_if_fail (val != NULL, string);
-
-	vallen = strlen (val);
-	
-	if ((string->len + vallen + 1) < string->allocated_len){
-		memmove (string->str+vallen, string->str, string->len+1);
-		memcpy (string->str, val, vallen);
-	} else {
-		/*
-		 * Add some extra space, so we do not reallocate too often
-		 * maybe we should centralize this decision somewhere else. 
-		 */
-		char *new;
-		int nl = MAX (string->len + vallen + 1, string->allocated_len);
-		nl = nl < 8192 ? (nl * 3) : nl + 1024;
-
-		new = malloc (nl);
-		/* Failure */
-		if (new == NULL) {
-			g_error ("No more memory");
-			return string;
-		}
-		strcpy (new, val);
-		/* To cope with embedded nulls */
-		memcpy (new + vallen, string->str, string->len);
-		string->len = string->len + vallen;
-		g_free (string->str);
-		string->str = new;
-		string->allocated_len = nl;
 	}
 	
+	string->len = len;
+	string->str[len] = 0;
 	return string;
 }
 

+ 46 - 12
eglib/test/string.c

@@ -5,6 +5,46 @@
 
 #define sfail(k,p) if (s->str [p] != k) { g_string_free (s,TRUE); return FAILED("Got %s, Failed at %d, expected '%c'", s->str, p, k);}
 
+RESULT
+test_append_speed()
+{
+	GString *s = g_string_new("");
+	gint i;
+	
+	for(i = 0; i < 1024; i++) {
+		g_string_append(s, "x");
+	}
+	
+	if(strlen (s->str) != 1024) {
+		return FAILED("Incorrect string size, got: %s %d", 
+			s->str, strlen(s->str));
+	}
+	
+	g_string_free (s, TRUE);
+
+	return OK;
+}
+
+RESULT
+test_append_c_speed()
+{
+	GString *s = g_string_new("");
+	gint i;
+	
+	for(i = 0; i < 1024; i++) {
+		g_string_append_c(s, 'x');
+	}
+	
+	if(strlen(s->str) != 1024) {
+		return FAILED("Incorrect string size, got: %s %d", s->str, 
+			strlen(s->str));
+	}
+	
+	g_string_free(s, TRUE);
+
+	return OK;
+}
+
 RESULT
 test_gstring ()
 {
@@ -30,14 +70,6 @@ test_gstring ()
 		return FAILED("Did not copy correctly, got: %s", s->str+4);
 	}
 
-	g_string_free (s, TRUE);
-	s = g_string_new ("");
-	for (i = 0; i < 1024; i++){
-		g_string_append (s, "x");
-	}
-	if (strlen (s->str) != 1024){
-		return FAILED("Incorrect string size, got: %s %d", s->str, strlen (s->str));
-	}
 	g_string_free (s, TRUE);
 
 	s = g_string_new ("");
@@ -76,7 +108,7 @@ test_gstring ()
 	return OK;
 }
 
-static char *
+RESULT
 test_sized ()
 {
 	GString *s = g_string_sized_new (20);
@@ -91,7 +123,7 @@ test_sized ()
 	return NULL;
 }
 
-static char *
+RESULT
 test_truncate ()
 {
 	GString *s = g_string_new ("0123456789");
@@ -117,7 +149,7 @@ test_truncate ()
 	return NULL;
 }
 
-static char *
+RESULT
 test_prepend ()
 {
 	GString *s = g_string_new ("dingus");
@@ -149,7 +181,7 @@ test_prepend ()
 	return NULL;
 }
 
-static char *
+RESULT
 test_appendlen ()
 {
 	GString *s = g_string_new ("");
@@ -170,6 +202,8 @@ test_appendlen ()
 }
 
 static Test string_tests [] = {
+	{"append-speed", test_append_speed},
+    {"append_c-speed", test_append_c_speed},
 	{"constructors+append", test_gstring },
 	{"constructor-sized", test_sized },
 	{"truncate", test_truncate },

+ 4 - 0
eglib/test/test-both

@@ -24,6 +24,10 @@ for arg in $@; do
 	fi
 done
 
+if [ ! -x "./test-glib" -o ! -x "./test-eglib" ]; then
+	make
+fi
+
 if [ "x$1" = "x--speed-compare" ]; then
 	ITERATIONS=100000
 	if [ ! -z "$2" ]; then