// Copyright 2016 PDFium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #ifndef CORE_FXCRT_STRING_VIEW_TEMPLATE_H_ #define CORE_FXCRT_STRING_VIEW_TEMPLATE_H_ #include <algorithm> #include <iterator> #include <type_traits> #include <utility> #include <vector> #include "core/fxcrt/fx_system.h" #include "core/fxcrt/unowned_ptr.h" #include "third_party/base/optional.h" #include "third_party/base/span.h" #include "third_party/base/stl_util.h" namespace fxcrt { // An immutable string with caller-provided storage which must outlive the // string itself. These are not necessarily nul-terminated, so that substring // extraction (via the Mid(), Left(), and Right() methods) is copy-free. template <typename T> class StringViewTemplate { public: using CharType = T; using UnsignedType = typename std::make_unsigned<CharType>::type; using const_iterator = const CharType*; using const_reverse_iterator = std::reverse_iterator<const_iterator>; constexpr StringViewTemplate() noexcept = default; constexpr StringViewTemplate(const StringViewTemplate& src) noexcept = default; // Deliberately implicit to avoid calling on every string literal. // NOLINTNEXTLINE(runtime/explicit) StringViewTemplate(const CharType* ptr) noexcept : m_Span(reinterpret_cast<const UnsignedType*>(ptr), ptr ? FXSYS_len(ptr) : 0) {} constexpr StringViewTemplate(const CharType* ptr, size_t len) noexcept : m_Span(reinterpret_cast<const UnsignedType*>(ptr), len) {} explicit constexpr StringViewTemplate( const pdfium::span<CharType>& other) noexcept : m_Span(reinterpret_cast<const UnsignedType*>(other.data()), other.size()) {} template <typename U = UnsignedType> constexpr StringViewTemplate( const UnsignedType* ptr, size_t size, typename std::enable_if<!std::is_same<U, CharType>::value>::type* = 0) noexcept : m_Span(ptr, size) {} template <typename U = UnsignedType> StringViewTemplate( const pdfium::span<U> other, typename std::enable_if<!std::is_same<U, CharType>::value>::type* = 0) noexcept : m_Span(other) {} // Deliberately implicit to avoid calling on every string literal. // |ch| must be an lvalue that outlives the StringViewTemplate. // NOLINTNEXTLINE(runtime/explicit) constexpr StringViewTemplate(CharType& ch) noexcept : m_Span(reinterpret_cast<const UnsignedType*>(&ch), 1) {} // Any changes to |vec| invalidate the string. explicit StringViewTemplate(const std::vector<UnsignedType>& vec) noexcept : m_Span(vec.size() ? vec.data() : nullptr, vec.size()) {} StringViewTemplate& operator=(const CharType* src) { m_Span = pdfium::span<const UnsignedType>( reinterpret_cast<const UnsignedType*>(src), src ? FXSYS_len(src) : 0); return *this; } StringViewTemplate& operator=(const StringViewTemplate& src) { m_Span = src.m_Span; return *this; } const_iterator begin() const { return reinterpret_cast<const_iterator>(m_Span.begin()); } const_iterator end() const { return reinterpret_cast<const_iterator>(m_Span.end()); } const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); } const_reverse_iterator rend() const { return const_reverse_iterator(begin()); } bool operator==(const StringViewTemplate& other) const { return m_Span == other.m_Span; } bool operator==(const CharType* ptr) const { StringViewTemplate other(ptr); return *this == other; } bool operator!=(const CharType* ptr) const { return !(*this == ptr); } bool operator!=(const StringViewTemplate& other) const { return !(*this == other); } uint32_t GetID() const { if (m_Span.size() == 0) return 0; uint32_t strid = 0; size_t size = std::min(static_cast<size_t>(4), m_Span.size()); for (size_t i = 0; i < size; i++) strid = strid * 256 + m_Span[i]; return strid << ((4 - size) * 8); } pdfium::span<const UnsignedType> span() const { return m_Span; } const UnsignedType* raw_str() const { return m_Span.data(); } const CharType* unterminated_c_str() const { return reinterpret_cast<const CharType*>(m_Span.data()); } size_t GetLength() const { return m_Span.size(); } bool IsEmpty() const { return m_Span.empty(); } bool IsValidIndex(size_t index) const { return index < m_Span.size(); } bool IsValidLength(size_t length) const { return length <= m_Span.size(); } const UnsignedType& operator[](const size_t index) const { return m_Span[index]; } UnsignedType First() const { return m_Span.size() ? m_Span[0] : 0; } UnsignedType Last() const { return m_Span.size() ? m_Span[m_Span.size() - 1] : 0; } const CharType CharAt(const size_t index) const { return static_cast<CharType>(m_Span[index]); } Optional<size_t> Find(CharType ch) const { const auto* found = reinterpret_cast<const UnsignedType*>(FXSYS_chr( reinterpret_cast<const CharType*>(m_Span.data()), ch, m_Span.size())); return found ? Optional<size_t>(found - m_Span.data()) : Optional<size_t>(); } bool Contains(CharType ch) const { return Find(ch).has_value(); } StringViewTemplate Mid(size_t first, size_t count) const { if (!m_Span.data()) return StringViewTemplate(); if (!IsValidIndex(first)) return StringViewTemplate(); if (count == 0 || !IsValidLength(count)) return StringViewTemplate(); if (!IsValidIndex(first + count - 1)) return StringViewTemplate(); return StringViewTemplate(m_Span.data() + first, count); } StringViewTemplate Left(size_t count) const { if (count == 0 || !IsValidLength(count)) return StringViewTemplate(); return Mid(0, count); } StringViewTemplate Right(size_t count) const { if (count == 0 || !IsValidLength(count)) return StringViewTemplate(); return Mid(GetLength() - count, count); } StringViewTemplate TrimmedRight(CharType ch) const { if (IsEmpty()) return StringViewTemplate(); size_t pos = GetLength(); while (pos && CharAt(pos - 1) == ch) pos--; if (pos == 0) return StringViewTemplate(); return StringViewTemplate(m_Span.data(), pos); } bool operator<(const StringViewTemplate& that) const { int result = FXSYS_cmp(reinterpret_cast<const CharType*>(m_Span.data()), reinterpret_cast<const CharType*>(that.m_Span.data()), std::min(m_Span.size(), that.m_Span.size())); return result < 0 || (result == 0 && m_Span.size() < that.m_Span.size()); } bool operator>(const StringViewTemplate& that) const { int result = FXSYS_cmp(reinterpret_cast<const CharType*>(m_Span.data()), reinterpret_cast<const CharType*>(that.m_Span.data()), std::min(m_Span.size(), that.m_Span.size())); return result > 0 || (result == 0 && m_Span.size() > that.m_Span.size()); } protected: pdfium::span<const UnsignedType> m_Span; private: void* operator new(size_t) throw() { return nullptr; } }; template <typename T> inline bool operator==(const T* lhs, const StringViewTemplate<T>& rhs) { return rhs == lhs; } template <typename T> inline bool operator!=(const T* lhs, const StringViewTemplate<T>& rhs) { return rhs != lhs; } template <typename T> inline bool operator<(const T* lhs, const StringViewTemplate<T>& rhs) { return rhs > lhs; } extern template class StringViewTemplate<char>; extern template class StringViewTemplate<wchar_t>; using ByteStringView = StringViewTemplate<char>; using WideStringView = StringViewTemplate<wchar_t>; } // namespace fxcrt using ByteStringView = fxcrt::ByteStringView; using WideStringView = fxcrt::WideStringView; #endif // CORE_FXCRT_STRING_VIEW_TEMPLATE_H_