summaryrefslogtreecommitdiff
path: root/core/fxcrt
diff options
context:
space:
mode:
Diffstat (limited to 'core/fxcrt')
-rw-r--r--core/fxcrt/fx_basic_bstring.cpp17
-rw-r--r--core/fxcrt/fx_basic_bstring_unittest.cpp29
-rw-r--r--core/fxcrt/fx_basic_wstring.cpp17
-rw-r--r--core/fxcrt/fx_basic_wstring_unittest.cpp29
4 files changed, 88 insertions, 4 deletions
diff --git a/core/fxcrt/fx_basic_bstring.cpp b/core/fxcrt/fx_basic_bstring.cpp
index 4a48539578..23fdcaa25e 100644
--- a/core/fxcrt/fx_basic_bstring.cpp
+++ b/core/fxcrt/fx_basic_bstring.cpp
@@ -719,17 +719,30 @@ FX_STRSIZE CFX_ByteString::Remove(FX_CHAR chRemove) {
if (!m_pData || m_pData->m_nDataLength < 1)
return 0;
- ReallocBeforeWrite(m_pData->m_nDataLength);
FX_CHAR* pstrSource = m_pData->m_String;
- FX_CHAR* pstrDest = m_pData->m_String;
FX_CHAR* pstrEnd = m_pData->m_String + m_pData->m_nDataLength;
while (pstrSource < pstrEnd) {
+ if (*pstrSource == chRemove)
+ break;
+ pstrSource++;
+ }
+ if (pstrSource == pstrEnd)
+ return 0;
+
+ ptrdiff_t copied = pstrSource - m_pData->m_String;
+ ReallocBeforeWrite(m_pData->m_nDataLength);
+ pstrSource = m_pData->m_String + copied;
+ pstrEnd = m_pData->m_String + m_pData->m_nDataLength;
+
+ FX_CHAR* pstrDest = pstrSource;
+ while (pstrSource < pstrEnd) {
if (*pstrSource != chRemove) {
*pstrDest = *pstrSource;
pstrDest++;
}
pstrSource++;
}
+
*pstrDest = 0;
FX_STRSIZE nCount = (FX_STRSIZE)(pstrSource - pstrDest);
m_pData->m_nDataLength -= nCount;
diff --git a/core/fxcrt/fx_basic_bstring_unittest.cpp b/core/fxcrt/fx_basic_bstring_unittest.cpp
index 8c72b2a054..ea7e17f1f1 100644
--- a/core/fxcrt/fx_basic_bstring_unittest.cpp
+++ b/core/fxcrt/fx_basic_bstring_unittest.cpp
@@ -333,6 +333,35 @@ TEST(fxcrt, ByteStringRemove) {
EXPECT_EQ("", empty);
}
+TEST(fxcrt, ByteStringRemoveCopies) {
+ CFX_ByteString freed("FREED");
+ const FX_CHAR* old_buffer = freed.c_str();
+
+ // No change with single reference - no copy.
+ freed.Remove('Q');
+ EXPECT_EQ("FREED", freed);
+ EXPECT_EQ(old_buffer, freed.c_str());
+
+ // Change with single reference - no copy.
+ freed.Remove('E');
+ EXPECT_EQ("FRD", freed);
+ EXPECT_EQ(old_buffer, freed.c_str());
+
+ // No change with multiple references - no copy.
+ CFX_ByteString shared(freed);
+ freed.Remove('Q');
+ EXPECT_EQ("FRD", freed);
+ EXPECT_EQ(old_buffer, freed.c_str());
+ EXPECT_EQ(old_buffer, shared.c_str());
+
+ // Change with multiple references -- must copy.
+ freed.Remove('D');
+ EXPECT_EQ("FR", freed);
+ EXPECT_NE(old_buffer, freed.c_str());
+ EXPECT_EQ("FRD", shared);
+ EXPECT_EQ(old_buffer, shared.c_str());
+}
+
TEST(fxcrt, ByteStringReplace) {
CFX_ByteString fred("FRED");
fred.Replace("FR", "BL");
diff --git a/core/fxcrt/fx_basic_wstring.cpp b/core/fxcrt/fx_basic_wstring.cpp
index 08a9d212d4..069b9fa42d 100644
--- a/core/fxcrt/fx_basic_wstring.cpp
+++ b/core/fxcrt/fx_basic_wstring.cpp
@@ -672,17 +672,30 @@ FX_STRSIZE CFX_WideString::Remove(FX_WCHAR chRemove) {
if (!m_pData || m_pData->m_nDataLength < 1)
return 0;
- ReallocBeforeWrite(m_pData->m_nDataLength);
FX_WCHAR* pstrSource = m_pData->m_String;
- FX_WCHAR* pstrDest = m_pData->m_String;
FX_WCHAR* pstrEnd = m_pData->m_String + m_pData->m_nDataLength;
while (pstrSource < pstrEnd) {
+ if (*pstrSource == chRemove)
+ break;
+ pstrSource++;
+ }
+ if (pstrSource == pstrEnd)
+ return 0;
+
+ ptrdiff_t copied = pstrSource - m_pData->m_String;
+ ReallocBeforeWrite(m_pData->m_nDataLength);
+ pstrSource = m_pData->m_String + copied;
+ pstrEnd = m_pData->m_String + m_pData->m_nDataLength;
+
+ FX_WCHAR* pstrDest = pstrSource;
+ while (pstrSource < pstrEnd) {
if (*pstrSource != chRemove) {
*pstrDest = *pstrSource;
pstrDest++;
}
pstrSource++;
}
+
*pstrDest = 0;
FX_STRSIZE nCount = (FX_STRSIZE)(pstrSource - pstrDest);
m_pData->m_nDataLength -= nCount;
diff --git a/core/fxcrt/fx_basic_wstring_unittest.cpp b/core/fxcrt/fx_basic_wstring_unittest.cpp
index bc38141a95..708556af1d 100644
--- a/core/fxcrt/fx_basic_wstring_unittest.cpp
+++ b/core/fxcrt/fx_basic_wstring_unittest.cpp
@@ -294,6 +294,35 @@ TEST(fxcrt, WideStringRemove) {
EXPECT_EQ(L"", empty);
}
+TEST(fxcrt, WideStringRemoveCopies) {
+ CFX_WideString freed(L"FREED");
+ const FX_WCHAR* old_buffer = freed.c_str();
+
+ // No change with single reference - no copy.
+ freed.Remove(L'Q');
+ EXPECT_EQ(L"FREED", freed);
+ EXPECT_EQ(old_buffer, freed.c_str());
+
+ // Change with single reference - no copy.
+ freed.Remove(L'E');
+ EXPECT_EQ(L"FRD", freed);
+ EXPECT_EQ(old_buffer, freed.c_str());
+
+ // No change with multiple references - no copy.
+ CFX_WideString shared(freed);
+ freed.Remove(L'Q');
+ EXPECT_EQ(L"FRD", freed);
+ EXPECT_EQ(old_buffer, freed.c_str());
+ EXPECT_EQ(old_buffer, shared.c_str());
+
+ // Change with multiple references -- must copy.
+ freed.Remove(L'D');
+ EXPECT_EQ(L"FR", freed);
+ EXPECT_NE(old_buffer, freed.c_str());
+ EXPECT_EQ(L"FRD", shared);
+ EXPECT_EQ(old_buffer, shared.c_str());
+}
+
TEST(fxcrt, WideStringReplace) {
CFX_WideString fred(L"FRED");
fred.Replace(L"FR", L"BL");