• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2016 PDFium Authors. All rights reserved.
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_VIEW_TEMPLATE_H_
8 #define CORE_FXCRT_STRING_VIEW_TEMPLATE_H_
9 
10 #include <algorithm>
11 #include <iterator>
12 #include <type_traits>
13 #include <vector>
14 
15 #include "core/fxcrt/fx_system.h"
16 #include "third_party/base/optional.h"
17 #include "third_party/base/span.h"
18 #include "third_party/base/stl_util.h"
19 
20 namespace fxcrt {
21 
22 // An immutable string with caller-provided storage which must outlive the
23 // string itself. These are not necessarily nul-terminated, so that substring
24 // extraction (via the Substr(), First(), and Last() methods) is copy-free.
25 //
26 // String view arguments should be passed by value, since they are small,
27 // rather than const-ref, even if they are not modified.
28 template <typename T>
29 class StringViewTemplate {
30  public:
31   using CharType = T;
32   using UnsignedType = typename std::make_unsigned<CharType>::type;
33   using const_iterator = const CharType*;
34   using const_reverse_iterator = std::reverse_iterator<const_iterator>;
35 
36   constexpr StringViewTemplate() noexcept = default;
37   constexpr StringViewTemplate(const StringViewTemplate& src) noexcept =
38       default;
39 
40   // Deliberately implicit to avoid calling on every string literal.
41   // NOLINTNEXTLINE(runtime/explicit)
StringViewTemplate(const CharType * ptr)42   StringViewTemplate(const CharType* ptr) noexcept
43       : m_Span(reinterpret_cast<const UnsignedType*>(ptr),
44                ptr ? FXSYS_len(ptr) : 0) {}
45 
StringViewTemplate(const CharType * ptr,size_t len)46   constexpr StringViewTemplate(const CharType* ptr, size_t len) noexcept
47       : m_Span(reinterpret_cast<const UnsignedType*>(ptr), len) {}
48 
StringViewTemplate(const pdfium::span<const CharType> & other)49   explicit constexpr StringViewTemplate(
50       const pdfium::span<const CharType>& other) noexcept
51       : m_Span(reinterpret_cast<const UnsignedType*>(other.data()),
52                other.size()) {}
53 
54   template <typename U = UnsignedType>
55   constexpr StringViewTemplate(
56       const UnsignedType* ptr,
57       size_t size,
58       typename std::enable_if<!std::is_same<U, CharType>::value>::type* =
59           0) noexcept
m_Span(ptr,size)60       : m_Span(ptr, size) {}
61 
62   template <typename U = UnsignedType>
63   StringViewTemplate(
64       const pdfium::span<U> other,
65       typename std::enable_if<!std::is_same<U, CharType>::value>::type* =
66           0) noexcept
m_Span(other)67       : m_Span(other) {}
68 
69   // Deliberately implicit to avoid calling on every string literal.
70   // |ch| must be an lvalue that outlives the StringViewTemplate.
71   // NOLINTNEXTLINE(runtime/explicit)
StringViewTemplate(CharType & ch)72   constexpr StringViewTemplate(CharType& ch) noexcept
73       : m_Span(reinterpret_cast<const UnsignedType*>(&ch), 1) {}
74 
75   // Any changes to |vec| invalidate the string.
76   template <typename AllocType>
StringViewTemplate(const std::vector<UnsignedType,AllocType> & vec)77   explicit StringViewTemplate(
78       const std::vector<UnsignedType, AllocType>& vec) noexcept
79       : m_Span(!vec.empty() ? vec.data() : nullptr, vec.size()) {}
80 
81   StringViewTemplate& operator=(const CharType* src) {
82     m_Span = pdfium::span<const UnsignedType>(
83         reinterpret_cast<const UnsignedType*>(src), src ? FXSYS_len(src) : 0);
84     return *this;
85   }
86 
87   StringViewTemplate& operator=(const StringViewTemplate& src) {
88     m_Span = src.m_Span;
89     return *this;
90   }
91 
begin()92   const_iterator begin() const {
93     return reinterpret_cast<const_iterator>(m_Span.begin());
94   }
end()95   const_iterator end() const {
96     return reinterpret_cast<const_iterator>(m_Span.end());
97   }
rbegin()98   const_reverse_iterator rbegin() const {
99     return const_reverse_iterator(end());
100   }
rend()101   const_reverse_iterator rend() const {
102     return const_reverse_iterator(begin());
103   }
104 
105   bool operator==(const StringViewTemplate& other) const {
106     return m_Span == other.m_Span;
107   }
108   bool operator==(const CharType* ptr) const {
109     StringViewTemplate other(ptr);
110     return *this == other;
111   }
112   bool operator!=(const CharType* ptr) const { return !(*this == ptr); }
113   bool operator!=(const StringViewTemplate& other) const {
114     return !(*this == other);
115   }
116 
IsASCII()117   bool IsASCII() const {
118     for (auto c : *this) {
119       if (c <= 0 || c > 127)  // Questionable signedness of |c|.
120         return false;
121     }
122     return true;
123   }
124 
EqualsASCII(const StringViewTemplate<char> & that)125   bool EqualsASCII(const StringViewTemplate<char>& that) const {
126     size_t length = GetLength();
127     if (length != that.GetLength())
128       return false;
129 
130     for (size_t i = 0; i < length; ++i) {
131       auto c = (*this)[i];
132       if (c <= 0 || c > 127 || c != that[i])  // Questionable signedness of |c|.
133         return false;
134     }
135     return true;
136   }
137 
EqualsASCIINoCase(const StringViewTemplate<char> & that)138   bool EqualsASCIINoCase(const StringViewTemplate<char>& that) const {
139     size_t length = GetLength();
140     if (length != that.GetLength())
141       return false;
142 
143     for (size_t i = 0; i < length; ++i) {
144       auto c = (*this)[i];
145       if (c <= 0 || c > 127 || tolower(c) != tolower(that[i]))
146         return false;
147     }
148     return true;
149   }
150 
GetID()151   uint32_t GetID() const {
152     if (m_Span.empty())
153       return 0;
154 
155     uint32_t strid = 0;
156     size_t size = std::min(static_cast<size_t>(4), m_Span.size());
157     for (size_t i = 0; i < size; i++)
158       strid = strid * 256 + m_Span[i];
159 
160     return strid << ((4 - size) * 8);
161   }
162 
raw_span()163   pdfium::span<const UnsignedType> raw_span() const { return m_Span; }
span()164   pdfium::span<const CharType> span() const {
165     return pdfium::make_span(reinterpret_cast<const CharType*>(m_Span.data()),
166                              m_Span.size());
167   }
raw_str()168   const UnsignedType* raw_str() const { return m_Span.data(); }
unterminated_c_str()169   const CharType* unterminated_c_str() const {
170     return reinterpret_cast<const CharType*>(m_Span.data());
171   }
172 
GetLength()173   size_t GetLength() const { return m_Span.size(); }
IsEmpty()174   bool IsEmpty() const { return m_Span.empty(); }
IsValidIndex(size_t index)175   bool IsValidIndex(size_t index) const { return index < m_Span.size(); }
IsValidLength(size_t length)176   bool IsValidLength(size_t length) const { return length <= m_Span.size(); }
177 
178   const UnsignedType& operator[](const size_t index) const {
179     return m_Span[index];
180   }
181 
Front()182   UnsignedType Front() const { return !m_Span.empty() ? m_Span[0] : 0; }
Back()183   UnsignedType Back() const {
184     return !m_Span.empty() ? m_Span[m_Span.size() - 1] : 0;
185   }
186 
CharAt(const size_t index)187   const CharType CharAt(const size_t index) const {
188     return static_cast<CharType>(m_Span[index]);
189   }
190 
Find(CharType ch)191   Optional<size_t> Find(CharType ch) const {
192     const auto* found = reinterpret_cast<const UnsignedType*>(FXSYS_chr(
193         reinterpret_cast<const CharType*>(m_Span.data()), ch, m_Span.size()));
194 
195     return found ? Optional<size_t>(found - m_Span.data()) : Optional<size_t>();
196   }
197 
Contains(CharType ch)198   bool Contains(CharType ch) const { return Find(ch).has_value(); }
199 
Substr(size_t first,size_t count)200   StringViewTemplate Substr(size_t first, size_t count) const {
201     if (!m_Span.data())
202       return StringViewTemplate();
203 
204     if (!IsValidIndex(first))
205       return StringViewTemplate();
206 
207     if (count == 0 || !IsValidLength(count))
208       return StringViewTemplate();
209 
210     if (!IsValidIndex(first + count - 1))
211       return StringViewTemplate();
212 
213     return StringViewTemplate(m_Span.data() + first, count);
214   }
215 
First(size_t count)216   StringViewTemplate First(size_t count) const {
217     if (count == 0 || !IsValidLength(count))
218       return StringViewTemplate();
219     return Substr(0, count);
220   }
221 
Last(size_t count)222   StringViewTemplate Last(size_t count) const {
223     if (count == 0 || !IsValidLength(count))
224       return StringViewTemplate();
225     return Substr(GetLength() - count, count);
226   }
227 
TrimmedRight(CharType ch)228   StringViewTemplate TrimmedRight(CharType ch) const {
229     if (IsEmpty())
230       return StringViewTemplate();
231 
232     size_t pos = GetLength();
233     while (pos && CharAt(pos - 1) == ch)
234       pos--;
235 
236     if (pos == 0)
237       return StringViewTemplate();
238 
239     return StringViewTemplate(m_Span.data(), pos);
240   }
241 
242   bool operator<(const StringViewTemplate& that) const {
243     int result =
244         FXSYS_cmp(reinterpret_cast<const CharType*>(m_Span.data()),
245                   reinterpret_cast<const CharType*>(that.m_Span.data()),
246                   std::min(m_Span.size(), that.m_Span.size()));
247     return result < 0 || (result == 0 && m_Span.size() < that.m_Span.size());
248   }
249 
250   bool operator>(const StringViewTemplate& that) const {
251     int result =
252         FXSYS_cmp(reinterpret_cast<const CharType*>(m_Span.data()),
253                   reinterpret_cast<const CharType*>(that.m_Span.data()),
254                   std::min(m_Span.size(), that.m_Span.size()));
255     return result > 0 || (result == 0 && m_Span.size() > that.m_Span.size());
256   }
257 
258  protected:
259   pdfium::span<const UnsignedType> m_Span;
260 
261  private:
new(size_t)262   void* operator new(size_t) throw() { return nullptr; }
263 };
264 
265 template <typename T>
266 inline bool operator==(const T* lhs, const StringViewTemplate<T>& rhs) {
267   return rhs == lhs;
268 }
269 template <typename T>
270 inline bool operator!=(const T* lhs, const StringViewTemplate<T>& rhs) {
271   return rhs != lhs;
272 }
273 template <typename T>
274 inline bool operator<(const T* lhs, const StringViewTemplate<T>& rhs) {
275   return rhs > lhs;
276 }
277 
278 // Workaround for one of the cases external template classes are
279 // failing in GCC before version 7 with -O0
280 #if !defined(__GNUC__) || __GNUC__ >= 7
281 extern template class StringViewTemplate<char>;
282 extern template class StringViewTemplate<wchar_t>;
283 #endif
284 
285 using ByteStringView = StringViewTemplate<char>;
286 using WideStringView = StringViewTemplate<wchar_t>;
287 
288 }  // namespace fxcrt
289 
290 using ByteStringView = fxcrt::ByteStringView;
291 using WideStringView = fxcrt::WideStringView;
292 
293 #endif  // CORE_FXCRT_STRING_VIEW_TEMPLATE_H_
294