Move even more code still into StringTemplate.

Put most accessors in the type-agnostic file, along with Remove().
Most of the remaining methods have dependencies on specific functions
that have not been generalized against character types.


Change-Id: I82d4af59add3959760f209feaf28c13f56f55032
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/116431
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Tom Sepez <tsepez@chromium.org>
Reviewed-by: Thomas Sepez <tsepez@google.com>
diff --git a/core/fxcrt/bytestring.cpp b/core/fxcrt/bytestring.cpp
index 2dae0d0..f1c5dec 100644
--- a/core/fxcrt/bytestring.cpp
+++ b/core/fxcrt/bytestring.cpp
@@ -99,12 +99,6 @@
 ByteString::ByteString(const uint8_t* pStr, size_t nLen)
     : ByteString(reinterpret_cast<const char*>(pStr), nLen) {}
 
-ByteString::ByteString() = default;
-
-ByteString::ByteString(const ByteString& other) = default;
-
-ByteString::ByteString(ByteString&& other) noexcept = default;
-
 ByteString::ByteString(char ch) {
   m_pData = StringData::Create(1);
   m_pData->m_String[0] = ch;
@@ -157,8 +151,6 @@
   }
 }
 
-ByteString::~ByteString() = default;
-
 ByteString& ByteString::operator=(const char* str) {
   if (!str || !str[0])
     clear();
@@ -433,40 +425,6 @@
   FXSYS_strupr(m_pData->m_String);
 }
 
-size_t ByteString::Remove(char chRemove) {
-  if (IsEmpty())
-    return 0;
-
-  char* pstrSource = m_pData->m_String;
-  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;
-
-  char* pstrDest = pstrSource;
-  while (pstrSource < pstrEnd) {
-    if (*pstrSource != chRemove) {
-      *pstrDest = *pstrSource;
-      pstrDest++;
-    }
-    pstrSource++;
-  }
-
-  *pstrDest = 0;
-  size_t nCount = static_cast<size_t>(pstrSource - pstrDest);
-  m_pData->m_nDataLength -= nCount;
-  return nCount;
-}
-
 size_t ByteString::Replace(ByteStringView pOld, ByteStringView pNew) {
   if (!m_pData || pOld.IsEmpty())
     return 0;
diff --git a/core/fxcrt/bytestring.h b/core/fxcrt/bytestring.h
index e698773..1269010 100644
--- a/core/fxcrt/bytestring.h
+++ b/core/fxcrt/bytestring.h
@@ -37,11 +37,13 @@
   [[nodiscard]] static ByteString Format(const char* pFormat, ...);
   [[nodiscard]] static ByteString FormatV(const char* pFormat, va_list argList);
 
-  ByteString();
-  ByteString(const ByteString& other);
+  ByteString() = default;
+  ByteString(const ByteString& other) = default;
 
   // Move-construct a ByteString. After construction, |other| is empty.
-  ByteString(ByteString&& other) noexcept;
+  ByteString(ByteString&& other) noexcept = default;
+
+  ~ByteString() = default;
 
   // Make a one-character string from a char.
   explicit ByteString(char ch);
@@ -62,59 +64,14 @@
   ByteString(const std::initializer_list<ByteStringView>& list);
   explicit ByteString(const fxcrt::ostringstream& outStream);
 
-  ~ByteString();
-
   // 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.
   const char* c_str() const { return m_pData ? m_pData->m_String : ""; }
 
-  // Explicit conversion to uint8_t*. May return nullptr.
-  // Note: Any subsequent modification of |this| will invalidate the result.
-  const uint8_t* raw_str() const {
-    return m_pData ? reinterpret_cast<const uint8_t*>(m_pData->m_String)
-                   : nullptr;
-  }
-
-  // Explicit conversion to ByteStringView.
-  // Note: Any subsequent modification of |this| will invalidate the result.
-  ByteStringView AsStringView() const {
-    return ByteStringView(raw_str(), GetLength());
-  }
-
-  // Explicit conversion to span.
-  // Note: Any subsequent modification of |this| will invalidate the result.
-  pdfium::span<const char> span() const {
-    return pdfium::make_span(m_pData ? m_pData->m_String : nullptr,
-                             GetLength());
-  }
-  pdfium::span<const uint8_t> raw_span() const {
-    return pdfium::make_span(raw_str(), GetLength());
-  }
-
-  // Note: Any subsequent modification of |this| will invalidate iterators.
-  const_iterator begin() const {
-    return m_pData ? m_pData->span().begin() : nullptr;
-  }
-  const_iterator end() const {
-    return m_pData ? m_pData->span().end() : nullptr;
-  }
-
-  // Note: Any subsequent modification of |this| will invalidate iterators.
-  const_reverse_iterator rbegin() const {
-    return const_reverse_iterator(end());
-  }
-  const_reverse_iterator rend() const {
-    return const_reverse_iterator(begin());
-  }
-
-  size_t GetLength() const { return m_pData ? m_pData->m_nDataLength : 0; }
   size_t GetStringLength() const {
     return m_pData ? strlen(m_pData->m_String) : 0;
   }
-  bool IsEmpty() const { return !GetLength(); }
-  bool IsValidIndex(size_t index) const { return index < GetLength(); }
-  bool IsValidLength(size_t length) const { return length <= GetLength(); }
 
   int Compare(ByteStringView str) const;
   bool EqualNoCase(ByteStringView str) const;
@@ -143,20 +100,6 @@
   ByteString& operator+=(const ByteString& str);
   ByteString& operator+=(ByteStringView str);
 
-  // CHECK() if index is out of range (via span's operator[]).
-  CharType operator[](const size_t index) const {
-    CHECK(m_pData);
-    return m_pData->span()[index];
-  }
-
-  // Unlike std::string::front(), this is always safe and returns a
-  // NUL char when the string is empty.
-  CharType Front() const { return m_pData ? m_pData->Front() : 0; }
-
-  // Unlike std::string::back(), this is always safe and returns a
-  // NUL char when the string is empty.
-  CharType Back() const { return m_pData ? m_pData->Back() : 0; }
-
   void SetAt(size_t index, char c);
 
   size_t Insert(size_t index, char ch);
@@ -199,7 +142,6 @@
   void TrimRight(ByteStringView targets);
 
   size_t Replace(ByteStringView pOld, ByteStringView pNew);
-  size_t Remove(char ch);
 
   uint32_t GetID() const { return AsStringView().GetID(); }
 
diff --git a/core/fxcrt/string_template.cpp b/core/fxcrt/string_template.cpp
index ec77706..0fb8b3b 100644
--- a/core/fxcrt/string_template.cpp
+++ b/core/fxcrt/string_template.cpp
@@ -63,6 +63,44 @@
 }
 
 template <typename T>
+size_t StringTemplate<T>::Remove(T chRemove) {
+  if (IsEmpty()) {
+    return 0;
+  }
+
+  T* pstrSource = m_pData->m_String;
+  T* 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;
+
+  T* pstrDest = pstrSource;
+  while (pstrSource < pstrEnd) {
+    if (*pstrSource != chRemove) {
+      *pstrDest = *pstrSource;
+      pstrDest++;
+    }
+    pstrSource++;
+  }
+
+  *pstrDest = 0;
+  size_t nCount = static_cast<size_t>(pstrSource - pstrDest);
+  m_pData->m_nDataLength -= nCount;
+  return nCount;
+}
+
+template <typename T>
 void StringTemplate<T>::ReallocBeforeWrite(size_t nNewLength) {
   if (m_pData && m_pData->CanOperateInPlace(nNewLength)) {
     return;
diff --git a/core/fxcrt/string_template.h b/core/fxcrt/string_template.h
index c479332..137b0ff 100644
--- a/core/fxcrt/string_template.h
+++ b/core/fxcrt/string_template.h
@@ -9,6 +9,8 @@
 
 #include <stddef.h>
 
+#include <type_traits>
+
 #include "core/fxcrt/retain_ptr.h"
 #include "core/fxcrt/string_data_template.h"
 #include "core/fxcrt/string_view_template.h"
@@ -21,9 +23,72 @@
 class StringTemplate {
  public:
   using CharType = T;
+  using UnsignedType = typename std::make_unsigned<CharType>::type;
   using const_iterator = T*;
   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
 
+  bool IsEmpty() const { return !GetLength(); }
+  size_t GetLength() const { return m_pData ? m_pData->m_nDataLength : 0; }
+
+  // Explicit conversion to UnsignedType*. May return nullptr.
+  // Note: Any subsequent modification of |this| will invalidate the result.
+  const UnsignedType* raw_str() const {
+    return m_pData ? reinterpret_cast<const UnsignedType*>(m_pData->m_String)
+                   : nullptr;
+  }
+
+  // Explicit conversion to ByteStringView.
+  // Note: Any subsequent modification of |this| will invalidate the result.
+  StringViewTemplate<CharType> AsStringView() const {
+    return StringViewTemplate<CharType>(raw_str(), GetLength());
+  }
+
+  // Explicit conversion to span.
+  // Note: Any subsequent modification of |this| will invalidate the result.
+  pdfium::span<const CharType> span() const {
+    return pdfium::make_span(m_pData ? m_pData->m_String : nullptr,
+                             GetLength());
+  }
+
+  // Explicit conversion to spans of unsigned types.
+  // Note: Any subsequent modification of |this| will invalidate the result.
+  pdfium::span<const UnsignedType> raw_span() const {
+    return pdfium::make_span(raw_str(), GetLength());
+  }
+
+  // Note: Any subsequent modification of |this| will invalidate iterators.
+  const_iterator begin() const {
+    return m_pData ? m_pData->span().begin() : nullptr;
+  }
+  const_iterator end() const {
+    return m_pData ? m_pData->span().end() : nullptr;
+  }
+
+  // Note: Any subsequent modification of |this| will invalidate iterators.
+  const_reverse_iterator rbegin() const {
+    return const_reverse_iterator(end());
+  }
+  const_reverse_iterator rend() const {
+    return const_reverse_iterator(begin());
+  }
+
+  bool IsValidIndex(size_t index) const { return index < GetLength(); }
+  bool IsValidLength(size_t length) const { return length <= GetLength(); }
+
+  // CHECK() if index is out of range (via span's operator[]).
+  CharType operator[](const size_t index) const {
+    CHECK(m_pData);
+    return m_pData->span()[index];
+  }
+
+  // Unlike std::wstring::front(), this is always safe and returns a
+  // NUL char when the string is empty.
+  CharType Front() const { return m_pData ? m_pData->Front() : 0; }
+
+  // Unlike std::wstring::back(), this is always safe and returns a
+  // NUL char when the string is empty.
+  CharType Back() const { return m_pData ? m_pData->Back() : 0; }
+
   // Holds on to buffer if possible for later re-use. Use assignment
   // to force immediate release if desired.
   void clear();
@@ -39,10 +104,20 @@
   // to GetBuffer(), to indicate how much of the buffer was actually used.
   void ReleaseBuffer(size_t nNewLength);
 
+  size_t Remove(T ch);
+
  protected:
   using StringView = StringViewTemplate<T>;
   using StringData = StringDataTemplate<T>;
 
+  StringTemplate() = default;
+  StringTemplate(const StringTemplate& other) = default;
+
+  // Move-construct a StringTemplate. After construction, |other| is empty.
+  StringTemplate(StringTemplate&& other) noexcept = default;
+
+  ~StringTemplate() = default;
+
   void ReallocBeforeWrite(size_t nNewLen);
   void AllocBeforeWrite(size_t nNewLen);
   void AssignCopy(const T* pSrcData, size_t nSrcLen);
diff --git a/core/fxcrt/widestring.cpp b/core/fxcrt/widestring.cpp
index 314c10e..46ad6cb 100644
--- a/core/fxcrt/widestring.cpp
+++ b/core/fxcrt/widestring.cpp
@@ -384,12 +384,6 @@
   return ret;
 }
 
-WideString::WideString() = default;
-
-WideString::WideString(const WideString& other) = default;
-
-WideString::WideString(WideString&& other) noexcept = default;
-
 WideString::WideString(const wchar_t* pStr, size_t nLen) {
   if (nLen) {
     m_pData = StringData::Create({pStr, nLen});
@@ -441,8 +435,6 @@
   }
 }
 
-WideString::~WideString() = default;
-
 WideString& WideString::operator=(const wchar_t* str) {
   if (!str || !str[0])
     clear();
@@ -748,40 +740,6 @@
   FXSYS_wcsupr(m_pData->m_String);
 }
 
-size_t WideString::Remove(wchar_t chRemove) {
-  if (IsEmpty())
-    return 0;
-
-  wchar_t* pstrSource = m_pData->m_String;
-  wchar_t* 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;
-
-  wchar_t* pstrDest = pstrSource;
-  while (pstrSource < pstrEnd) {
-    if (*pstrSource != chRemove) {
-      *pstrDest = *pstrSource;
-      pstrDest++;
-    }
-    pstrSource++;
-  }
-
-  *pstrDest = 0;
-  size_t count = static_cast<size_t>(pstrSource - pstrDest);
-  m_pData->m_nDataLength -= count;
-  return count;
-}
-
 size_t WideString::Replace(WideStringView pOld, WideStringView pNew) {
   if (!m_pData || pOld.IsEmpty())
     return 0;
diff --git a/core/fxcrt/widestring.h b/core/fxcrt/widestring.h
index 8cdb69d..eac1d50 100644
--- a/core/fxcrt/widestring.h
+++ b/core/fxcrt/widestring.h
@@ -39,11 +39,13 @@
   [[nodiscard]] static WideString FormatV(const wchar_t* lpszFormat,
                                           va_list argList);
 
-  WideString();
-  WideString(const WideString& other);
+  WideString() = default;
+  WideString(const WideString& other) = default;
 
   // Move-construct a WideString. After construction, |other| is empty.
-  WideString(WideString&& other) noexcept;
+  WideString(WideString&& other) noexcept = default;
+
+  ~WideString() = default;
 
   // Make a one-character string from one wide char.
   explicit WideString(wchar_t ch);
@@ -62,8 +64,6 @@
   WideString(WideStringView str1, WideStringView str2);
   WideString(const std::initializer_list<WideStringView>& list);
 
-  ~WideString();
-
   [[nodiscard]] static WideString FromASCII(ByteStringView str);
   [[nodiscard]] static WideString FromLatin1(ByteStringView str);
   [[nodiscard]] static WideString FromDefANSI(ByteStringView str);
@@ -76,42 +76,10 @@
   // Note: Any subsequent modification of |this| will invalidate the result.
   const wchar_t* c_str() const { return m_pData ? m_pData->m_String : L""; }
 
-  // Explicit conversion to WideStringView.
-  // Note: Any subsequent modification of |this| will invalidate the result.
-  WideStringView AsStringView() const {
-    return WideStringView(c_str(), GetLength());
-  }
 
-  // Explicit conversion to span.
-  // Note: Any subsequent modification of |this| will invalidate the result.
-  pdfium::span<const wchar_t> span() const {
-    return pdfium::make_span(m_pData ? m_pData->m_String : nullptr,
-                             GetLength());
-  }
-
-  // Note: Any subsequent modification of |this| will invalidate iterators.
-  const_iterator begin() const {
-    return m_pData ? m_pData->span().begin() : nullptr;
-  }
-  const_iterator end() const {
-    return m_pData ? m_pData->span().end() : nullptr;
-  }
-
-  // Note: Any subsequent modification of |this| will invalidate iterators.
-  const_reverse_iterator rbegin() const {
-    return const_reverse_iterator(end());
-  }
-  const_reverse_iterator rend() const {
-    return const_reverse_iterator(begin());
-  }
-
-  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;
   }
-  bool IsEmpty() const { return !GetLength(); }
-  bool IsValidIndex(size_t index) const { return index < GetLength(); }
-  bool IsValidLength(size_t length) const { return length <= GetLength(); }
 
   WideString& operator=(const wchar_t* str);
   WideString& operator=(WideStringView str);
@@ -137,20 +105,6 @@
   bool operator<(WideStringView str) const;
   bool operator<(const WideString& other) const;
 
-  // / CHECK() if index is out of range (via span's operator[]).
-  CharType operator[](const size_t index) const {
-    CHECK(m_pData);
-    return m_pData->span()[index];
-  }
-
-  // Unlike std::wstring::front(), this is always safe and returns a
-  // NUL char when the string is empty.
-  CharType Front() const { return m_pData ? m_pData->Front() : 0; }
-
-  // Unlike std::wstring::back(), this is always safe and returns a
-  // NUL char when the string is empty.
-  CharType Back() const { return m_pData ? m_pData->Back() : 0; }
-
   void SetAt(size_t index, wchar_t c);
 
   int Compare(const wchar_t* str) const;
@@ -199,7 +153,6 @@
   }
 
   size_t Replace(WideStringView pOld, WideStringView pNew);
-  size_t Remove(wchar_t ch);
 
   bool IsASCII() const { return AsStringView().IsASCII(); }
   bool EqualsASCII(ByteStringView that) const {