summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authortsepez <tsepez@chromium.org>2016-04-26 12:13:16 -0700
committerCommit bot <commit-bot@chromium.org>2016-04-26 12:13:16 -0700
commit518fd4c5ababbfbf28e010a9c27098e8f6669e4b (patch)
tree79e20cf56d24f2aaf9463056ccb52803426be082 /core
parent5cc24654fb345189140acb4711ff981e1c720951 (diff)
downloadpdfium-518fd4c5ababbfbf28e010a9c27098e8f6669e4b.tar.xz
CFX_ByteString::Reserve(), ReleaseBuffer() fixes.
Also identical fixes for CFX_WideString. Reserve() on an empty string would not actually reserve a buffer. Currently unused, but there are places where this would really help. ReleaseBuffer() would rarely return memory to the system, since it would short-circuit thinking it could operate in place. Tune the algorithm slightly so that we hold on when the savings is small. Bounds check release buffer args rather than just asserting. Add tests for all of these. Review URL: https://codereview.chromium.org/1916303004
Diffstat (limited to 'core')
-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;