• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #ifndef CORE_FXCRT_STRING_TEMPLATE_H_
8 #define CORE_FXCRT_STRING_TEMPLATE_H_
9 
10 #include <stddef.h>
11 
12 #include <type_traits>
13 
14 #include "core/fxcrt/compiler_specific.h"
15 #include "core/fxcrt/retain_ptr.h"
16 #include "core/fxcrt/span.h"
17 #include "core/fxcrt/string_data_template.h"
18 #include "core/fxcrt/string_view_template.h"
19 
20 namespace fxcrt {
21 
EmptyString(char *)22 inline constexpr const char* EmptyString(char*) {
23   return "";
24 }
EmptyString(wchar_t *)25 inline constexpr const wchar_t* EmptyString(wchar_t*) {
26   return L"";
27 }
28 
29 // Base class for a  mutable string with shared buffers using copy-on-write
30 // semantics that avoids std::string's iterator stability guarantees.
31 template <typename T>
32 class StringTemplate {
33  public:
34   using CharType = T;
35   using UnsignedType = typename std::make_unsigned<CharType>::type;
36   using StringView = StringViewTemplate<T>;
37   using const_iterator = T*;
38   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
39 
IsEmpty()40   bool IsEmpty() const { return !GetLength(); }
GetLength()41   size_t GetLength() const { return m_pData ? m_pData->m_nDataLength : 0; }
42 
43   // Return length as determined by the position of the first NUL.
GetStringLength()44   size_t GetStringLength() const {
45     return m_pData ? m_pData->GetStringLength() : 0;
46   }
47 
48   // Explicit conversion to UnsignedType*. May return nullptr.
49   // Note: Any subsequent modification of |this| will invalidate the result.
unsigned_str()50   const UnsignedType* unsigned_str() const {
51     return m_pData ? reinterpret_cast<const UnsignedType*>(m_pData->m_String)
52                    : nullptr;
53   }
54 
55   // Explicit conversion to StringView.
56   // Note: Any subsequent modification of |this| will invalidate the result.
AsStringView()57   StringView AsStringView() const { return StringView(unsigned_span()); }
58 
59   // Explicit conversion to C-style string. The result is never nullptr,
60   // and is always NUL terminated.
61   // Note: Any subsequent modification of |this| will invalidate the result.
c_str()62   const CharType* c_str() const {
63     return m_pData ? m_pData->m_String
64                    : EmptyString(static_cast<CharType*>(nullptr));
65   }
66 
67   // Explicit conversion to span.
68   // Note: Any subsequent modification of |this| will invalidate the result.
span()69   pdfium::span<const CharType> span() const {
70     return m_pData ? m_pData->span() : pdfium::span<const CharType>();
71   }
72 
73   // Explicit conversion to spans of unsigned types.
74   // Note: Any subsequent modification of |this| will invalidate the result.
unsigned_span()75   pdfium::span<const UnsignedType> unsigned_span() const {
76     return reinterpret_span<const UnsignedType>(span());
77   }
78 
79   // Explicit conversion to spans including the NUL terminator. The result is
80   // never an empty span. Only a const-form is provided to preclude modifying
81   // the terminator. Usage should be rare and carefully considered.
82   // Note: Any subsequent modification of |this| will invalidate the result.
span_with_terminator()83   pdfium::span<const CharType> span_with_terminator() const {
84     // SAFETY: EmptyString() returns one NUL byte.
85     return m_pData ? m_pData->span_with_terminator()
86                    : UNSAFE_BUFFERS(pdfium::make_span(
87                          EmptyString(static_cast<CharType*>(nullptr)), 1u));
88   }
89 
90   // Explicit conversion to spans of unsigned types including the NUL
91   // terminator. The result is never an empty span. Only a const-form is
92   // provided to preclude modifying the terminator. Usage should be rare
93   // and carefully considered.
94   // Note: Any subsequent modification of |this| will invalidate the result.
unsigned_span_with_terminator()95   pdfium::span<const UnsignedType> unsigned_span_with_terminator() const {
96     return reinterpret_span<const UnsignedType>(span_with_terminator());
97   }
98 
99   // Note: Any subsequent modification of |this| will invalidate iterators.
begin()100   const_iterator begin() const {
101     return m_pData ? m_pData->span().begin() : nullptr;
102   }
end()103   const_iterator end() const {
104     return m_pData ? m_pData->span().end() : nullptr;
105   }
106 
107   // Note: Any subsequent modification of |this| will invalidate iterators.
rbegin()108   const_reverse_iterator rbegin() const {
109     return const_reverse_iterator(end());
110   }
rend()111   const_reverse_iterator rend() const {
112     return const_reverse_iterator(begin());
113   }
114 
IsValidIndex(size_t index)115   bool IsValidIndex(size_t index) const { return index < GetLength(); }
IsValidLength(size_t length)116   bool IsValidLength(size_t length) const { return length <= GetLength(); }
117 
118   // CHECK() if index is out of range (via span's operator[]).
119   CharType operator[](const size_t index) const {
120     CHECK(m_pData);
121     return m_pData->span()[index];
122   }
123 
124   // Unlike std::wstring::front(), this is always safe and returns a
125   // NUL char when the string is empty.
Front()126   CharType Front() const { return m_pData ? m_pData->Front() : 0; }
127 
128   // Unlike std::wstring::back(), this is always safe and returns a
129   // NUL char when the string is empty.
Back()130   CharType Back() const { return m_pData ? m_pData->Back() : 0; }
131 
132   // Holds on to buffer if possible for later re-use. Use assignment
133   // to force immediate release if desired.
134   void clear();
135 
136   // Increase the backing store of the string so that it is capable of storing
137   // at least `nMinBufLength` chars. Returns a span to the entire buffer,
138   // which may be larger than `nMinBufLength` due to rounding by allocators.
139   // Note: any modification of the string (including ReleaseBuffer()) may
140   // invalidate the span, which must not outlive its buffer.
141   pdfium::span<T> GetBuffer(size_t nMinBufLength);
142 
143   // Sets the size of the string to `nNewLength` chars. Call this after a call
144   // to GetBuffer(), to indicate how much of the buffer was actually used.
145   void ReleaseBuffer(size_t nNewLength);
146 
147   // Returns size of string following insertion.
148   size_t Insert(size_t index, T ch);
InsertAtFront(T ch)149   size_t InsertAtFront(T ch) { return Insert(0, ch); }
InsertAtBack(T ch)150   size_t InsertAtBack(T ch) { return Insert(GetLength(), ch); }
151 
152   // Returns number of instances of `ch` removed.
153   size_t Remove(T ch);
154 
155   // Returns size of the string following deletion.
156   size_t Delete(size_t index, size_t count = 1);
157 
158   // Returns the index within the string when found.
159   std::optional<size_t> Find(StringView str, size_t start = 0) const;
160   std::optional<size_t> Find(T ch, size_t start = 0) const;
161   std::optional<size_t> ReverseFind(T ch) const;
162 
163   bool Contains(StringView str, size_t start = 0) const {
164     return Find(str, start).has_value();
165   }
166   bool Contains(T ch, size_t start = 0) const {
167     return Find(ch, start).has_value();
168   }
169 
170   // Replace all occurences of `oldstr' with `newstr'.
171   size_t Replace(StringView oldstr, StringView newstr);
172 
173   // Overwrite character at `index`.
174   void SetAt(size_t index, T ch);
175 
Reserve(size_t len)176   void Reserve(size_t len) { GetBuffer(len); }
177 
178   // Remove character `ch` from  both/front/back of string.
179   void Trim(T ch);
180   void TrimFront(T ch);
181   void TrimBack(T ch);
182 
183   // Remove all characters in `targets` from both/front/back of string.
184   void Trim(StringView targets);
185   void TrimFront(StringView targets);
186   void TrimBack(StringView targets);
187 
188  protected:
189   using StringData = StringDataTemplate<T>;
190 
191   StringTemplate() = default;
192   StringTemplate(const StringTemplate& other) = default;
193 
194   // Move-construct a StringTemplate. After construction, |other| is empty.
195   StringTemplate(StringTemplate&& other) noexcept = default;
196 
197   ~StringTemplate() = default;
198 
199   void ReallocBeforeWrite(size_t nNewLen);
200   void AllocBeforeWrite(size_t nNewLen);
201   void AssignCopy(const T* pSrcData, size_t nSrcLen);
202   void Concat(const T* pSrcData, size_t nSrcLen);
203 
204   RetainPtr<StringData> m_pData;
205 };
206 
207 extern template class StringTemplate<char>;
208 extern template class StringTemplate<wchar_t>;
209 
210 }  // namespace fxcrt
211 
212 #endif  // CORE_FXCRT_STRING_TEMPLATE_H_
213