From b88a26f02276ec2e98287cd2e5f2abea1ea9e949 Mon Sep 17 00:00:00 2001
From: Luboš Luňák <l.lunak@suse.cz>
Date: Tue, 4 Dec 2012 19:27:34 +0100
Subject: rtl_(u)String_ensureCapacity

Ensure there will be enough extra space in a string, to be used for string
appending. A bit like rtl_(u)String_newConcat(), but without the function
actually appending anything. Unlike the stringbuffer variant this does
not allocate any extra.

Change-Id: Ic6f84bf014a713f9912c81d8f1405c593978822d
---
 sal/qa/rtl/strings/test_ostring_concat.cxx  | 40 +++++++++++++++++++++++++
 sal/qa/rtl/strings/test_oustring_concat.cxx | 45 +++++++++++++++++++++++++++++
 2 files changed, 85 insertions(+)

(limited to 'sal/qa/rtl')

diff --git a/sal/qa/rtl/strings/test_ostring_concat.cxx b/sal/qa/rtl/strings/test_ostring_concat.cxx
index 46457ddf5f35..c3a422a51f5f 100644
--- a/sal/qa/rtl/strings/test_ostring_concat.cxx
+++ b/sal/qa/rtl/strings/test_ostring_concat.cxx
@@ -33,9 +33,11 @@ class StringConcat : public CppUnit::TestFixture
 {
 private:
     void check();
+    void checkEnsureCapacity();
 
 CPPUNIT_TEST_SUITE(StringConcat);
 CPPUNIT_TEST(check);
+CPPUNIT_TEST(checkEnsureCapacity);
 CPPUNIT_TEST_SUITE_END();
 };
 
@@ -73,6 +75,44 @@ void test::ostring::StringConcat::check()
 }
 #undef typeid
 
+void test::ostring::StringConcat::checkEnsureCapacity()
+{
+    rtl_String* str = NULL;
+    rtl_string_newFromLiteral( &str, "test", strlen( "test" ), 0 );
+    CPPUNIT_ASSERT_EQUAL( sal_Int32( 4 ), str->length );
+    CPPUNIT_ASSERT_EQUAL( 1, str->refCount );
+
+    rtl_String* oldStr = str;
+    rtl_string_ensureCapacity( &str, 4 ); // should be no-op
+    CPPUNIT_ASSERT_EQUAL( sal_Int32( 4 ), str->length );
+    CPPUNIT_ASSERT_EQUAL( 1, str->refCount );
+    CPPUNIT_ASSERT( oldStr == str );
+
+    rtl_string_acquire( oldStr );
+    CPPUNIT_ASSERT_EQUAL( 2, str->refCount );
+    rtl_string_ensureCapacity( &str, 4 );
+    CPPUNIT_ASSERT_EQUAL( sal_Int32( 4 ), str->length );
+    CPPUNIT_ASSERT_EQUAL( 1, str->refCount );
+    // a copy was forced because of refcount
+    CPPUNIT_ASSERT( oldStr != str );
+    CPPUNIT_ASSERT( strcmp( oldStr->buffer, str->buffer ) == 0 );
+    CPPUNIT_ASSERT_EQUAL( 1, oldStr->refCount );
+    rtl_string_release( str );
+    str = oldStr;
+
+    rtl_string_acquire( oldStr );
+    rtl_string_ensureCapacity( &str, 1024 );
+    CPPUNIT_ASSERT_EQUAL( sal_Int32( 4 ), str->length ); // size is still 4
+    CPPUNIT_ASSERT_EQUAL( 1, str->refCount );
+    CPPUNIT_ASSERT( oldStr != str );
+    CPPUNIT_ASSERT( strcmp( oldStr->buffer, str->buffer ) == 0 );
+    CPPUNIT_ASSERT_EQUAL( 1, oldStr->refCount );
+    strcpy( str->buffer, "01234567890123456789" ); // but there should be extra capacity
+    str->length += 20;
+    rtl_string_release( str );
+    rtl_string_release( oldStr );
+}
+
 }} // namespace
 
 CPPUNIT_TEST_SUITE_REGISTRATION(test::ostring::StringConcat);
diff --git a/sal/qa/rtl/strings/test_oustring_concat.cxx b/sal/qa/rtl/strings/test_oustring_concat.cxx
index 7eefb6f44587..108b166c6de2 100644
--- a/sal/qa/rtl/strings/test_oustring_concat.cxx
+++ b/sal/qa/rtl/strings/test_oustring_concat.cxx
@@ -33,9 +33,11 @@ class StringConcat : public CppUnit::TestFixture
 {
 private:
     void check();
+    void checkEnsureCapacity();
 
 CPPUNIT_TEST_SUITE(StringConcat);
 CPPUNIT_TEST(check);
+CPPUNIT_TEST(checkEnsureCapacity);
 CPPUNIT_TEST_SUITE_END();
 };
 
@@ -61,6 +63,49 @@ void test::oustring::StringConcat::check()
     TYPES_ASSERT_EQUAL(( typeid( OUStringConcat< OUString, const char[ 4 ] > )), typeid( OUString( "foo" ) + d1 ));
 }
 
+void test::oustring::StringConcat::checkEnsureCapacity()
+{
+    rtl_uString* str = NULL;
+    rtl_uString_newFromLiteral( &str, "test", strlen( "test" ), 0 );
+    CPPUNIT_ASSERT_EQUAL( sal_Int32( 4 ), str->length );
+    CPPUNIT_ASSERT_EQUAL( 1, str->refCount );
+
+    rtl_uString* oldStr = str;
+    rtl_uString_ensureCapacity( &str, 4 ); // should be no-op
+    CPPUNIT_ASSERT_EQUAL( sal_Int32( 4 ), str->length );
+    CPPUNIT_ASSERT_EQUAL( 1, str->refCount );
+    CPPUNIT_ASSERT( oldStr == str );
+
+    rtl_uString_acquire( oldStr );
+    CPPUNIT_ASSERT_EQUAL( 2, str->refCount );
+    rtl_uString_ensureCapacity( &str, 4 );
+    CPPUNIT_ASSERT_EQUAL( sal_Int32( 4 ), str->length );
+    CPPUNIT_ASSERT_EQUAL( 1, str->refCount );
+    // a copy was forced because of refcount
+    CPPUNIT_ASSERT( oldStr != str );
+    CPPUNIT_ASSERT( rtl_ustr_compare( oldStr->buffer, str->buffer ) == 0 );
+    CPPUNIT_ASSERT_EQUAL( 1, oldStr->refCount );
+    rtl_uString_release( str );
+    str = oldStr;
+
+    rtl_uString_acquire( oldStr );
+    rtl_uString_ensureCapacity( &str, 1024 );
+    CPPUNIT_ASSERT_EQUAL( sal_Int32( 4 ), str->length ); // size is still 4
+    CPPUNIT_ASSERT_EQUAL( 1, str->refCount );
+    CPPUNIT_ASSERT( oldStr != str );
+    CPPUNIT_ASSERT( rtl_ustr_compare( oldStr->buffer, str->buffer ) == 0 );
+    CPPUNIT_ASSERT_EQUAL( 1, oldStr->refCount );
+    // but there should be extra capacity
+    for( int i = 0;
+         i < 20;
+         ++i )
+        str->buffer[ str->length + i ] = '0';
+    str->length += 20;
+    rtl_uString_release( str );
+    rtl_uString_release( oldStr );
+}
+
+
 }} // namespace
 
 CPPUNIT_TEST_SUITE_REGISTRATION(test::oustring::StringConcat);
-- 
cgit