[svn:parrot] r49018 - in trunk: include/parrot src/string

nwellnhof at svn.parrot.org nwellnhof at svn.parrot.org
Wed Sep 15 15:18:32 UTC 2010


Author: nwellnhof
Date: Wed Sep 15 15:18:32 2010
New Revision: 49018
URL: https://trac.parrot.org/parrot/changeset/49018

Log:
[str] Introduce growable strings

This greatly speeds up the concatenation of a long and a short string.

Modified:
   trunk/include/parrot/pobj.h
   trunk/src/string/api.c

Modified: trunk/include/parrot/pobj.h
==============================================================================
--- trunk/include/parrot/pobj.h	Wed Sep 15 14:14:49 2010	(r49017)
+++ trunk/include/parrot/pobj.h	Wed Sep 15 15:18:32 2010	(r49018)
@@ -135,6 +135,8 @@
     PObj_is_string_FLAG         = POBJ_FLAG(8),
     /* PObj is a PMC */
     PObj_is_PMC_FLAG            = POBJ_FLAG(9),
+    /* PObj is a copy of a string that doesn't own the string buffer */
+    PObj_is_string_copy_FLAG    = POBJ_FLAG(10),
     /* the PMC is a shared PMC */
     PObj_is_PMC_shared_FLAG     = POBJ_FLAG(11), /* Same as PObj_is_shared_FLAG */
     /* PObj is otherwise shared */
@@ -246,6 +248,10 @@
 #define PObj_is_string_SET(o) PObj_flag_SET(is_string, o)
 #define PObj_is_string_CLEAR(o) PObj_flag_CLEAR(is_string, o)
 
+#define PObj_is_string_copy_TEST(o) PObj_flag_TEST(is_string_copy, o)
+#define PObj_is_string_copy_SET(o) PObj_flag_SET(is_string_copy, o)
+#define PObj_is_string_copy_CLEAR(o) PObj_flag_CLEAR(is_string_copy, o)
+
 #define PObj_sysmem_TEST(o) PObj_flag_TEST(sysmem, o)
 #define PObj_sysmem_SET(o) PObj_flag_SET(sysmem, o)
 #define PObj_sysmem_CLEAR(o) PObj_flag_CLEAR(sysmem, o)
@@ -318,6 +324,10 @@
         (PObj_sysmem_FLAG | PObj_on_free_list_FLAG | \
          PObj_constant_FLAG | PObj_external_FLAG)))
 
+#define PObj_is_growable_TESTALL(o) (!(PObj_get_FLAGS(o) & \
+        (PObj_sysmem_FLAG | PObj_is_string_copy_FLAG | \
+         PObj_constant_FLAG | PObj_external_FLAG)))
+
 #define PObj_custom_mark_destroy_SETALL(o) do { \
         PObj_custom_mark_SET(o); \
         PObj_custom_destroy_SET(o); \

Modified: trunk/src/string/api.c
==============================================================================
--- trunk/src/string/api.c	Wed Sep 15 14:14:49 2010	(r49017)
+++ trunk/src/string/api.c	Wed Sep 15 15:18:32 2010	(r49018)
@@ -377,6 +377,9 @@
     /* Clear live flag. It might be set on constant strings */
     PObj_live_CLEAR(d);
 
+    /* Set the string copy flag */
+    PObj_is_string_copy_SET(d);
+
     /* Now check that buffer allocated from pool and affected by compacting */
     if (is_movable && Buffer_bufstart(s)) {
         /* If so, mark it as shared */
@@ -450,16 +453,42 @@
     /* calc usable and total bytes */
     total_length = a->bufused + b->bufused;
 
-    dest = Parrot_str_new_noinit(interp, total_length);
-    PARROT_ASSERT(enc);
-    dest->encoding = enc;
+    if (PObj_is_growable_TESTALL(a)
+    &&  a->strstart + total_length <=
+        (char *)Buffer_bufstart(a) + Buffer_buflen(a)) {
+        /* String a is growable and there's enough space in the buffer */
+        DECL_CONST_CAST;
+
+        dest = Parrot_str_copy(interp, a);
+
+        /* Switch string copy flags */
+        PObj_is_string_copy_SET(PARROT_const_cast(STRING *, a));
+        PObj_is_string_copy_CLEAR(dest);
 
-    /* Copy A first */
-    mem_sys_memcopy(dest->strstart, a->strstart, a->bufused);
+        /* Append b */
+        mem_sys_memcopy(dest->strstart + dest->bufused,
+                b->strstart, b->bufused);
 
-    /* Tack B on the end of A */
-    mem_sys_memcopy((void *)((ptrcast_t)dest->strstart + a->bufused),
-            b->strstart, b->bufused);
+        dest->hashval = 0;
+    }
+    else {
+        if (4 * b->bufused < a->bufused) {
+            /* Preallocate more memory if we're appending a short string to
+               a long string */
+            total_length += total_length >> 1;
+        }
+
+        dest = Parrot_str_new_noinit(interp, total_length);
+        PARROT_ASSERT(enc);
+        dest->encoding = enc;
+
+        /* Copy A first */
+        mem_sys_memcopy(dest->strstart, a->strstart, a->bufused);
+
+        /* Tack B on the end of A */
+        mem_sys_memcopy((void *)((ptrcast_t)dest->strstart + a->bufused),
+                b->strstart, b->bufused);
+    }
 
     dest->bufused = a->bufused + b->bufused;
     dest->strlen  = a->strlen + b->strlen;


More information about the parrot-commits mailing list