From 2bdc331b9aec0fd4861c694e9672710234a475e2 Mon Sep 17 00:00:00 2001 From: nwellnhof Date: Wed, 15 Sep 2010 15:18:32 +0000 Subject: [PATCH] [str] Introduce growable strings This greatly speeds up the concatenation of a long and a short string. git-svn-id: https://svn.parrot.org/parrot/trunk@49018 d31e2699-5ff4-0310-a27c-f18f2fbe73fe --- include/parrot/pobj.h | 10 ++++++++++ src/string/api.c | 45 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/include/parrot/pobj.h b/include/parrot/pobj.h index 126c27f58a..4f593e1976 100644 --- a/include/parrot/pobj.h +++ b/include/parrot/pobj.h @@ -135,6 +135,8 @@ typedef enum PObj_enum { 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 @@ typedef enum PObj_enum { #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 @@ typedef enum PObj_enum { (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); \ diff --git a/src/string/api.c b/src/string/api.c index 587f89e030..4fbf7444e8 100644 --- a/src/string/api.c +++ b/src/string/api.c @@ -377,6 +377,9 @@ Parrot_str_copy(PARROT_INTERP, ARGIN(const STRING *s)) /* 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 @@ Parrot_str_concat(PARROT_INTERP, ARGIN_NULLOK(const STRING *a), /* 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); + + /* Append b */ + mem_sys_memcopy(dest->strstart + dest->bufused, + b->strstart, b->bufused); - /* Copy A first */ - mem_sys_memcopy(dest->strstart, a->strstart, a->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; + } - /* Tack B on the end of A */ - mem_sys_memcopy((void *)((ptrcast_t)dest->strstart + a->bufused), - b->strstart, b->bufused); + 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; -- 2.11.4.GIT