diff --git a/protos/repeated_field.h b/protos/repeated_field.h index e4524107b3..98d2f6bfdb 100644 --- a/protos/repeated_field.h +++ b/protos/repeated_field.h @@ -71,9 +71,6 @@ class RepeatedFieldProxyBase { bool empty() const { return size() == 0; } protected: - // Returns upb_Array string member. - inline absl::string_view GetString(size_t n) const; - // Returns upb_Array message member. inline upb_Message* GetMessage(size_t n) const; @@ -81,13 +78,6 @@ class RepeatedFieldProxyBase { upb_Arena* arena_; }; -template -inline absl::string_view RepeatedFieldProxyBase::GetString(size_t n) const { - upb_MessageValue message_value = upb_Array_Get(arr_, n); - return absl::string_view(message_value.str_val.data, - message_value.str_val.size); -} - template upb_Message* RepeatedFieldProxyBase::GetMessage(size_t n) const { auto** messages = @@ -174,6 +164,14 @@ class RepeatedFieldStringProxy static constexpr bool kIsConst = std::is_const_v; public: + using value_type = std::remove_const_t; + using size_type = size_t; + using difference_type = ptrdiff_t; + using iterator = internal::Iterator>; + using reference = typename iterator::reference; + using pointer = typename iterator::pointer; + using reverse_iterator = std::reverse_iterator; + // Immutable constructor. explicit RepeatedFieldStringProxy(const upb_Array* arr, upb_Arena* arena) : RepeatedFieldProxyBase(arr, arena) {} @@ -183,7 +181,7 @@ class RepeatedFieldStringProxy // Constructor used by ::protos::Ptr. RepeatedFieldStringProxy(const RepeatedFieldStringProxy&) = default; - T operator[](size_t n) const { return this->GetString(n); } + reference operator[](size_t n) const { return begin()[n]; } template > @@ -197,6 +195,13 @@ class RepeatedFieldStringProxy message_value.str_val = upb_StringView_FromDataAndSize(data, t.size()); upb_Array_Append(this->arr_, message_value, this->arena_); } + + iterator begin() const { return iterator({this->arr_, this->arena_, 0}); } + iterator end() const { + return iterator({this->arr_, this->arena_, this->size()}); + } + reverse_iterator rbegin() const { return reverse_iterator(end()); } + reverse_iterator rend() const { return reverse_iterator(begin()); } }; // RepeatedField proxy for repeated scalar types. @@ -211,7 +216,7 @@ class RepeatedFieldScalarProxy using value_type = std::remove_const_t; using size_type = size_t; using difference_type = ptrdiff_t; - using iterator = internal::RepeatedScalarIterator; + using iterator = internal::Iterator>; using reference = typename iterator::reference; using pointer = typename iterator::pointer; using reverse_iterator = std::reverse_iterator; @@ -238,9 +243,9 @@ class RepeatedFieldScalarProxy upb_Array_Append(this->arr_, message_value, this->arena_); } - iterator begin() const { return iterator(unsafe_array()); } + iterator begin() const { return iterator({unsafe_array()}); } iterator cbegin() const { return begin(); } - iterator end() const { return iterator(unsafe_array() + this->size()); } + iterator end() const { return iterator({unsafe_array() + this->size()}); } iterator cend() const { return end(); } // Reverse iterator support. diff --git a/protos/repeated_field_iterator.h b/protos/repeated_field_iterator.h index 321abd7e3b..64815d0f19 100644 --- a/protos/repeated_field_iterator.h +++ b/protos/repeated_field_iterator.h @@ -28,6 +28,7 @@ #define UPB_PROTOS_REPEATED_FIELD_ITERATOR_H_ #include +#include #include #include @@ -44,136 +45,197 @@ namespace protos { namespace internal { -// TODO(b/279086429): Implement std iterator for strings and messages +// TODO(b/279086429): Implement std iterator for messages template class RepeatedFieldScalarProxy; +template +class RepeatedFieldStringProxy; struct IteratorTestPeer; template -class RepeatedScalarIterator; +class Iterator; + +template +class ReferenceProxy; + +template +class InjectedRelationalsImpl { + using RP = ReferenceProxy; + using V = typename PolicyT::value_type; + friend bool operator==(RP a, V b) { return static_cast(a) == b; } + friend bool operator==(V a, RP b) { return a == static_cast(b); } + friend bool operator==(RP a, RP b) { + return static_cast(a) == static_cast(b); + } + friend bool operator!=(RP a, V b) { return static_cast(a) != b; } + friend bool operator!=(V a, RP b) { return a != static_cast(b); } + friend bool operator!=(RP a, RP b) { + return static_cast(a) != static_cast(b); + } + friend bool operator<(RP a, V b) { return static_cast(a) < b; } + friend bool operator<(V a, RP b) { return a < static_cast(b); } + friend bool operator<(RP a, RP b) { + return static_cast(a) < static_cast(b); + } + friend bool operator<=(RP a, V b) { return static_cast(a) <= b; } + friend bool operator<=(V a, RP b) { return a <= static_cast(b); } + friend bool operator<=(RP a, RP b) { + return static_cast(a) <= static_cast(b); + } + friend bool operator>(RP a, V b) { return static_cast(a) > b; } + friend bool operator>(V a, RP b) { return a > static_cast(b); } + friend bool operator>(RP a, RP b) { + return static_cast(a) > static_cast(b); + } + friend bool operator>=(RP a, V b) { return static_cast(a) >= b; } + friend bool operator>=(V a, RP b) { return a >= static_cast(b); } + friend bool operator>=(RP a, RP b) { + return static_cast(a) >= static_cast(b); + } +}; +class NoInjectedRelationalsImpl {}; + +// We need to inject relationals for the string references because the +// relationals for string_view are templates and won't allow for implicit +// conversions from ReferenceProxy to string_view before deduction. +template +using InjectedRelationals = std::conditional_t< + std::is_same_v, + absl::string_view>, + InjectedRelationalsImpl, NoInjectedRelationalsImpl>; + +template +class ReferenceProxy : InjectedRelationals { + using value_type = typename PolicyT::value_type; -template -class ReferenceProxy { public: ReferenceProxy(const ReferenceProxy&) = default; ReferenceProxy& operator=(const ReferenceProxy& other) { // Assign through the references - *ptr_ = *other.ptr_; + // TODO(sbenza): Make this better for strings to avoid the copy. + it_.Set(other.it_.Get()); return *this; } - friend void swap(ReferenceProxy a, ReferenceProxy b) { - using std::swap; - swap(*a.ptr_, *b.ptr_); - } + friend void swap(ReferenceProxy a, ReferenceProxy b) { a.it_.swap(b.it_); } - operator T() const { return *ptr_; } - void operator=(const T& value) const { *ptr_ = value; } - void operator=(T&& value) const { *ptr_ = std::move(value); } - RepeatedScalarIterator operator&() const { - return RepeatedScalarIterator(ptr_); - } + operator value_type() const { return it_.Get(); } + void operator=(const value_type& value) const { it_.Set(value); } + void operator=(value_type&& value) const { it_.Set(std::move(value)); } + Iterator operator&() const { return Iterator(it_); } private: friend IteratorTestPeer; - friend ReferenceProxy; - friend RepeatedScalarIterator; + friend ReferenceProxy; + friend Iterator; - explicit ReferenceProxy(T& elem) : ptr_(&elem) {} - T* ptr_; + explicit ReferenceProxy(typename PolicyT::Payload elem) : it_(elem) {} + typename PolicyT::Payload it_; }; -template -class ReferenceProxy { +template