From b88a26f02276ec2e98287cd2e5f2abea1ea9e949 Mon Sep 17 00:00:00 2001 From: Luboš Luňák 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/inc/rtl/string.h | 18 ++++++++++++ sal/inc/rtl/ustring.h | 18 ++++++++++++ sal/qa/rtl/strings/test_ostring_concat.cxx | 40 +++++++++++++++++++++++++ sal/qa/rtl/strings/test_oustring_concat.cxx | 45 +++++++++++++++++++++++++++++ sal/rtl/source/strtmpl.cxx | 23 +++++++++++++++ sal/util/sal.map | 6 ++++ 6 files changed, 150 insertions(+) (limited to 'sal') diff --git a/sal/inc/rtl/string.h b/sal/inc/rtl/string.h index 9f3c69a0bcc4..13c622d4e8b3 100644 --- a/sal/inc/rtl/string.h +++ b/sal/inc/rtl/string.h @@ -1313,6 +1313,24 @@ SAL_DLLPUBLIC sal_Bool SAL_CALL rtl_convertUStringToString( sal_uInt32 nFlags) SAL_THROW_EXTERN_C(); +/** Ensure a string has enough space for a given number of characters. + + If the given string is large enough and has refcount of 1, it is not altered in any way. + Otherwise it is replaced by a copy that has enough space for the given number of characters, + data from the source string is copied to the beginning of it, the content of the remaining + capacity undefined, the string has refcount of 1, and refcount of the original string is decreased. + + @param str + pointer to the string. The pointed-to data must be a valid string. + + @param size + the number of characters + + @since LibreOffice 4.1 + @internal + */ +SAL_DLLPUBLIC void SAL_CALL rtl_string_ensureCapacity( rtl_String ** str, sal_Int32 size ) SAL_THROW_EXTERN_C(); + #ifdef __cplusplus } #endif diff --git a/sal/inc/rtl/ustring.h b/sal/inc/rtl/ustring.h index 0352e59b0e33..0548033f732c 100644 --- a/sal/inc/rtl/ustring.h +++ b/sal/inc/rtl/ustring.h @@ -1926,6 +1926,24 @@ SAL_DLLPUBLIC sal_Bool SAL_CALL rtl_convertStringToUString( rtl_uString ** target, char const * source, sal_Int32 length, rtl_TextEncoding encoding, sal_uInt32 flags) SAL_THROW_EXTERN_C(); +/** Ensure a string has enough space for a given number of characters. + + If the given string is large enough and has refcount of 1, it is not altered in any way. + Otherwise it is replaced by a copy that has enough space for the given number of characters, + data from the source string is copied to the beginning of it, the content of the remaining + capacity undefined, the string has refcount of 1, and refcount of the original string is decreased. + + @param str + pointer to the string. The pointed-to data must be a valid string. + + @param size + the number of characters + + @since LibreOffice 4.1 + @internal + */ +SAL_DLLPUBLIC void SAL_CALL rtl_uString_ensureCapacity( rtl_uString ** str, sal_Int32 size ) SAL_THROW_EXTERN_C(); + #ifdef __cplusplus } #endif 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); diff --git a/sal/rtl/source/strtmpl.cxx b/sal/rtl/source/strtmpl.cxx index 8001e0a250a7..afeb2db8ca60 100644 --- a/sal/rtl/source/strtmpl.cxx +++ b/sal/rtl/source/strtmpl.cxx @@ -1318,6 +1318,29 @@ void SAL_CALL IMPL_RTL_STRINGNAME( newConcat )( IMPL_RTL_STRINGDATA** ppThis, /* ----------------------------------------------------------------------- */ +void SAL_CALL IMPL_RTL_STRINGNAME( ensureCapacity )( IMPL_RTL_STRINGDATA** ppThis, + sal_Int32 size ) + SAL_THROW_EXTERN_C() +{ + IMPL_RTL_STRINGDATA* const pOrg = *ppThis; + if ( pOrg->refCount == 1 && pOrg->length >= size ) + return; + assert( pOrg->length <= size ); // do not truncate + IMPL_RTL_STRINGDATA* pTempStr = IMPL_RTL_STRINGNAME( ImplAlloc )( size ); + rtl_str_ImplCopy( pTempStr->buffer, pOrg->buffer, pOrg->length ); + // right now the length is still the same as of the original + pTempStr->length = pOrg->length; + pTempStr->buffer[ pOrg->length ] = '\0'; + *ppThis = pTempStr; + RTL_LOG_STRING_NEW( *ppThis ); + + /* must be done last, if pStr == *ppThis */ + if ( pOrg ) + IMPL_RTL_STRINGNAME( release )( pOrg ); +} + +/* ----------------------------------------------------------------------- */ + void SAL_CALL IMPL_RTL_STRINGNAME( newReplaceStrAt )( IMPL_RTL_STRINGDATA** ppThis, IMPL_RTL_STRINGDATA* pStr, sal_Int32 nIndex, diff --git a/sal/util/sal.map b/sal/util/sal.map index ade61cdaffc2..1eef9c6c3cb7 100644 --- a/sal/util/sal.map +++ b/sal/util/sal.map @@ -652,6 +652,12 @@ LIBO_UDK_4.0 { # symbols available in >= LibO 4.0 rtl_uString_newReplaceAllFromIndex; } LIBO_UDK_3.6; +LIBO_UDK_4.1 { # symbols available in >= LibO 4.1 + global: + rtl_string_ensureCapacity; + rtl_uString_ensureCapacity; +} LIBO_UDK_4.0; + PRIVATE_1.0 { global: osl_detail_ObjectRegistry_storeAddresses; -- cgit