summaryrefslogtreecommitdiff
path: root/sal
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@suse.cz>2012-12-04 19:27:34 +0100
committerLuboš Luňák <l.lunak@suse.cz>2012-12-06 13:35:17 +0100
commitb88a26f02276ec2e98287cd2e5f2abea1ea9e949 (patch)
tree42997756a94ee8bf4614f01a19994927783660e7 /sal
parent5c61b8e87b6a8cda82a0857fdae4d2b2215552fb (diff)
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
Diffstat (limited to 'sal')
-rw-r--r--sal/inc/rtl/string.h18
-rw-r--r--sal/inc/rtl/ustring.h18
-rw-r--r--sal/qa/rtl/strings/test_ostring_concat.cxx40
-rw-r--r--sal/qa/rtl/strings/test_oustring_concat.cxx45
-rw-r--r--sal/rtl/source/strtmpl.cxx23
-rw-r--r--sal/util/sal.map6
6 files changed, 150 insertions, 0 deletions
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;