Place common code for byte/wide strings in StringTemplate.
Initially, the bytestring and widestring code was quite divergent,
but over time portions of it have become identical apart from type.
-- Remove one duplicate instantiation of extern template class.
Change-Id: I0f42909b0f597fe05269e729c0233910721267a5
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/116410
Reviewed-by: Thomas Sepez <tsepez@google.com>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
diff --git a/core/fxcrt/BUILD.gn b/core/fxcrt/BUILD.gn
index ddebda5..c05196f 100644
--- a/core/fxcrt/BUILD.gn
+++ b/core/fxcrt/BUILD.gn
@@ -90,6 +90,8 @@
"string_data_template.cpp",
"string_data_template.h",
"string_pool_template.h",
+ "string_template.cpp",
+ "string_template.h",
"string_view_template.h",
"tree_node.h",
"unowned_ptr.h",
diff --git a/core/fxcrt/bytestring.cpp b/core/fxcrt/bytestring.cpp
index 83109fe..bff4b3c 100644
--- a/core/fxcrt/bytestring.cpp
+++ b/core/fxcrt/bytestring.cpp
@@ -25,7 +25,7 @@
#include "third_party/base/check_op.h"
#include "third_party/base/containers/span.h"
-template class fxcrt::StringDataTemplate<char>;
+// Instantiate.
template class fxcrt::StringViewTemplate<char>;
template class fxcrt::StringPoolTemplate<ByteString>;
template struct std::hash<ByteString>;
@@ -159,14 +159,6 @@
ByteString::~ByteString() = default;
-void ByteString::clear() {
- if (m_pData && m_pData->CanOperateInPlace(0)) {
- m_pData->m_nDataLength = 0;
- return;
- }
- m_pData.Reset();
-}
-
ByteString& ByteString::operator=(const char* str) {
if (!str || !str[0])
clear();
@@ -310,44 +302,6 @@
return true;
}
-void ByteString::AssignCopy(const char* pSrcData, size_t nSrcLen) {
- AllocBeforeWrite(nSrcLen);
- m_pData->CopyContents({pSrcData, nSrcLen});
- m_pData->m_nDataLength = nSrcLen;
-}
-
-void ByteString::ReallocBeforeWrite(size_t nNewLength) {
- if (m_pData && m_pData->CanOperateInPlace(nNewLength))
- return;
-
- if (nNewLength == 0) {
- clear();
- return;
- }
-
- RetainPtr<StringData> pNewData = StringData::Create(nNewLength);
- if (m_pData) {
- size_t nCopyLength = std::min(m_pData->m_nDataLength, nNewLength);
- pNewData->CopyContents({m_pData->m_String, nCopyLength});
- pNewData->m_nDataLength = nCopyLength;
- } else {
- pNewData->m_nDataLength = 0;
- }
- pNewData->m_String[pNewData->m_nDataLength] = 0;
- m_pData = std::move(pNewData);
-}
-
-void ByteString::AllocBeforeWrite(size_t nNewLength) {
- if (m_pData && m_pData->CanOperateInPlace(nNewLength)) {
- return;
- }
- if (nNewLength == 0) {
- clear();
- return;
- }
- m_pData = StringData::Create(nNewLength);
-}
-
void ByteString::ReleaseBuffer(size_t nNewLength) {
if (!m_pData)
return;
@@ -419,30 +373,6 @@
return m_pData->m_nDataLength;
}
-void ByteString::Concat(const char* pSrcData, size_t nSrcLen) {
- if (!pSrcData || nSrcLen == 0)
- return;
-
- if (!m_pData) {
- m_pData = StringData::Create({pSrcData, nSrcLen});
- return;
- }
-
- if (m_pData->CanOperateInPlace(m_pData->m_nDataLength + nSrcLen)) {
- m_pData->CopyContentsAt(m_pData->m_nDataLength, {pSrcData, nSrcLen});
- m_pData->m_nDataLength += nSrcLen;
- return;
- }
-
- size_t nConcatLen = std::max(m_pData->m_nDataLength / 2, nSrcLen);
- RetainPtr<StringData> pNewData =
- StringData::Create(m_pData->m_nDataLength + nConcatLen);
- pNewData->CopyContents(*m_pData);
- pNewData->CopyContentsAt(m_pData->m_nDataLength, {pSrcData, nSrcLen});
- pNewData->m_nDataLength = m_pData->m_nDataLength + nSrcLen;
- m_pData = std::move(pNewData);
-}
-
intptr_t ByteString::ReferenceCountForTesting() const {
return m_pData ? m_pData->m_nRefs : 0;
}
diff --git a/core/fxcrt/bytestring.h b/core/fxcrt/bytestring.h
index f9ace48..a5a33dc 100644
--- a/core/fxcrt/bytestring.h
+++ b/core/fxcrt/bytestring.h
@@ -21,6 +21,7 @@
#include "core/fxcrt/fx_string_wrappers.h"
#include "core/fxcrt/retain_ptr.h"
#include "core/fxcrt/string_data_template.h"
+#include "core/fxcrt/string_template.h"
#include "core/fxcrt/string_view_template.h"
#include "third_party/base/check.h"
#include "third_party/base/containers/span.h"
@@ -29,12 +30,8 @@
// A mutable string with shared buffers using copy-on-write semantics that
// avoids the cost of std::string's iterator stability guarantees.
-class ByteString {
+class ByteString : public StringTemplate<char> {
public:
- using CharType = char;
- using const_iterator = const CharType*;
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
-
[[nodiscard]] static ByteString FormatInteger(int i);
[[nodiscard]] static ByteString FormatFloat(float f);
[[nodiscard]] static ByteString Format(const char* pFormat, ...);
@@ -67,10 +64,6 @@
~ByteString();
- // Holds on to buffer if possible for later re-use. Assign ByteString()
- // to force immediate release if desired.
- void clear();
-
// Explicit conversion to C-style string. The result is never nullptr,
// and is always NUL terminated.
// Note: Any subsequent modification of |this| will invalidate the result.
@@ -222,16 +215,8 @@
uint32_t GetID() const { return AsStringView().GetID(); }
protected:
- using StringData = StringDataTemplate<char>;
-
- void ReallocBeforeWrite(size_t nNewLen);
- void AllocBeforeWrite(size_t nNewLen);
- void AssignCopy(const char* pSrcData, size_t nSrcLen);
- void Concat(const char* pSrcData, size_t nSrcLen);
intptr_t ReferenceCountForTesting() const;
- RetainPtr<StringData> m_pData;
-
friend class ByteString_Assign_Test;
friend class ByteString_Concat_Test;
friend class ByteString_Construct_Test;
diff --git a/core/fxcrt/string_data_template.cpp b/core/fxcrt/string_data_template.cpp
index fb5c3c4..8b418a5 100644
--- a/core/fxcrt/string_data_template.cpp
+++ b/core/fxcrt/string_data_template.cpp
@@ -91,6 +91,7 @@
m_String[dataLen] = 0;
}
+// Instantiate.
template class StringDataTemplate<char>;
template class StringDataTemplate<wchar_t>;
diff --git a/core/fxcrt/string_template.cpp b/core/fxcrt/string_template.cpp
new file mode 100644
index 0000000..85fd480
--- /dev/null
+++ b/core/fxcrt/string_template.cpp
@@ -0,0 +1,99 @@
+// Copyright 2024 The PDFium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "core/fxcrt/string_template.h"
+
+#include <algorithm>
+#include <utility>
+
+#include "core/fxcrt/span_util.h"
+#include "third_party/base/check.h"
+#include "third_party/base/check_op.h"
+#include "third_party/base/containers/span.h"
+
+namespace fxcrt {
+
+template <typename T>
+void StringTemplate<T>::ReallocBeforeWrite(size_t nNewLength) {
+ if (m_pData && m_pData->CanOperateInPlace(nNewLength)) {
+ return;
+ }
+ if (nNewLength == 0) {
+ clear();
+ return;
+ }
+
+ RetainPtr<StringData> pNewData = StringData::Create(nNewLength);
+ if (m_pData) {
+ size_t nCopyLength = std::min(m_pData->m_nDataLength, nNewLength);
+ pNewData->CopyContents({m_pData->m_String, nCopyLength});
+ pNewData->m_nDataLength = nCopyLength;
+ } else {
+ pNewData->m_nDataLength = 0;
+ }
+ pNewData->m_String[pNewData->m_nDataLength] = 0;
+ m_pData = std::move(pNewData);
+}
+
+template <typename T>
+void StringTemplate<T>::AllocBeforeWrite(size_t nNewLength) {
+ if (m_pData && m_pData->CanOperateInPlace(nNewLength)) {
+ return;
+ }
+ if (nNewLength == 0) {
+ clear();
+ return;
+ }
+ m_pData = StringData::Create(nNewLength);
+}
+
+template <typename T>
+void StringTemplate<T>::AssignCopy(const T* pSrcData, size_t nSrcLen) {
+ AllocBeforeWrite(nSrcLen);
+ m_pData->CopyContents({pSrcData, nSrcLen});
+ m_pData->m_nDataLength = nSrcLen;
+}
+
+template <typename T>
+void StringTemplate<T>::Concat(const T* pSrcData, size_t nSrcLen) {
+ if (!pSrcData || nSrcLen == 0) {
+ return;
+ }
+
+ if (!m_pData) {
+ m_pData = StringData::Create({pSrcData, nSrcLen});
+ return;
+ }
+
+ if (m_pData->CanOperateInPlace(m_pData->m_nDataLength + nSrcLen)) {
+ m_pData->CopyContentsAt(m_pData->m_nDataLength, {pSrcData, nSrcLen});
+ m_pData->m_nDataLength += nSrcLen;
+ return;
+ }
+
+ size_t nConcatLen = std::max(m_pData->m_nDataLength / 2, nSrcLen);
+ RetainPtr<StringData> pNewData =
+ StringData::Create(m_pData->m_nDataLength + nConcatLen);
+ pNewData->CopyContents(*m_pData);
+ pNewData->CopyContentsAt(m_pData->m_nDataLength, {pSrcData, nSrcLen});
+ pNewData->m_nDataLength = m_pData->m_nDataLength + nSrcLen;
+ m_pData = std::move(pNewData);
+}
+
+template <typename T>
+void StringTemplate<T>::clear() {
+ if (m_pData && m_pData->CanOperateInPlace(0)) {
+ m_pData->m_nDataLength = 0;
+ return;
+ }
+ m_pData.Reset();
+}
+
+// Instantiate.
+template class StringTemplate<char>;
+template class StringTemplate<wchar_t>;
+
+} // namespace fxcrt
diff --git a/core/fxcrt/string_template.h b/core/fxcrt/string_template.h
new file mode 100644
index 0000000..51be807
--- /dev/null
+++ b/core/fxcrt/string_template.h
@@ -0,0 +1,48 @@
+// Copyright 2024 The PDFium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#ifndef CORE_FXCRT_STRING_TEMPLATE_H_
+#define CORE_FXCRT_STRING_TEMPLATE_H_
+
+#include <stddef.h>
+
+#include "core/fxcrt/retain_ptr.h"
+#include "core/fxcrt/string_data_template.h"
+#include "core/fxcrt/string_view_template.h"
+
+namespace fxcrt {
+
+// Base class for a mutable string with shared buffers using copy-on-write
+// semantics that avoids std::string's iterator stability guarantees.
+template <typename T>
+class StringTemplate {
+ public:
+ using CharType = T;
+ using const_iterator = T*;
+ using const_reverse_iterator = std::reverse_iterator<const_iterator>;
+
+ // Holds on to buffer if possible for later re-use. Use assignment
+ // to force immediate release if desired.
+ void clear();
+
+ protected:
+ using StringView = StringViewTemplate<T>;
+ using StringData = StringDataTemplate<T>;
+
+ void ReallocBeforeWrite(size_t nNewLen);
+ void AllocBeforeWrite(size_t nNewLen);
+ void AssignCopy(const T* pSrcData, size_t nSrcLen);
+ void Concat(const T* pSrcData, size_t nSrcLen);
+
+ RetainPtr<StringData> m_pData;
+};
+
+extern template class StringTemplate<char>;
+extern template class StringTemplate<wchar_t>;
+
+} // namespace fxcrt
+
+#endif // CORE_FXCRT_STRING_TEMPLATE_H_
diff --git a/core/fxcrt/widestring.cpp b/core/fxcrt/widestring.cpp
index a4bcdd8..a9cd10b 100644
--- a/core/fxcrt/widestring.cpp
+++ b/core/fxcrt/widestring.cpp
@@ -24,7 +24,7 @@
#include "third_party/base/check_op.h"
#include "third_party/base/numerics/safe_math.h"
-template class fxcrt::StringDataTemplate<wchar_t>;
+// Instantiate.
template class fxcrt::StringViewTemplate<wchar_t>;
template class fxcrt::StringPoolTemplate<WideString>;
template struct std::hash<WideString>;
@@ -443,14 +443,6 @@
WideString::~WideString() = default;
-void WideString::clear() {
- if (m_pData && m_pData->CanOperateInPlace(0)) {
- m_pData->m_nDataLength = 0;
- return;
- }
- m_pData.Reset();
-}
-
WideString& WideString::operator=(const wchar_t* str) {
if (!str || !str[0])
clear();
@@ -565,45 +557,6 @@
return Compare(other) < 0;
}
-void WideString::AssignCopy(const wchar_t* pSrcData, size_t nSrcLen) {
- AllocBeforeWrite(nSrcLen);
- m_pData->CopyContents({pSrcData, nSrcLen});
- m_pData->m_nDataLength = nSrcLen;
-}
-
-void WideString::ReallocBeforeWrite(size_t nNewLength) {
- if (m_pData && m_pData->CanOperateInPlace(nNewLength))
- return;
-
- if (nNewLength == 0) {
- clear();
- return;
- }
-
- RetainPtr<StringData> pNewData = StringData::Create(nNewLength);
- if (m_pData) {
- size_t nCopyLength = std::min(m_pData->m_nDataLength, nNewLength);
- pNewData->CopyContents({m_pData->m_String, nCopyLength});
- pNewData->m_nDataLength = nCopyLength;
- } else {
- pNewData->m_nDataLength = 0;
- }
- pNewData->m_String[pNewData->m_nDataLength] = 0;
- m_pData = std::move(pNewData);
-}
-
-void WideString::AllocBeforeWrite(size_t nNewLength) {
- if (m_pData && m_pData->CanOperateInPlace(nNewLength))
- return;
-
- if (nNewLength == 0) {
- clear();
- return;
- }
-
- m_pData = StringData::Create(nNewLength);
-}
-
void WideString::ReleaseBuffer(size_t nNewLength) {
if (!m_pData)
return;
@@ -675,30 +628,6 @@
return m_pData->m_nDataLength;
}
-void WideString::Concat(const wchar_t* pSrcData, size_t nSrcLen) {
- if (!pSrcData || nSrcLen == 0)
- return;
-
- if (!m_pData) {
- m_pData = StringData::Create({pSrcData, nSrcLen});
- return;
- }
-
- if (m_pData->CanOperateInPlace(m_pData->m_nDataLength + nSrcLen)) {
- m_pData->CopyContentsAt(m_pData->m_nDataLength, {pSrcData, nSrcLen});
- m_pData->m_nDataLength += nSrcLen;
- return;
- }
-
- size_t nConcatLen = std::max(m_pData->m_nDataLength / 2, nSrcLen);
- RetainPtr<StringData> pNewData =
- StringData::Create(m_pData->m_nDataLength + nConcatLen);
- pNewData->CopyContents(*m_pData);
- pNewData->CopyContentsAt(m_pData->m_nDataLength, {pSrcData, nSrcLen});
- pNewData->m_nDataLength = m_pData->m_nDataLength + nSrcLen;
- m_pData = std::move(pNewData);
-}
-
intptr_t WideString::ReferenceCountForTesting() const {
return m_pData ? m_pData->m_nRefs : 0;
}
diff --git a/core/fxcrt/widestring.h b/core/fxcrt/widestring.h
index ae79e11..3d199fd 100644
--- a/core/fxcrt/widestring.h
+++ b/core/fxcrt/widestring.h
@@ -20,6 +20,7 @@
#include "core/fxcrt/retain_ptr.h"
#include "core/fxcrt/string_data_template.h"
+#include "core/fxcrt/string_template.h"
#include "core/fxcrt/string_view_template.h"
#include "third_party/base/check.h"
#include "third_party/base/containers/span.h"
@@ -30,13 +31,9 @@
// A mutable string with shared buffers using copy-on-write semantics that
// avoids the cost of std::string's iterator stability guarantees.
-class WideString {
+// TODO(crbug.com/pdfium/2031): Consider switching to `char16_t` instead.
+class WideString : public StringTemplate<wchar_t> {
public:
- // TODO(crbug.com/pdfium/2031): Consider switching to `char16_t` instead.
- using CharType = wchar_t;
- using const_iterator = const CharType*;
- using const_reverse_iterator = std::reverse_iterator<const_iterator>;
-
[[nodiscard]] static WideString FormatInteger(int i);
[[nodiscard]] static WideString Format(const wchar_t* pFormat, ...);
[[nodiscard]] static WideString FormatV(const wchar_t* lpszFormat,
@@ -108,10 +105,6 @@
return const_reverse_iterator(begin());
}
- // Holds on to buffer if possible for later re-use. Assign WideString()
- // to force immediate release if desired.
- void clear();
-
size_t GetLength() const { return m_pData ? m_pData->m_nDataLength : 0; }
size_t GetStringLength() const {
return m_pData ? wcslen(m_pData->m_String) : 0;
@@ -241,16 +234,8 @@
WideString EncodeEntities() const;
protected:
- using StringData = StringDataTemplate<wchar_t>;
-
- void ReallocBeforeWrite(size_t nNewLength);
- void AllocBeforeWrite(size_t nNewLength);
- void AssignCopy(const wchar_t* pSrcData, size_t nSrcLen);
- void Concat(const wchar_t* pSrcData, size_t nSrcLen);
intptr_t ReferenceCountForTesting() const;
- RetainPtr<StringData> m_pData;
-
friend class WideString_Assign_Test;
friend class WideString_ConcatInPlace_Test;
friend class WideString_Construct_Test;