#ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_PROXY_ITERATOR_H__ #define GOOGLE_PROTOBUF_REPEATED_FIELD_PROXY_ITERATOR_H__ #include #include #include #include "google/protobuf/repeated_field_proxy_traits.h" namespace google { namespace protobuf { namespace internal { template class MutableRepeatedFieldProxyImpl; template class RepeatedFieldProxyIteratorInternalPrivateAccessHelper; // kOrProxy is a phony parameter just to force `RepeatedFieldProxy` and // `RepeatedFieldOrProxy` to have different iterator types. When the backing // representation of `RepeatedFieldProxy` changes, we will need these iterators // to have different types. By making the type different now, it makes writing // code that mixes iterators from `RepeatedFieldProxy` and // `RepeatedFieldOrProxy` impossible. template class RepeatedFieldProxyIteratorImpl { // An alias for self. using iterator = RepeatedFieldProxyIteratorImpl; using Traits = RepeatedFieldTraits>; using InternalForwardIterator = std::conditional_t, typename Traits::type::const_iterator, typename Traits::type::iterator>; using InternalIterator = std::conditional_t, InternalForwardIterator>; public: using value_type = std::remove_const_t; using difference_type = std::ptrdiff_t; using pointer = ElementType*; using reference = std::conditional_t, typename Traits::const_reference, typename Traits::reference>; private: static constexpr bool kReturnByValue = !std::is_reference_v; public: // When returning elements by value, this iterator does not satisfy the // pre-C++20 requirement that "If i and j are both dereferenceable, then i == // j if and only if *i and *j are bound to the same object" from // `LegacyForwardIterator`. This is broken because `operator*` returns a // temporary. using iterator_category = std::conditional_t; // This object equivalence restriction was relaxed in C++20, allowing us to // use `std::random_access_iterator_tag` for `iterator_concept` for // value-returning and reference-returning iterators. using iterator_concept = std::random_access_iterator_tag; private: struct ArrowProxy { value_type view; const value_type* operator->() const { return &view; } }; public: explicit RepeatedFieldProxyIteratorImpl(InternalIterator it) : it_(it) {} template >> // NOLINTNEXTLINE(google-explicit-constructor) RepeatedFieldProxyIteratorImpl( const RepeatedFieldProxyIteratorImpl, kReverse, kOrProxy>& other) : it_(other.it_) {} // Allow explicit conversion from forward to reverse iterators. template > explicit RepeatedFieldProxyIteratorImpl( RepeatedFieldProxyIteratorImpl other) : it_(std::make_reverse_iterator(other.it_)) {} [[nodiscard]] reference operator*() const { return static_cast(*it_); } [[nodiscard]] auto operator->() const { if constexpr (kReturnByValue) { // Since operator-> needs to return a pointer-like object, we return a // struct that holds a copy of the element value, with an overloaded // operator-> returning a pointer to this object. return ArrowProxy{static_cast(*it_)}; } else { return &(operator*()); } } iterator& operator++() { ++it_; return *this; } iterator operator++(int) { return iterator(it_++); } iterator& operator--() { --it_; return *this; } iterator operator--(int) { return iterator(it_--); } friend bool operator==(const iterator& x, const iterator& y) { return x.it_ == y.it_; } friend bool operator!=(const iterator& x, const iterator& y) { return x.it_ != y.it_; } friend bool operator<(const iterator& x, const iterator& y) { return x.it_ < y.it_; } friend bool operator<=(const iterator& x, const iterator& y) { return x.it_ <= y.it_; } friend bool operator>(const iterator& x, const iterator& y) { return x.it_ > y.it_; } friend bool operator>=(const iterator& x, const iterator& y) { return x.it_ >= y.it_; } iterator& operator+=(difference_type d) { it_ += d; return *this; } friend iterator operator+(iterator it, const difference_type d) { it += d; return it; } friend iterator operator+(const difference_type d, iterator it) { it += d; return it; } iterator& operator-=(difference_type d) { it_ -= d; return *this; } friend iterator operator-(iterator it, difference_type d) { it -= d; return it; } [[nodiscard]] reference operator[](difference_type d) const { return static_cast(it_[d]); } friend difference_type operator-(iterator it1, iterator it2) { return it1.it_ - it2.it_; } private: template friend class RepeatedFieldProxyIteratorImpl; friend RepeatedFieldProxyIteratorInternalPrivateAccessHelper; friend MutableRepeatedFieldProxyImpl, kOrProxy>; // Allow explicit conversion to the internal iterator. explicit operator InternalIterator() const { return it_; } InternalIterator it_; }; template class RepeatedFieldProxyIteratorInternalPrivateAccessHelper { using Traits = RepeatedFieldTraits>; public: template static auto iterator( const RepeatedFieldProxyIteratorImpl& it) { return it.it_; } }; } // namespace internal // Like C++20's std::sort, for RepeatedFieldProxy. template void sort(internal::RepeatedFieldProxyIteratorImpl begin, internal::RepeatedFieldProxyIteratorImpl end, Compare cmp) { auto begin_it = internal::RepeatedFieldProxyIteratorInternalPrivateAccessHelper< T>::iterator(begin); auto end_it = internal::RepeatedFieldProxyIteratorInternalPrivateAccessHelper< T>::iterator(end); google::protobuf::sort(begin_it, end_it, cmp); } // Like C++20's std::sort, for RepeatedFieldProxy, with default comparison. template void sort(internal::RepeatedFieldProxyIteratorImpl begin, internal::RepeatedFieldProxyIteratorImpl end) { auto begin_it = internal::RepeatedFieldProxyIteratorInternalPrivateAccessHelper< T>::iterator(begin); auto end_it = internal::RepeatedFieldProxyIteratorInternalPrivateAccessHelper< T>::iterator(end); google::protobuf::sort(begin_it, end_it); } // Like C++20's std::stable_sort, for RepeatedFieldProxy. template void stable_sort( internal::RepeatedFieldProxyIteratorImpl begin, internal::RepeatedFieldProxyIteratorImpl end, Compare cmp) { auto begin_it = internal::RepeatedFieldProxyIteratorInternalPrivateAccessHelper< T>::iterator(begin); auto end_it = internal::RepeatedFieldProxyIteratorInternalPrivateAccessHelper< T>::iterator(end); google::protobuf::stable_sort(begin_it, end_it, cmp); } // Like C++20's std::stable_sort, for RepeatedFieldProxy, with default // comparison. template void stable_sort( internal::RepeatedFieldProxyIteratorImpl begin, internal::RepeatedFieldProxyIteratorImpl end) { auto begin_it = internal::RepeatedFieldProxyIteratorInternalPrivateAccessHelper< T>::iterator(begin); auto end_it = internal::RepeatedFieldProxyIteratorInternalPrivateAccessHelper< T>::iterator(end); google::protobuf::stable_sort(begin_it, end_it); } } // namespace protobuf } // namespace google #endif // GOOGLE_PROTOBUF_REPEATED_FIELD_PROXY_ITERATOR_H__