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