From 4a5e3fb71330f7eeb4febc49acf886cc776cc018 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Henrik=20Grubbstr=C3=B6m=20=28Grubba=29?=
 <grubba@grubba.org>
Date: Sat, 25 Nov 2000 18:00:17 +0100
Subject: [PATCH] Allocate short strings with BLOCK_ALLOC(). Optimized
 string_builder_putchar(), and string_builder_fill().

Rev: src/stralloc.c:1.107
---
 src/stralloc.c | 168 +++++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 142 insertions(+), 26 deletions(-)

diff --git a/src/stralloc.c b/src/stralloc.c
index 04cc1e37ed..55535fbac5 100644
--- a/src/stralloc.c
+++ b/src/stralloc.c
@@ -15,6 +15,7 @@
 #include "stuff.h"
 #include "bignum.h"
 #include "interpret.h"
+#include "block_alloc.h"
 
 #include <errno.h>
 #include <float.h>
@@ -25,7 +26,7 @@
 #define HUGE HUGE_VAL
 #endif /*!HUGE*/
 
-RCSID("$Id: stralloc.c,v 1.106 2000/10/20 10:06:50 grubba Exp $");
+RCSID("$Id: stralloc.c,v 1.107 2000/11/25 17:00:17 grubba Exp $");
 
 #define BEGIN_HASH_SIZE 997
 #define MAX_AVG_LINK_LENGTH 3
@@ -414,6 +415,58 @@ static void rehash(void)
 
 /*** Make new strings ***/
 
+/* Use the BLOCK_ALLOC() stuff for short strings */
+
+#define SHORT_STRING_BLOCK	256
+#define SHORT_STRING_THRESHOLD	16
+
+struct short_pike_string0 {
+  struct pike_string str;
+  p_wchar0 data[SHORT_STRING_THRESHOLD];
+};
+
+struct short_pike_string1 {
+  struct pike_string str;
+  p_wchar1 data[SHORT_STRING_THRESHOLD];
+};
+
+struct short_pike_string2 {
+  struct pike_string str;
+  p_wchar2 data[SHORT_STRING_THRESHOLD];
+};
+
+#undef BLOCK_ALLOC_NEXT
+#define BLOCK_ALLOC_NEXT	str.next
+
+BLOCK_ALLOC(short_pike_string0, SHORT_STRING_BLOCK)
+BLOCK_ALLOC(short_pike_string1, SHORT_STRING_BLOCK)
+BLOCK_ALLOC(short_pike_string2, SHORT_STRING_BLOCK)
+
+#undef BLOCK_ALLOC_NEXT
+#define BLOCK_ALLOC_NEXT	next
+
+#define really_free_short_pike_string(s) do { \
+     if (!s->size_shift) { \
+       really_free_short_pike_string0((struct short_pike_string0 *)s); \
+     } else if (s->size_shift == 1) { \
+       really_free_short_pike_string1((struct short_pike_string1 *)s); \
+     DO_IF_DEBUG( \
+     } else if (s->size_shift != 2) { \
+       fatal("Unsupported string shift: %d\n", s->size_shift); \
+     ) \
+     } else { \
+       really_free_short_pike_string2((struct short_pike_string2 *)s); \
+     } \
+   } while(0)
+
+#define really_free_pike_string(s) do { \
+    if (s->len <= SHORT_STRING_THRESHOLD) { \
+      really_free_short_pike_string(s); \
+    } else { \
+      debug_free((char *)s, DMALLOC_LOCATION(), 1); \
+    } \
+  } while(0)
+
 /* note that begin_shared_string expects the _exact_ size of the string,
  * not the maximum size
  */
@@ -425,7 +478,11 @@ PMOD_EXPORT struct pike_string *debug_begin_shared_string(size_t len)
   if(d_flag>10)
     verify_shared_strings_tables();
 #endif
-  t=(struct pike_string *)xalloc(len + sizeof(struct pike_string));
+  if (len <= SHORT_STRING_THRESHOLD) {
+    t=(struct pike_string *)alloc_short_pike_string0();
+  } else {
+    t=(struct pike_string *)xalloc(len + sizeof(struct pike_string));
+  }
   t->str[len]=0;
   t->len=len;
   t->size_shift=0;
@@ -485,7 +542,21 @@ PMOD_EXPORT struct pike_string *debug_begin_wide_shared_string(size_t len, int s
   if(d_flag>10)
     verify_shared_strings_tables();
 #endif
-  t=(struct pike_string *)xalloc((len<<shift) + sizeof(struct pike_string));
+  if (len <= SHORT_STRING_THRESHOLD) {
+    if (!shift) {
+      t = (struct pike_string *)alloc_short_pike_string0();
+    } else if (shift == 1) {
+      t = (struct pike_string *)alloc_short_pike_string1();
+#ifdef PIKE_DEBUG
+    } else if (shift != 2) {
+      fatal("Unsupported string shift: %d\n", shift);
+#endif /* PIKE_DEBUG */
+    } else {
+      t = (struct pike_string *)alloc_short_pike_string2();
+    }
+  } else {
+    t=(struct pike_string *)xalloc((len<<shift) + sizeof(struct pike_string));
+  }
   t->len=len;
   t->size_shift=shift;
   low_set_index(t,len,0);
@@ -512,7 +583,7 @@ PMOD_EXPORT struct pike_string *low_end_shared_string(struct pike_string *s)
 
   if(s2)
   {
-    free((char *)s);
+    really_free_pike_string(s);
     s = s2;
   }else{
     link_pike_string(s, h);
@@ -542,14 +613,14 @@ PMOD_EXPORT struct pike_string *end_shared_string(struct pike_string *s)
 	case 0:
 	  s2=begin_shared_string(s->len);
 	  convert_2_to_0(STR0(s2),STR2(s),s->len);
-	  free((char *)s);
+	  really_free_pike_string(s);
 	  s=s2;
 	  break;
 
 	case 1:
 	  s2=begin_wide_shared_string(s->len,1);
 	  convert_2_to_1(STR1(s2),STR2(s),s->len);
-	  free((char *)s);
+	  really_free_pike_string(s);
 	  s=s2;
 	  /* Fall though */
       }
@@ -560,7 +631,7 @@ PMOD_EXPORT struct pike_string *end_shared_string(struct pike_string *s)
       {
 	s2=begin_shared_string(s->len);
 	convert_1_to_0(STR0(s2),STR1(s),s->len);
-	free((char *)s);
+	really_free_pike_string(s);
 	s=s2;
       }
       break;
@@ -742,7 +813,7 @@ PMOD_EXPORT void really_free_string(struct pike_string *s)
   }
 #endif
   unlink_pike_string(s);
-  debug_free((char *)s,DMALLOC_LOCATION(),1);
+  really_free_pike_string(s);
   GC_FREE_SIMPLE_BLOCK(s);
 }
 
@@ -1129,16 +1200,30 @@ PMOD_EXPORT ptrdiff_t my_strcmp(struct pike_string *a,struct pike_string *b)
 PMOD_EXPORT struct pike_string *realloc_unlinked_string(struct pike_string *a,
 							ptrdiff_t size)
 {
-  struct pike_string *r;
-  r=(struct pike_string *)realloc((char *)a,
-					sizeof(struct pike_string)+
-				  ((size+1)<<a->size_shift)); /* FIXME !! */
+  struct pike_string *r = NULL;
+
+  if (a->len <= SHORT_STRING_THRESHOLD) {
+    if (size <= SHORT_STRING_THRESHOLD) {
+      /* There's already place enough. */
+      a->len = size;
+      low_set_index(a, size, 0);
+      return a;
+    }
+  } else if (size > SHORT_STRING_THRESHOLD) {
+    r=(struct pike_string *)realloc((char *)a,
+				    sizeof(struct pike_string)+
+				    ((size+1)<<a->size_shift)); /* FIXME !! */
+  }
 	
   if(!r)
   {
-    r=begin_shared_string(size);
-    MEMCPY(r->str, a->str, a->len<<a->size_shift);
-    free((char *)a);
+    r=begin_wide_shared_string(size, a->size_shift);
+    if (a->len <= size) {
+      MEMCPY(r->str, a->str, a->len<<a->size_shift);
+    } else {
+      MEMCPY(r->str, a->str, size<<a->size_shift);
+    }
+    really_free_pike_string(a);
   }
 
   r->len=size;
@@ -1572,7 +1657,7 @@ void cleanup_shared_string_table(void)
     {
       next=s->next;
 #ifdef REALLY_FREE
-      free((char *)s);
+      really_free_pike_string(s);
 #else
       s->next=0;
 #endif
@@ -1654,21 +1739,20 @@ static void string_build_mkspace(struct string_builder *s,
     n=begin_wide_shared_string(l,mag);
     pike_string_cpy(MKPCHARP_STR(n),s->s);
     n->len=s->s->len;
+    s->s->len = s->malloced;	/* Restore the real length */
+    really_free_pike_string(s->s);
     s->malloced=l;
-    free((char *)s->s);
     s->s=n;
   }
   else if(((size_t)s->s->len+chars) > ((size_t)s->malloced))
   {
     size_t newlen = MAXIMUM((size_t)(s->malloced*2),
 			    (size_t)(s->s->len + chars));
+    ptrdiff_t oldlen = s->s->len;
 
-    s->s=(struct pike_string *)realloc((char *)s->s,
-				       sizeof(struct pike_string)+
-				       ((newlen+1)<<s->s->size_shift));
-    if(!s->s)
-      fatal("Out of memory.\n");
-    s->malloced=newlen;
+    s->s = realloc_unlinked_string(s->s, newlen);
+    s->s->len = oldlen;
+    s->malloced = newlen;
   }
 }
 
@@ -1685,7 +1769,14 @@ PMOD_EXPORT void *string_builder_allocate(struct string_builder *s, ptrdiff_t ch
 PMOD_EXPORT void string_builder_putchar(struct string_builder *s, int ch)
 {
   ptrdiff_t i;
+#if 1
+  if ((min_magnitude(ch) > s->s->size_shift) ||
+      (((size_t)s->s->len) >= ((size_t)s->malloced))) {
+    string_build_mkspace(s,1,min_magnitude(ch));
+  }
+#else
   string_build_mkspace(s,1,min_magnitude(ch));
+#endif /* 0 */
   s->known_shift=MAXIMUM((size_t)min_magnitude(ch),s->known_shift);
   i = s->s->len++;
   low_set_index(s->s,i,ch);
@@ -1711,7 +1802,15 @@ PMOD_EXPORT void string_builder_append(struct string_builder *s,
 				       PCHARP from,
 				       ptrdiff_t len)
 {
-  string_build_mkspace(s,len,from.shift);
+  int shift;
+  if ((shift = from.shift) > s->s->size_shift) {
+    if (shift == 1) {
+      shift = find_magnitude1((p_wchar1 *)from.ptr, len);
+    } else {
+      shift = find_magnitude2((p_wchar2 *)from.ptr, len);
+    }
+  }
+  string_build_mkspace(s, len, shift);
   generic_memcpy(MKPCHARP_STR_OFF(s->s,s->s->len), from, len);
   s->s->len+=len;
 }
@@ -1723,6 +1822,7 @@ PMOD_EXPORT void string_builder_fill(struct string_builder *s,
 				     ptrdiff_t offset)
 {
   ptrdiff_t tmp;
+  int shift;
 
 #ifdef PIKE_DEBUG
   if(len<=0)
@@ -1740,7 +1840,17 @@ PMOD_EXPORT void string_builder_fill(struct string_builder *s,
     return;
   }
 
-  string_build_mkspace(s,howmany,from.shift);
+  if ((shift = from.shift) > s->s->size_shift) {
+    /* Check if we really need the extra magnitude. */
+    /* FIXME: What about offset? */
+    if (shift == 1) {
+      shift = find_magnitude1((p_wchar1 *)from.ptr, len);
+    } else {
+      shift = find_magnitude2((p_wchar2 *)from.ptr, len);
+    }
+  }
+
+  string_build_mkspace(s, howmany, shift);
   tmp = MINIMUM(howmany, len - offset);
 
   generic_memcpy(MKPCHARP_STR_OFF(s->s,s->s->len),
@@ -1794,12 +1904,18 @@ PMOD_EXPORT void reset_string_builder(struct string_builder *s)
 
 PMOD_EXPORT void free_string_builder(struct string_builder *s)
 {
-  free((char *)s->s);
+  s->s->len = s->malloced;
+  really_free_pike_string(s->s);
 }
 
 PMOD_EXPORT struct pike_string *finish_string_builder(struct string_builder *s)
 {
   low_set_index(s->s,s->s->len,0);
+  if (s->s->len <= SHORT_STRING_THRESHOLD) {
+    ptrdiff_t len = s->s->len;
+    s->s->len = s->malloced;
+    s->s = realloc_unlinked_string(s->s, len);
+  }
   if(s->known_shift == (size_t)s->s->size_shift)
     return low_end_shared_string(s->s);
   return end_shared_string(s->s);
-- 
GitLab