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