// Copyright 2023 The PDFium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #ifndef CORE_FXCRT_CODE_POINT_VIEW_H_ #define CORE_FXCRT_CODE_POINT_VIEW_H_ #include "build/build_config.h" #include "core/fxcrt/string_view_template.h" #include "core/fxcrt/utf16.h" #include "third_party/base/check_op.h" namespace pdfium { #if defined(WCHAR_T_IS_UTF16) // A view over a UTF-16 `WideStringView` suitable for iterating by code point // using a range-based `for` loop. class CodePointView final { public: class Iterator { public: bool operator==(const Iterator& other) const { return current_ == other.current_; } bool operator!=(const Iterator& other) const { return current_ != other.current_; } Iterator& operator++() { DCHECK_LT(current_, end_); current_ += IsSupplementary(code_point_) ? 2 : 1; code_point_ = Decode(); return *this; } char32_t operator*() const { DCHECK_NE(kSentinel, code_point_); return code_point_; } private: friend class CodePointView; static constexpr char32_t kSentinel = -1; Iterator(const wchar_t* begin, const wchar_t* end) : current_(begin), end_(end), code_point_(Decode()) {} char32_t Decode() { if (current_ >= end_) { return kSentinel; } char32_t code_point = *current_; if (IsHighSurrogate(code_point)) { const wchar_t* next = current_ + 1; if (next < end_ && IsLowSurrogate(*next)) { code_point = SurrogatePair(code_point, *next).ToCodePoint(); } } return code_point; } const wchar_t* current_; const wchar_t* end_; char32_t code_point_; }; explicit CodePointView(WideStringView backing) : begin_(backing.begin()), end_(backing.end()) { DCHECK_LE(begin_, end_); } Iterator begin() const { return Iterator(begin_, end_); } Iterator end() const { return Iterator(end_, end_); } private: // Note that a `WideStringView` member would make the constructor too complex. const wchar_t* begin_; const wchar_t* end_; }; #else using CodePointView = WideStringView; #endif // defined(WCHAR_T_IS_UTF16) } // namespace pdfium #endif // CORE_FXCRT_CODE_POINT_VIEW_H_