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;