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