summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/fxcrt/fx_basic_bstring.cpp11
-rw-r--r--core/fxcrt/fx_basic_bstring_unittest.cpp77
-rw-r--r--core/fxcrt/fx_basic_wstring.cpp11
-rw-r--r--core/fxcrt/fx_basic_wstring_unittest.cpp77
4 files changed, 170 insertions, 6 deletions
diff --git a/core/fxcrt/fx_basic_bstring.cpp b/core/fxcrt/fx_basic_bstring.cpp
index 1622c4bc55..e098d8fe50 100644
--- a/core/fxcrt/fx_basic_bstring.cpp
+++ b/core/fxcrt/fx_basic_bstring.cpp
@@ -276,20 +276,25 @@ void CFX_ByteString::ReleaseBuffer(FX_STRSIZE nNewLength) {
if (nNewLength == -1)
nNewLength = FXSYS_strlen(m_pData->m_String);
+ nNewLength = std::min(nNewLength, m_pData->m_nAllocLength);
if (nNewLength == 0) {
clear();
return;
}
- FXSYS_assert(nNewLength <= m_pData->m_nAllocLength);
- ReallocBeforeWrite(nNewLength);
+ FXSYS_assert(m_pData->m_nRefs == 1);
m_pData->m_nDataLength = nNewLength;
m_pData->m_String[nNewLength] = 0;
+ if (m_pData->m_nAllocLength - nNewLength >= 32) {
+ // Over arbitrary threshold, so pay the price to relocate. Force copy to
+ // always occur by holding a second reference to the string.
+ CFX_ByteString preserve(*this);
+ ReallocBeforeWrite(nNewLength);
+ }
}
void CFX_ByteString::Reserve(FX_STRSIZE len) {
GetBuffer(len);
- ReleaseBuffer(GetLength());
}
FX_CHAR* CFX_ByteString::GetBuffer(FX_STRSIZE nMinBufLength) {
diff --git a/core/fxcrt/fx_basic_bstring_unittest.cpp b/core/fxcrt/fx_basic_bstring_unittest.cpp
index ea7e17f1f1..087c264940 100644
--- a/core/fxcrt/fx_basic_bstring_unittest.cpp
+++ b/core/fxcrt/fx_basic_bstring_unittest.cpp
@@ -624,6 +624,83 @@ TEST(fxcrt, ByteStringTrimLeftCopies) {
}
}
+TEST(fxcrt, ByteStringReserve) {
+ {
+ CFX_ByteString str;
+ str.Reserve(6);
+ const FX_CHAR* old_buffer = str.c_str();
+ str += "ABCDEF";
+ EXPECT_EQ(old_buffer, str.c_str());
+ str += "Blah Blah Blah Blah Blah Blah";
+ EXPECT_NE(old_buffer, str.c_str());
+ }
+ {
+ CFX_ByteString str("A");
+ str.Reserve(6);
+ const FX_CHAR* old_buffer = str.c_str();
+ str += "BCDEF";
+ EXPECT_EQ(old_buffer, str.c_str());
+ str += "Blah Blah Blah Blah Blah Blah";
+ EXPECT_NE(old_buffer, str.c_str());
+ }
+}
+
+TEST(fxcrt, ByteStringGetBuffer) {
+ {
+ CFX_ByteString str;
+ FX_CHAR* buffer = str.GetBuffer(12);
+ strcpy(buffer, "clams");
+ str.ReleaseBuffer();
+ EXPECT_EQ("clams", str);
+ }
+ {
+ CFX_ByteString str("cl");
+ FX_CHAR* buffer = str.GetBuffer(12);
+ strcpy(buffer + 2, "ams");
+ str.ReleaseBuffer();
+ EXPECT_EQ("clams", str);
+ }
+}
+
+TEST(fxcrt, ByteStringReleaseBuffer) {
+ {
+ CFX_ByteString str;
+ str.Reserve(12);
+ str += "clams";
+ const FX_CHAR* old_buffer = str.c_str();
+ str.ReleaseBuffer(4);
+ EXPECT_EQ(old_buffer, str.c_str());
+ EXPECT_EQ("clam", str);
+ }
+ {
+ CFX_ByteString str("c");
+ str.Reserve(12);
+ str += "lams";
+ const FX_CHAR* old_buffer = str.c_str();
+ str.ReleaseBuffer(4);
+ EXPECT_EQ(old_buffer, str.c_str());
+ EXPECT_EQ("clam", str);
+ }
+ {
+ CFX_ByteString str;
+ str.Reserve(200);
+ str += "clams";
+ const FX_CHAR* old_buffer = str.c_str();
+ str.ReleaseBuffer(4);
+ EXPECT_NE(old_buffer, str.c_str());
+ EXPECT_EQ("clam", str);
+ }
+ {
+ CFX_ByteString str("c");
+ str.Reserve(200);
+ str += "lams";
+ const FX_CHAR* old_buffer = str.c_str();
+ str.ReleaseBuffer(4);
+ EXPECT_NE(old_buffer, str.c_str());
+ EXPECT_EQ("clam", str);
+ }
+}
+
TEST(fxcrt, ByteStringCNotNull) {
CFX_ByteStringC string3("abc");
CFX_ByteStringC string6("abcdef");
diff --git a/core/fxcrt/fx_basic_wstring.cpp b/core/fxcrt/fx_basic_wstring.cpp
index f3b430c7bf..38fd15e13f 100644
--- a/core/fxcrt/fx_basic_wstring.cpp
+++ b/core/fxcrt/fx_basic_wstring.cpp
@@ -224,20 +224,25 @@ void CFX_WideString::ReleaseBuffer(FX_STRSIZE nNewLength) {
if (nNewLength == -1)
nNewLength = FXSYS_wcslen(m_pData->m_String);
+ nNewLength = std::min(nNewLength, m_pData->m_nAllocLength);
if (nNewLength == 0) {
clear();
return;
}
- FXSYS_assert(nNewLength <= m_pData->m_nAllocLength);
- ReallocBeforeWrite(nNewLength);
+ FXSYS_assert(m_pData->m_nRefs == 1);
m_pData->m_nDataLength = nNewLength;
m_pData->m_String[nNewLength] = 0;
+ if (m_pData->m_nAllocLength - nNewLength >= 32) {
+ // Over arbitrary threshold, so pay the price to relocate. Force copy to
+ // always occur by holding a second reference to the string.
+ CFX_WideString preserve(*this);
+ ReallocBeforeWrite(nNewLength);
+ }
}
void CFX_WideString::Reserve(FX_STRSIZE len) {
GetBuffer(len);
- ReleaseBuffer(GetLength());
}
FX_WCHAR* CFX_WideString::GetBuffer(FX_STRSIZE nMinBufLength) {
diff --git a/core/fxcrt/fx_basic_wstring_unittest.cpp b/core/fxcrt/fx_basic_wstring_unittest.cpp
index 708556af1d..02281afd36 100644
--- a/core/fxcrt/fx_basic_wstring_unittest.cpp
+++ b/core/fxcrt/fx_basic_wstring_unittest.cpp
@@ -591,6 +591,83 @@ TEST(fxcrt, WideStringTrimLeftCopies) {
}
}
+TEST(fxcrt, WideStringReserve) {
+ {
+ CFX_WideString str;
+ str.Reserve(6);
+ const FX_WCHAR* old_buffer = str.c_str();
+ str += L"ABCDEF";
+ EXPECT_EQ(old_buffer, str.c_str());
+ str += L"Blah Blah Blah Blah Blah Blah";
+ EXPECT_NE(old_buffer, str.c_str());
+ }
+ {
+ CFX_WideString str(L"A");
+ str.Reserve(6);
+ const FX_WCHAR* old_buffer = str.c_str();
+ str += L"BCDEF";
+ EXPECT_EQ(old_buffer, str.c_str());
+ str += L"Blah Blah Blah Blah Blah Blah";
+ EXPECT_NE(old_buffer, str.c_str());
+ }
+}
+
+TEST(fxcrt, WideStringGetBuffer) {
+ {
+ CFX_WideString str;
+ FX_WCHAR* buffer = str.GetBuffer(12);
+ wcscpy(buffer, L"clams");
+ str.ReleaseBuffer();
+ EXPECT_EQ(L"clams", str);
+ }
+ {
+ CFX_WideString str(L"cl");
+ FX_WCHAR* buffer = str.GetBuffer(12);
+ wcscpy(buffer + 2, L"ams");
+ str.ReleaseBuffer();
+ EXPECT_EQ(L"clams", str);
+ }
+}
+
+TEST(fxcrt, WideStringReleaseBuffer) {
+ {
+ CFX_WideString str;
+ str.Reserve(12);
+ str += L"clams";
+ const FX_WCHAR* old_buffer = str.c_str();
+ str.ReleaseBuffer(4);
+ EXPECT_EQ(old_buffer, str.c_str());
+ EXPECT_EQ(L"clam", str);
+ }
+ {
+ CFX_WideString str(L"c");
+ str.Reserve(12);
+ str += L"lams";
+ const FX_WCHAR* old_buffer = str.c_str();
+ str.ReleaseBuffer(4);
+ EXPECT_EQ(old_buffer, str.c_str());
+ EXPECT_EQ(L"clam", str);
+ }
+ {
+ CFX_WideString str;
+ str.Reserve(200);
+ str += L"clams";
+ const FX_WCHAR* old_buffer = str.c_str();
+ str.ReleaseBuffer(4);
+ EXPECT_NE(old_buffer, str.c_str());
+ EXPECT_EQ(L"clam", str);
+ }
+ {
+ CFX_WideString str(L"c");
+ str.Reserve(200);
+ str += L"lams";
+ const FX_WCHAR* old_buffer = str.c_str();
+ str.ReleaseBuffer(4);
+ EXPECT_NE(old_buffer, str.c_str());
+ EXPECT_EQ(L"clam", str);
+ }
+}
+
TEST(fxcrt, WideStringUTF16LE_Encode) {
struct UTF16LEEncodeCase {
CFX_WideString ws;