| #ifndef GOOGLE_PROTOBUF_REPEATED_FIELD_PROXY_H__ | |
| #define GOOGLE_PROTOBUF_REPEATED_FIELD_PROXY_H__ | |
| #include <algorithm> | |
| #include <cstddef> | |
| #include <iterator> | |
| #include <string> | |
| #include <type_traits> | |
| #include <utility> | |
| #include "absl/log/absl_check.h" | |
| #include "absl/strings/cord.h" | |
| #include "absl/strings/string_view.h" | |
| #include "google/protobuf/raw_ptr.h" | |
| #include "google/protobuf/repeated_field.h" | |
| #include "google/protobuf/repeated_field_proxy_iterator.h" | |
| #include "google/protobuf/repeated_field_proxy_traits.h" | |
| #include "google/protobuf/repeated_ptr_field.h" | |
| // Must be included last. | |
| #include "google/protobuf/port_def.inc" | |
| // NOLINTBEGIN(readability-const-return-type) | |
| namespace google { | |
| namespace protobuf { | |
| template <typename ElementType> | |
| class RepeatedFieldProxy; | |
| namespace internal { | |
| template <typename ElementType> | |
| class RepeatedFieldOrProxy; | |
| template <typename ElementType, bool kOrProxy> | |
| class MutableRepeatedFieldProxyImpl; | |
| template <typename ElementType, bool kOrProxy> | |
| class ConstRepeatedFieldProxyImpl; | |
| template <typename ElementType, bool kOrProxy> | |
| class RepeatedFieldProxyInternalPrivateAccessHelper; | |
| namespace string_util { | |
| template <typename StringType, typename T> | |
| inline void CopyToString(StringType& element, T&& value) { | |
| // We want to explicitly enumerate all types we accept for constructing | |
| // strings, otherwise this would be a subtle place we'd be leaking the | |
| // `std::string` backing of `string_view` repeated fields. I.e. whatever new | |
| // backing we use for `string_view` fields would have to support all | |
| // `operator=` overloads that `std::string` has. | |
| // | |
| // With an explicit list, we no longer have this dependency. | |
| if constexpr (std::is_convertible_v<T, absl::string_view>) { | |
| element = absl::implicit_cast<absl::string_view>(value); | |
| } else if constexpr (std::is_convertible_v<T, const std::string&>) { | |
| element = absl::implicit_cast<const std::string&>(value); | |
| } else if constexpr (std::is_convertible_v<T, const char*>) { | |
| element = absl::implicit_cast<const char*>(value); | |
| } else { | |
| element = {value.data(), value.size()}; | |
| } | |
| } | |
| template <typename T> | |
| inline void SetElement(std::string& element, T&& value) { | |
| if constexpr (std::is_same_v<T&&, std::string&&>) { | |
| element = std::forward<T>(value); | |
| } else if constexpr (std::is_convertible_v<T, const absl::Cord&>) { | |
| const absl::Cord& cord = std::forward<T>(value); | |
| absl::CopyCordToString(cord, &element); | |
| } else { | |
| CopyToString(element, std::forward<T>(value)); | |
| } | |
| } | |
| template <typename T> | |
| inline void SetElement(absl::Cord& element, T&& value) { | |
| if constexpr (std::is_same_v<T&&, absl::Cord&&>) { | |
| element = std::forward<T>(value); | |
| } else if constexpr (std::is_convertible_v<T, const absl::Cord&>) { | |
| element = absl::implicit_cast<const absl::Cord&>(std::forward<T>(value)); | |
| } else { | |
| CopyToString(element, std::forward<T>(value)); | |
| } | |
| } | |
| } // namespace string_util | |
| // The base class for both mutable and const repeated field proxies. Implements | |
| // all of the common methods and dependent types for both classes. | |
| // | |
| // Class structure: | |
| // | |
| // internal {- - - - - - - - - - - - - - - - - - - - - - - | |
| // RepeatedFieldProxyBase | |
| // | | | |
| // MutableRepeatedFieldProxyImpl | | |
| // | | | |
| // | ConstRepeatedFieldProxyImpl | |
| // } - - - - - -|- - - - - - - - - - - - | - - - - - - - - | |
| // RepeatedFieldProxy<E>, | | |
| // RepeatedFieldOrProxy<E> | | |
| // RepeatedFieldProxy<const E>, | |
| // RepeatedFieldOrProxy<const E> | |
| // | |
| // RepeatedFieldProxyBase has the common implementation and interface between | |
| // both mutable and const proxies, and `Mutable*Impl` and `Const*Impl` have the | |
| // const/mutable-specific implementations + interfaces. | |
| // | |
| // Both `RepeatedFieldProxy` and `RepeatedFieldOrProxy` comprise the public | |
| // API and are thin wrappers around `Mutable*Impl` and `Const*Impl`, | |
| // implementing only the constructors and APIs particular to them. | |
| template <typename ElementType, bool kOrProxy> | |
| class RepeatedFieldProxyBase { | |
| protected: | |
| // If true, this is a view into a repeated field, meaning neither the elements | |
| // nor the container can be modified. If false, both the elements and the | |
| // container can be modified. | |
| static constexpr bool kIsConst = std::is_const_v<ElementType>; | |
| using Traits = RepeatedFieldTraits<std::remove_const_t<ElementType>>; | |
| using RepeatedFieldType = typename Traits::type; | |
| using ConstQualifiedRepeatedFieldType = | |
| std::conditional_t<kIsConst, const RepeatedFieldType, RepeatedFieldType>; | |
| public: | |
| using value_type = std::remove_const_t<ElementType>; | |
| using size_type = size_t; | |
| using difference_type = ptrdiff_t; | |
| using const_reference = typename Traits::const_reference; | |
| using const_iterator = | |
| internal::RepeatedFieldProxyIteratorImpl<const ElementType, | |
| /*kReverse=*/false, kOrProxy>; | |
| using iterator = | |
| internal::RepeatedFieldProxyIteratorImpl<ElementType, | |
| /*kReverse=*/false, kOrProxy>; | |
| using const_reverse_iterator = | |
| internal::RepeatedFieldProxyIteratorImpl<const ElementType, | |
| /*kReverse=*/true, kOrProxy>; | |
| using reverse_iterator = | |
| internal::RepeatedFieldProxyIteratorImpl<ElementType, | |
| /*kReverse=*/true, kOrProxy>; | |
| // Allow explicit conversion to the backing repeated field type. This will | |
| // perform a deep copy of the repeated field backed by this proxy. | |
| // | |
| // Note that this exposes `RepeatedFieldType`, but will be kept around for | |
| // backwards compatibility with code that uses `RepeatedField`s or | |
| // `RepeatedPtrField`s directly. We may freely change `RepeatedFieldType` so | |
| // long as we maintain this explicit conversion to the legacy container types. | |
| explicit operator RepeatedFieldType() const { | |
| return RepeatedFieldType(field()); | |
| } | |
| RepeatedFieldProxyBase(const RepeatedFieldProxyBase&) = default; | |
| // Assignment of repeated field proxies simply rebinds the proxy to a | |
| // different repeated field. It does not modify the underlying field. | |
| // | |
| // Copying should be done through `assign()`. | |
| RepeatedFieldProxyBase& operator=(const RepeatedFieldProxyBase&) = default; | |
| ~RepeatedFieldProxyBase() = default; | |
| // Returns true if the repeated field has no elements (size == 0). | |
| [[nodiscard]] bool empty() const { return field().empty(); } | |
| // Returns the number of elements in the repeated field. | |
| [[nodiscard]] size_type size() const { | |
| return static_cast<size_type>(field().size()); | |
| } | |
| // Returns a const reference or view into the element at the given index, | |
| // performing bounds checking in accordance with `bounds_check_mode_*`. | |
| [[nodiscard]] const const_reference get(size_type index) const { | |
| return field()[index]; | |
| } | |
| [[nodiscard]] const_iterator cbegin() const { return begin(); } | |
| [[nodiscard]] const_iterator cend() const { return end(); } | |
| [[nodiscard]] iterator begin() const { return iterator(field().begin()); } | |
| [[nodiscard]] iterator end() const { return iterator(field().end()); } | |
| [[nodiscard]] reverse_iterator rbegin() const { | |
| return reverse_iterator(end()); | |
| } | |
| [[nodiscard]] reverse_iterator rend() const { | |
| return reverse_iterator(begin()); | |
| } | |
| protected: | |
| explicit RepeatedFieldProxyBase(ConstQualifiedRepeatedFieldType& field) | |
| : field_(&field) {} | |
| ConstQualifiedRepeatedFieldType& field() const { return *field_; } | |
| private: | |
| ConstQualifiedRepeatedFieldType* PROTOBUF_NONNULL field_; | |
| }; | |
| // The following classes are used to specialize methods of `RepeatedFieldProxy` | |
| // based on the element type. Most methods do not need specialization, since | |
| // they look similar for all element types, maybe only differing in whether | |
| // `const_reference` resolves to a `const T&` or some value type like | |
| // `absl::string_view`. | |
| // | |
| // For methods that do have a different signature based on the element type, we | |
| // make a `*With<MethodName>` class that defines only that method, specialized | |
| // on the element type using whatever conditions make sense for the method. We | |
| // then inherit from this type in `RepeatedFieldProxy`. | |
| // Defines `set()` for primitive element types, which only take by value. | |
| template <typename ElementType, bool kOrProxy, typename Enable = void> | |
| class PROTOBUF_DECLSPEC_EMPTY_BASES RepeatedFieldProxyWithSet { | |
| public: | |
| // Sets the element at the given index to the given value. | |
| // | |
| // Performs bounds checking in accordance with `bounds_check_mode_*`. | |
| void set(size_t index, ElementType value) const { | |
| auto& field = | |
| RepeatedFieldProxyInternalPrivateAccessHelper<ElementType, | |
| kOrProxy>::field(this); | |
| field[index] = value; | |
| } | |
| }; | |
| // Defines `set()` for message element types, which take by const reference or | |
| // rvalue. | |
| template <typename ElementType, bool kOrProxy> | |
| class PROTOBUF_DECLSPEC_EMPTY_BASES RepeatedFieldProxyWithSet< | |
| ElementType, kOrProxy, | |
| std::enable_if_t<RepeatedElementTypeIsMessage<ElementType>>> { | |
| public: | |
| // Sets the element at the given index to the given value by move-assignment. | |
| // | |
| // Performs bounds checking in accordance with `bounds_check_mode_*`. | |
| void set(size_t index, ElementType&& value) const { | |
| auto& field = | |
| RepeatedFieldProxyInternalPrivateAccessHelper<ElementType, | |
| kOrProxy>::field(this); | |
| field[index] = std::move(value); | |
| } | |
| // Sets the element at the given index to the given value by copy-assignment. | |
| // | |
| // Performs bounds checking in accordance with `bounds_check_mode_*`. | |
| void set(size_t index, const ElementType& value) const { | |
| auto& field = | |
| RepeatedFieldProxyInternalPrivateAccessHelper<ElementType, | |
| kOrProxy>::field(this); | |
| field[index] = value; | |
| } | |
| }; | |
| // Defines `set()` for string element types, which dispatch to | |
| // `string_util::SetElement` and accept many string-like types. | |
| template <typename ElementType, bool kOrProxy> | |
| class PROTOBUF_DECLSPEC_EMPTY_BASES RepeatedFieldProxyWithSet< | |
| ElementType, kOrProxy, | |
| std::enable_if_t<RepeatedElementTypeIsString<ElementType>>> { | |
| public: | |
| // Sets the element at the given index to the given value. | |
| // | |
| // Performs bounds checking in accordance with `bounds_check_mode_*`. | |
| template <typename T> | |
| void set(size_t index, T&& value) const { | |
| auto& field = | |
| RepeatedFieldProxyInternalPrivateAccessHelper<ElementType, | |
| kOrProxy>::field(this); | |
| string_util::SetElement(field[index], std::forward<T>(value)); | |
| } | |
| }; | |
| // Defines `push_back()` for primitive element types, which only take by value. | |
| template <typename ElementType, bool kOrProxy, typename Enable = void> | |
| class PROTOBUF_DECLSPEC_EMPTY_BASES RepeatedFieldProxyWithPushBack { | |
| public: | |
| // Appends the given value to the end of the repeated field. | |
| void push_back(ElementType value) const { | |
| RepeatedFieldProxyInternalPrivateAccessHelper<ElementType, kOrProxy>::Add( | |
| this, value); | |
| } | |
| }; | |
| // Defines `push_back()` for message element types, which take by const | |
| // reference or rvalue. | |
| template <typename ElementType, bool kOrProxy> | |
| class PROTOBUF_DECLSPEC_EMPTY_BASES RepeatedFieldProxyWithPushBack< | |
| ElementType, kOrProxy, | |
| std::enable_if_t<RepeatedElementTypeIsMessage<ElementType>>> { | |
| public: | |
| // Appends the given value to the end of the repeated field by move | |
| // construction/assignment. | |
| void push_back(ElementType&& value) const { | |
| RepeatedFieldProxyInternalPrivateAccessHelper<ElementType, kOrProxy>::Add( | |
| this, std::move(value)); | |
| } | |
| // Appends the given value to the end of the repeated field by copy | |
| // construction/assignment. | |
| void push_back(const ElementType& value) const { | |
| RepeatedFieldProxyInternalPrivateAccessHelper<ElementType, kOrProxy>::Add( | |
| this, value); | |
| } | |
| }; | |
| // Defines `push_back()` for string element types, which dispatch to | |
| // `string_util::SetElement` and accept many string-like types. | |
| template <typename ElementType, bool kOrProxy> | |
| class PROTOBUF_DECLSPEC_EMPTY_BASES RepeatedFieldProxyWithPushBack< | |
| ElementType, kOrProxy, | |
| std::enable_if_t<RepeatedElementTypeIsString<ElementType>>> { | |
| public: | |
| // Appends the given value to the end of the repeated field. | |
| template <typename T> | |
| void push_back(T&& value) const { | |
| string_util::SetElement( | |
| RepeatedFieldProxyInternalPrivateAccessHelper<ElementType, | |
| kOrProxy>::Add(this), | |
| std::forward<T>(value)); | |
| } | |
| }; | |
| // Defines the default `emplace_back()`. Simply takes any arguments that can be | |
| // passed to the constructor of `ElementType` and in-place constructs the | |
| // element at the end of the repeated field. Returns a reference to the newly | |
| // constructed element. | |
| template <typename ElementType, bool kOrProxy, typename Enable = void> | |
| class PROTOBUF_DECLSPEC_EMPTY_BASES RepeatedFieldProxyWithEmplaceBack { | |
| public: | |
| // In-place constructs an element at the end of the repeated field, returning | |
| // a reference to the newly constructed element. | |
| template <typename... Args> | |
| auto& emplace_back(Args&&... args) const { | |
| return RepeatedFieldProxyInternalPrivateAccessHelper< | |
| ElementType, kOrProxy>::Emplace(this, std::forward<Args>(args)...); | |
| } | |
| }; | |
| // Defines `emplace_back()` for primitive element types, which returns by value | |
| // to avoid leaking references to the underlying field. | |
| template <typename ElementType, bool kOrProxy> | |
| class PROTOBUF_DECLSPEC_EMPTY_BASES RepeatedFieldProxyWithEmplaceBack< | |
| ElementType, kOrProxy, | |
| std::enable_if_t<RepeatedElementTypeIsPrimitive<ElementType>>> { | |
| public: | |
| // In-place constructs an element at the end of the repeated field, returning | |
| // the newly constructed element by value. | |
| template <typename... Args> | |
| const ElementType emplace_back(Args&&... args) const { | |
| return RepeatedFieldProxyInternalPrivateAccessHelper< | |
| ElementType, kOrProxy>::Emplace(this, std::forward<Args>(args)...); | |
| } | |
| }; | |
| // Defines `emplace_back()` for `absl::string_view` element types. We explicitly | |
| // list all constructors we want to support for repeated `string_views` to not | |
| // leak the `std::string` backing of repeated `string_views`. | |
| template <typename ElementType, bool kOrProxy> | |
| class PROTOBUF_DECLSPEC_EMPTY_BASES RepeatedFieldProxyWithEmplaceBack< | |
| ElementType, kOrProxy, | |
| std::enable_if_t<std::is_same_v<ElementType, absl::string_view>>> { | |
| public: | |
| // In-place constructs an element at the end of the repeated field, returning | |
| // a string_view of the newly constructed element. | |
| const absl::string_view emplace_back() const { | |
| return RepeatedFieldProxyInternalPrivateAccessHelper< | |
| ElementType, kOrProxy>::Emplace(this); | |
| } | |
| // In-place constructs an element at the end of the repeated field, returning | |
| // a string_view of the newly constructed element. | |
| const absl::string_view emplace_back(absl::string_view value) const { | |
| return RepeatedFieldProxyInternalPrivateAccessHelper< | |
| ElementType, kOrProxy>::Emplace(this, value); | |
| } | |
| // In-place constructs an element at the end of the repeated field, returning | |
| // a string_view of the newly constructed element. | |
| const absl::string_view emplace_back(std::string&& value) const { | |
| return RepeatedFieldProxyInternalPrivateAccessHelper< | |
| ElementType, kOrProxy>::Emplace(this, std::move(value)); | |
| } | |
| // In-place constructs an element at the end of the repeated field, returning | |
| // a string_view of the newly constructed element. | |
| const absl::string_view emplace_back(const std::string& value) const { | |
| return RepeatedFieldProxyInternalPrivateAccessHelper< | |
| ElementType, kOrProxy>::Emplace(this, value); | |
| } | |
| // In-place constructs an element at the end of the repeated field, returning | |
| // a string_view of the newly constructed element. | |
| const absl::string_view emplace_back( | |
| const char* PROTOBUF_NONNULL value) const { | |
| return RepeatedFieldProxyInternalPrivateAccessHelper< | |
| ElementType, kOrProxy>::Emplace(this, value); | |
| } | |
| }; | |
| // Defines `resize(new_size, value)` for all non-string repeated fields. | |
| template <typename ElementType, bool kOrProxy, typename Enable = void> | |
| class PROTOBUF_DECLSPEC_EMPTY_BASES RepeatedFieldProxyWithResize { | |
| public: | |
| // Resizes the repeated field to `new_size` elements. If `new_size` is smaller | |
| // than the current size, the field is truncated. Otherwise, the field is | |
| // extended with copies of `value`. | |
| void resize(size_t new_size, const ElementType& value) const { | |
| auto& field = | |
| RepeatedFieldProxyInternalPrivateAccessHelper<ElementType, | |
| kOrProxy>::field(this); | |
| field.resize(new_size, value); | |
| } | |
| }; | |
| // Defines `resize(new_size, value)` for non-Cord string repeated fields. | |
| template <typename ElementType, bool kOrProxy> | |
| class PROTOBUF_DECLSPEC_EMPTY_BASES RepeatedFieldProxyWithResize< | |
| ElementType, kOrProxy, | |
| std::enable_if_t<RepeatedElementTypeIsString<ElementType> && | |
| !std::is_same_v<ElementType, absl::Cord>>> { | |
| public: | |
| // Resizes the repeated field to `new_size` elements. If `new_size` is smaller | |
| // than the current size, the field is truncated. Otherwise, the field is | |
| // extended with copies of `value`. | |
| void resize(size_t new_size, absl::string_view value) const { | |
| auto& field = | |
| RepeatedFieldProxyInternalPrivateAccessHelper<ElementType, | |
| kOrProxy>::field(this); | |
| field.resize(new_size, value); | |
| } | |
| }; | |
| // Defines `resize(new_size, value)` for repeated Cords. | |
| template <typename ElementType, bool kOrProxy> | |
| class PROTOBUF_DECLSPEC_EMPTY_BASES RepeatedFieldProxyWithResize< | |
| ElementType, kOrProxy, | |
| std::enable_if_t<std::is_same_v<ElementType, absl::Cord>>> { | |
| public: | |
| // Resizes the repeated field to `new_size` elements. If `new_size` is smaller | |
| // than the current size, the field is truncated. Otherwise, the field is | |
| // extended with copies of `value`. | |
| void resize(size_t new_size, const absl::Cord& value) const { | |
| auto& field = | |
| RepeatedFieldProxyInternalPrivateAccessHelper<ElementType, | |
| kOrProxy>::field(this); | |
| field.resize(new_size, value); | |
| } | |
| }; | |
| template <typename ElementType, bool kOrProxy> | |
| class PROTOBUF_DECLSPEC_EMPTY_BASES MutableRepeatedFieldProxyImpl | |
| : public internal::RepeatedFieldProxyBase<ElementType, kOrProxy>, | |
| public internal::RepeatedFieldProxyWithSet<ElementType, kOrProxy>, | |
| public internal::RepeatedFieldProxyWithPushBack<ElementType, kOrProxy>, | |
| public internal::RepeatedFieldProxyWithEmplaceBack<ElementType, kOrProxy>, | |
| public internal::RepeatedFieldProxyWithResize<ElementType, kOrProxy> { | |
| static_assert(!std::is_const_v<ElementType>); | |
| protected: | |
| using Base = internal::RepeatedFieldProxyBase<ElementType, kOrProxy>; | |
| using typename Base::RepeatedFieldType; | |
| using Base::field; | |
| public: | |
| using typename Base::const_iterator; | |
| using typename Base::iterator; | |
| using typename Base::size_type; | |
| using reference = | |
| typename internal::RepeatedFieldTraits<ElementType>::reference; | |
| MutableRepeatedFieldProxyImpl(const MutableRepeatedFieldProxyImpl& other) = | |
| default; | |
| // Mutable proxies are not assignable. This is intentional to avoid confusion | |
| // with the `assign` method, which reassigns the underlying repeated field. | |
| MutableRepeatedFieldProxyImpl& operator=( | |
| const MutableRepeatedFieldProxyImpl&) = delete; | |
| // Returns a type which references the element at the given index. Performs | |
| // bounds checking in accordance with `bounds_check_mode_*`. | |
| [[nodiscard]] const reference operator[](size_type index) const { | |
| return field()[index]; | |
| } | |
| // Removes the last element from the repeated field. | |
| void pop_back() const { field().RemoveLast(); } | |
| // Removes all elements from the repeated field. The field will be empty after | |
| // this call. | |
| void clear() const { field().Clear(); } | |
| // Removes the element at `position` from the repeated field. Returns an | |
| // iterator to the element immediately following the removed element. | |
| iterator erase(const_iterator position) const { | |
| // The internal iterator type may not match the proxy iterator type (for | |
| // example for `absl::string_view` proxies which are backed by | |
| // `std::string`). To avoid special casing, we will always cast to the | |
| // internal iterator type before passing down to erase, then cast back to | |
| // the proxy iterator type upon return. This conversion is redundant for | |
| // types which have matching exposed and internal element types. | |
| using const_internal_iterator = typename RepeatedFieldType::const_iterator; | |
| return iterator(field().erase(const_internal_iterator(position))); | |
| } | |
| // Removes the elements in the range `[first, last)` from the repeated field. | |
| // Returns an iterator to the element immediately following the last removed | |
| // element. | |
| iterator erase(const_iterator first, const_iterator last) const { | |
| using const_internal_iterator = typename RepeatedFieldType::const_iterator; | |
| return iterator(field().erase(const_internal_iterator(first), | |
| const_internal_iterator(last))); | |
| } | |
| // Copy-assigns the elements in the range `[begin, end)` to the repeated | |
| // field. | |
| // | |
| // If `begin` or `end` is an iterator into this repeated field, the behavior | |
| // is undefined. | |
| template < | |
| typename Iter, | |
| // A seemingly redundant verification that `Iter` is an iterator type. | |
| // Even though we use `std::iterator_traits` below, we duplicate the | |
| // condition here in case the implementation changes. | |
| typename = std::void_t<typename std::iterator_traits<Iter>::value_type>> | |
| auto assign(Iter begin, Iter end) const | |
| // Verify that the iterator value type is assignable to `ElementType`. | |
| // Pass through `push_back`, which is a catch-all for allowed conversions | |
| // to the element type. | |
| -> std::void_t<decltype(this->push_back(*begin))> { | |
| field().Clear(); | |
| // Forward iterators in C++ are required to model `std::incrementable`, | |
| // which means they are suitable for multi-pass algorithms, and therefore | |
| // support `std::distance`. | |
| if constexpr (std::is_base_of_v< | |
| std::forward_iterator_tag, | |
| typename std::iterator_traits<Iter>::iterator_category>) { | |
| int distance = static_cast<int>(std::distance(begin, end)); | |
| field().ReserveWithArena(arena(), distance); | |
| } | |
| for (; begin != end; ++begin) { | |
| this->push_back(*begin); | |
| } | |
| } | |
| // A hint to the container to expect to grow/shrink to `new_size` elements. | |
| // This may allow the container to make optimizations to avoid reallocations, | |
| // but may also be ignored. | |
| void reserve(size_type new_size) const { | |
| field().ReserveWithArena(arena(), new_size); | |
| } | |
| // Resizes the repeated field to `new_size` elements. If `new_size` is smaller | |
| // than the current size, the field is truncated. Otherwise, the field is | |
| // extended with default-valued elements. | |
| void resize(size_t new_size) const { field().resize(new_size); } | |
| // Because we have an overload of `resize` in this class, we need to | |
| // explicitly inherit the overload from the base class to avoid hiding it. | |
| using internal::RepeatedFieldProxyWithResize<ElementType, kOrProxy>::resize; | |
| protected: | |
| MutableRepeatedFieldProxyImpl(RepeatedFieldType& field, | |
| Arena* PROTOBUF_NULLABLE arena) | |
| : Base(field), arena_(arena) { | |
| ABSL_DCHECK_EQ(arena, field.GetArena()); | |
| } | |
| Arena* PROTOBUF_NULLABLE arena() const { return arena_; } | |
| // The following methods all forward to the backing repeated fields. This is | |
| // done here for access to private members of the legacy containers, which | |
| // only need to friend `MutableRepeatedFieldProxyImpl`. | |
| auto& Add() const { return *field().AddWithArena(arena()); } | |
| auto& Add(ElementType&& value) const { | |
| return *field().AddWithArena(arena(), std::move(value)); | |
| } | |
| auto& Add(const ElementType& value) const { | |
| return *field().AddWithArena(arena(), value); | |
| } | |
| template <typename... Args> | |
| auto& Emplace(Args&&... args) const { | |
| return *field().EmplaceWithArena(arena(), std::forward<Args>(args)...); | |
| } | |
| private: | |
| friend RepeatedFieldProxyInternalPrivateAccessHelper<ElementType, kOrProxy>; | |
| // Rebinds the proxy to a different repeated field. Intentionally not exposed | |
| // in the public interface. | |
| void rebind(const MutableRepeatedFieldProxyImpl& other) { | |
| static_cast<Base&>(*this) = static_cast<const Base&>(other); | |
| arena_ = other.arena_; | |
| } | |
| Arena* PROTOBUF_NULLABLE arena_; | |
| }; | |
| template <typename ElementType, bool kOrProxy> | |
| class PROTOBUF_DECLSPEC_EMPTY_BASES ConstRepeatedFieldProxyImpl | |
| : public internal::RepeatedFieldProxyBase<const ElementType, kOrProxy> { | |
| // A specialization of RepeatedFieldProxy for const proxies. This is needed | |
| // for mutating methods to not be exposed on const proxies. | |
| protected: | |
| using Base = internal::RepeatedFieldProxyBase<const ElementType, kOrProxy>; | |
| // Inherit constructors, but don't publicly expose them. | |
| // | |
| // Repeated field proxies have no public constructors aside from a copy | |
| // constructor. This is intentional, as layout of data that is proxied is an | |
| // implementation detail. By not exposing a way to construct a proxy, we can | |
| // freely change the layout of the underlying repeated field. | |
| using Base::Base; | |
| using Base::field; | |
| public: | |
| ConstRepeatedFieldProxyImpl() | |
| : Base(*internal::RawPtr<const typename Base::RepeatedFieldType>()) {} | |
| using typename Base::const_reference; | |
| using typename Base::size_type; | |
| ConstRepeatedFieldProxyImpl(const ConstRepeatedFieldProxyImpl& other) = | |
| default; | |
| ConstRepeatedFieldProxyImpl& operator=(const ConstRepeatedFieldProxyImpl&) = | |
| default; | |
| // Returns a type which references the element at the given index. Performs | |
| // bounds checking in accordance with `bounds_check_mode_*`. | |
| [[nodiscard]] const const_reference operator[](size_type index) const { | |
| return field()[index]; | |
| } | |
| private: | |
| // Note that we don't need an arena pointer here, since we don't mutate the | |
| // underlying repeated field. | |
| }; | |
| } // namespace internal | |
| // A proxy for a repeated field of type `ElementType` in a Protobuf message. | |
| // Proxies alias the repeated field and provide an interface to read or modify | |
| // it, following STL naming conventions. | |
| // | |
| // Proxies themselves are value types, meaning they should be passed around by | |
| // value similar to `absl::string_view` or `absl::Span`. | |
| // | |
| // Proxies cannot be constructed directly. They are returned from a message's | |
| // repeated field accessors which have the `features.(pb.cpp).repeated_type = | |
| // PROXY` annotation. This annotation is currently only available in edition | |
| // `UNSTABLE`, but will eventually be available in an upcoming edition. | |
| template <typename ElementType> | |
| class PROTOBUF_DECLSPEC_EMPTY_BASES RepeatedFieldProxy final | |
| : public internal::MutableRepeatedFieldProxyImpl<ElementType, | |
| /*kOrProxy=*/false> { | |
| static_assert(!std::is_const_v<ElementType>); | |
| private: | |
| using Base = internal::MutableRepeatedFieldProxyImpl<ElementType, | |
| /*kOrProxy=*/false>; | |
| using Base::Base; | |
| using Base::field; | |
| public: | |
| // Copy-assigns `other` into this repeated field. | |
| // | |
| // This method exists because mutable proxies cannot be rebound. | |
| void assign(RepeatedFieldProxy<const ElementType> other) const { | |
| field().CopyFrom(other.field()); | |
| } | |
| // Because we have an overload of `assign` in this class, we need to | |
| // explicitly inherit the overload from the base class to avoid hiding it. | |
| using Base::assign; | |
| // Move-assigns `other` into this repeated field. `other` is left in a valid | |
| // but unspecified state. | |
| void move_assign(RepeatedFieldProxy<ElementType> other) const { | |
| field() = std::move(other.field()); | |
| } | |
| // Swaps the contents of this repeated field with `other`. | |
| // | |
| // Invalidates all iterators. Pointer stability is not guaranteed across the | |
| // swap for any element of either repeated field. | |
| // | |
| // If the underlying repeated fields are on different arenas, this may force | |
| // deep copies of the elements. | |
| void swap(RepeatedFieldProxy other) const { field().Swap(&other.field()); } | |
| private: | |
| friend RepeatedFieldProxy<const ElementType>; | |
| friend internal::RepeatedFieldOrProxy<ElementType>; | |
| friend internal::RepeatedFieldOrProxy<const ElementType>; | |
| friend internal::RepeatedFieldProxyInternalPrivateAccessHelper< | |
| ElementType, /*kOrProxy=*/false>; | |
| }; | |
| template <typename ElementType> | |
| class PROTOBUF_DECLSPEC_EMPTY_BASES RepeatedFieldProxy<const ElementType> final | |
| : public internal::ConstRepeatedFieldProxyImpl<ElementType, | |
| /*kOrProxy=*/false> { | |
| // A specialization of RepeatedFieldProxy for const proxies. This is needed | |
| // for mutating methods to not be exposed on const proxies. | |
| private: | |
| using Base = internal::ConstRepeatedFieldProxyImpl<ElementType, | |
| /*kOrProxy=*/false>; | |
| // Inherit constructors, but don't publicly expose them. | |
| // | |
| // Repeated field proxies have no public constructors aside from a copy | |
| // constructor. This is intentional, as layout of data that is proxied is an | |
| // implementation detail. By not exposing a way to construct a proxy, we can | |
| // freely change the layout of the underlying repeated field. | |
| using Base::Base; | |
| public: | |
| RepeatedFieldProxy() = default; | |
| RepeatedFieldProxy(const RepeatedFieldProxy& other) = default; | |
| RepeatedFieldProxy& operator=(const RepeatedFieldProxy& other) = default; | |
| // Allow implicit conversion from a mutable RepeatedFieldProxy to a const | |
| // RepeatedFieldProxy. | |
| // | |
| // NOLINTNEXTLINE(google-explicit-constructor) | |
| RepeatedFieldProxy(RepeatedFieldProxy<ElementType> other) | |
| : Base(other.field()) {} | |
| private: | |
| friend RepeatedFieldProxy<ElementType>; | |
| friend internal::RepeatedFieldOrProxy<const ElementType>; | |
| friend internal::RepeatedFieldProxyInternalPrivateAccessHelper< | |
| const ElementType, /*kOrProxy=*/false>; | |
| }; | |
| // The size of proxies is not really important, since they should mostly be | |
| // passed around by value and inlined away to oblivion. Regardless, size | |
| // assertions guarantee that the compiler hasn't introduced invisible members | |
| // that we didn't notice (e.g. `PROTOBUF_DECLSPEC_EMPTY_BASES`). | |
| static_assert(sizeof(RepeatedFieldProxy<int>) == 2 * sizeof(void*)); | |
| static_assert(sizeof(RepeatedFieldProxy<const int>) == sizeof(void*)); | |
| namespace internal { | |
| // A helper class for accessing private members of `RepeatedFieldProxy` in | |
| // Protobuf internal code. | |
| // | |
| // DO NOT USE this class for any reason outside of protobuf internal code. | |
| template <typename ElementType, bool kOrProxy = false> | |
| class RepeatedFieldProxyInternalPrivateAccessHelper { | |
| using ProxyType = | |
| std::conditional_t<kOrProxy, RepeatedFieldOrProxy<ElementType>, | |
| RepeatedFieldProxy<ElementType>>; | |
| using MutableProxyImpl = MutableRepeatedFieldProxyImpl<ElementType, kOrProxy>; | |
| // Casts up to a `MutableRepeatedFieldProxyImpl<ElementType>` from a subclass | |
| // of `MutableRepeatedFieldProxyImpl<ElementType>`. This is used to implement | |
| // the CRTP pattern for `*With<MethodName>` classes. | |
| template <typename C> | |
| static MutableRepeatedFieldProxyImpl<ElementType, kOrProxy> ToProxyType( | |
| const C* PROTOBUF_NONNULL proxy) { | |
| return *static_cast< | |
| const MutableRepeatedFieldProxyImpl<ElementType, kOrProxy>*>(proxy); | |
| } | |
| public: | |
| template <typename... Args> | |
| static RepeatedFieldProxy<ElementType> Construct(Args&&... args) { | |
| return RepeatedFieldProxy<ElementType>(std::forward<Args>(args)...); | |
| } | |
| static auto& field(const ProxyType& proxy) { return proxy.field(); } | |
| // Takes any subclass of `RepeatedFieldProxy<ElementType>`, upcasts to | |
| // `RepeatedFieldProxy<ElementType>`, then calls `field()`. This is used to | |
| // implement the CRTP pattern for `*With<MethodName>` classes. | |
| template <typename C> | |
| static auto& field(const C* PROTOBUF_NONNULL proxy) { | |
| return ToProxyType(proxy).field(); | |
| } | |
| static void rebind(MutableProxyImpl& proxy, const MutableProxyImpl& other) { | |
| proxy.rebind(other); | |
| } | |
| template <typename C, typename... Args> | |
| static auto& Add(const C* PROTOBUF_NONNULL proxy, Args&&... args) { | |
| return ToProxyType(proxy).Add(std::forward<Args>(args)...); | |
| } | |
| template <typename C, typename... Args> | |
| static auto& Emplace(const C* PROTOBUF_NONNULL proxy, Args&&... args) { | |
| return ToProxyType(proxy).Emplace(std::forward<Args>(args)...); | |
| } | |
| }; | |
| // A mutable `RepeatedFieldOrProxy` for a repeated field of type `ElementType` | |
| // in a Protobuf message. Proxies alias the repeated field and provide an | |
| // interface to read or modify it, following STL naming conventions. | |
| // | |
| // Unlike `RepeatedFieldProxy`, `RepeatedFieldOrProxy` can be constructed from | |
| // the legacy repeated field containers (`google::protobuf::RepeatedField` and | |
| // `google::protobuf::RepeatedPtrField`). This container can be used in code which has not | |
| // yet fully migrated to proxies. It is particularly useful for function | |
| // parameters that have many callers, allowing the callers to be migrated to | |
| // proxies incrementally. | |
| // | |
| // Proxies themselves are value types, meaning they should be passed around by | |
| // value similar to `absl::string_view` or `absl::Span`. | |
| template <typename ElementType> | |
| class RepeatedFieldOrProxy final | |
| : public internal::MutableRepeatedFieldProxyImpl<ElementType, | |
| /*kOrProxy=*/true> { | |
| // `const ElementType` is specialized below. | |
| static_assert(!std::is_const_v<ElementType>); | |
| private: | |
| using Base = internal::MutableRepeatedFieldProxyImpl<ElementType, | |
| /*kOrProxy=*/true>; | |
| using RepeatedFieldType = typename Base::RepeatedFieldType; | |
| // Inherit constructors. | |
| using Base::Base; | |
| using Base::field; | |
| public: | |
| // Allow implicit conversion from a RepeatedField to a RepeatedFieldOrProxy. | |
| // | |
| // NOLINTNEXTLINE(google-explicit-constructor) | |
| RepeatedFieldOrProxy(RepeatedFieldType& field) | |
| : Base(field, field.GetArena()) {} | |
| // Allow implicit conversion from a RepeatedField* to a RepeatedFieldOrProxy, | |
| // but inline this to call the RepeatedFieldOrProxy(RepeatedFieldType& field) | |
| // constructor. | |
| // | |
| // This will be used to ease migration along for functions that currently take | |
| // a RepeatedField* parameter. If we allow implicit conversion from | |
| // RepeatedField* to RepeatedFieldOrProxy, then we can change the type of the | |
| // parameter from RepeatedField<T>* to RepeatedFieldOrProxy<T> without | |
| // updating any callers. Then, the C++ inliner will later come along and | |
| // dereference the repeated field pointer argument to the method at callsites. | |
| PROTOBUF_REFACTOR_INLINE() | |
| // NOLINTNEXTLINE | |
| RepeatedFieldOrProxy(RepeatedFieldType* PROTOBUF_NONNULL field) | |
| : RepeatedFieldOrProxy(*field) {} | |
| // Allow implicit conversion from a RepeatedFieldProxy to a | |
| // RepeatedFieldOrProxy. | |
| // | |
| // NOLINTNEXTLINE(google-explicit-constructor) | |
| RepeatedFieldOrProxy(RepeatedFieldProxy<ElementType> proxy) | |
| : Base(proxy.field(), proxy.arena()) {} | |
| // Allow explicit conversion to the legacy repeated field container. | |
| // | |
| // Note: this performs a deep copy of the underlying repeated field. | |
| explicit operator std::remove_const_t<RepeatedFieldType>() const { | |
| return RepeatedFieldType(static_cast<const Base&>(*this)); | |
| } | |
| // Note: we do not directly expose the following methods from the base class | |
| // because they have overloads that take a `RepeatedFieldProxy`. We re-define | |
| // them below with overloads that take `RepeatedFieldOrProxy`. | |
| // Copy-assigns `other` into this repeated field. | |
| // | |
| // This method exists because mutable proxies cannot be rebound. | |
| void assign(RepeatedFieldOrProxy<const ElementType> other) const { | |
| Base::field().CopyFrom(other.field()); | |
| } | |
| // Because we have an overload of `assign` in this class, we need to | |
| // explicitly inherit the overload from the base class to avoid hiding it. | |
| using Base::assign; | |
| // Move-assigns `other` into this repeated field. `other` is left in a valid | |
| // but unspecified state. | |
| // | |
| // This method only differs from `assign` in that it is a hint that you don't | |
| // need the contents of `other` anymore. It is not guaranteed that the | |
| // contents will be efficiently transferred, nor that pointer stability will | |
| // be preserved for elements of `other`. | |
| void move_assign(RepeatedFieldOrProxy other) const { | |
| field() = std::move(other.field()); | |
| } | |
| // Swaps the contents of this repeated field with `other`. | |
| // | |
| // Invalidates all iterators. Pointer stability is not guaranteed across the | |
| // swap for any element of either repeated field. | |
| // | |
| // If the underlying repeated fields are on different arenas, this may force | |
| // deep copies of the elements. | |
| void swap(RepeatedFieldOrProxy other) const { | |
| Base::field().Swap(&other.field()); | |
| } | |
| private: | |
| friend RepeatedFieldProxy<ElementType>; | |
| friend RepeatedFieldOrProxy<const ElementType>; | |
| friend internal::RepeatedFieldProxyInternalPrivateAccessHelper< | |
| ElementType, /*kOrProxy=*/true>; | |
| }; | |
| // A const proxy for a repeated field of type `ElementType` in a Protobuf | |
| // message. Proxies alias the repeated field and provide an interface to read or | |
| // modify it, following STL naming conventions. | |
| // | |
| // Unlike `RepeatedFieldProxy`, `RepeatedFieldOrProxy` can be constructed from | |
| // the legacy repeated field containers (`google::protobuf::RepeatedField` and | |
| // `google::protobuf::RepeatedPtrField`). This container can be used in code which has not | |
| // yet fully migrated to proxies. It is particularly useful for function | |
| // parameters that have many callers, allowing the callers to be migrated to | |
| // proxies incrementally. | |
| // | |
| // Proxies themselves are value types, meaning they should be passed around by | |
| // value similar to `absl::string_view` or `absl::Span`. | |
| template <typename ElementType> | |
| class RepeatedFieldOrProxy<const ElementType> final | |
| : public internal::ConstRepeatedFieldProxyImpl<ElementType, | |
| /*kOrProxy=*/true> { | |
| using Base = internal::ConstRepeatedFieldProxyImpl<ElementType, | |
| /*kOrProxy=*/true>; | |
| using RepeatedFieldType = typename Base::RepeatedFieldType; | |
| // Inherit constructors. | |
| using Base::Base; | |
| using Base::field; | |
| public: | |
| RepeatedFieldOrProxy() = default; | |
| RepeatedFieldOrProxy(const RepeatedFieldOrProxy& other) = default; | |
| RepeatedFieldOrProxy& operator=(const RepeatedFieldOrProxy& other) = default; | |
| // Allow implicit conversion from a mutable RepeatedFieldOrProxy to a const | |
| // RepeatedFieldOrProxy. | |
| // | |
| // NOLINTNEXTLINE(google-explicit-constructor) | |
| RepeatedFieldOrProxy(RepeatedFieldOrProxy<ElementType> other) | |
| : Base(other.field()) {} | |
| // Allow implicit conversion from a RepeatedField to a RepeatedFieldOrProxy. | |
| // | |
| // NOLINTNEXTLINE(google-explicit-constructor) | |
| RepeatedFieldOrProxy(const RepeatedFieldType& field) : Base(field) {} | |
| // Allow implicit conversion from a const RepeatedField* to a | |
| // RepeatedFieldOrProxy, but inline this to call the | |
| // RepeatedFieldOrProxy(RepeatedFieldType& field) constructor. | |
| // | |
| // This will be used to ease migration along for functions that currently take | |
| // a const RepeatedField* parameter. If we allow implicit conversion from | |
| // const RepeatedField* to RepeatedFieldOrProxy, then we can change the type | |
| // of the parameter from const RepeatedField<T>* to | |
| // RepeatedFieldOrProxy<const T> without updating any callers. Then, the C++ | |
| // inliner will later come along and dereference the repeated field pointer | |
| // argument to the method at callsites. | |
| PROTOBUF_REFACTOR_INLINE() | |
| // NOLINTNEXTLINE | |
| RepeatedFieldOrProxy(RepeatedFieldType* PROTOBUF_NONNULL field) | |
| : RepeatedFieldOrProxy(*field) {} | |
| // Allow implicit conversion from a RepeatedFieldProxy to a | |
| // RepeatedFieldOrProxy. | |
| // | |
| // NOLINTNEXTLINE(google-explicit-constructor) | |
| RepeatedFieldOrProxy(RepeatedFieldProxy<ElementType> proxy) | |
| : Base(proxy.field()) {} | |
| // NOLINTNEXTLINE(google-explicit-constructor) | |
| RepeatedFieldOrProxy(RepeatedFieldProxy<const ElementType> proxy) | |
| : Base(proxy.field()) {} | |
| // Allow explicit conversion to the legacy repeated field container. | |
| // | |
| // Note: this performs a deep copy of the underlying repeated field. | |
| explicit operator RepeatedFieldType() const { | |
| return RepeatedFieldType(static_cast<const Base&>(*this)); | |
| } | |
| private: | |
| friend RepeatedFieldOrProxy<ElementType>; | |
| }; | |
| static_assert(sizeof(RepeatedFieldOrProxy<int>) == | |
| sizeof(RepeatedFieldProxy<int>), | |
| "Mutable `RepeatedFieldOrProxy` is not the expected size"); | |
| static_assert(sizeof(RepeatedFieldOrProxy<const int>) == | |
| sizeof(RepeatedFieldProxy<const int>), | |
| "Const `RepeatedFieldOrProxy` is not the expected size"); | |
| } // namespace internal | |
| // Like C++20's std::erase_if, for RepeatedFieldProxy | |
| template <int&... DeductionBarrier, typename T, typename Pred> | |
| size_t erase_if(RepeatedFieldProxy<T> cont, Pred pred) { | |
| return google::protobuf::erase_if( | |
| internal::RepeatedFieldProxyInternalPrivateAccessHelper< | |
| T, /*kOrProxy=*/false>::field(cont), | |
| pred); | |
| } | |
| // Like C++20's std::erase, for RepeatedFieldProxy | |
| template <int&... DeductionBarrier, typename T, typename U> | |
| size_t erase(RepeatedFieldProxy<T> cont, const U& value) { | |
| return google::protobuf::erase(internal::RepeatedFieldProxyInternalPrivateAccessHelper< | |
| T, /*kOrProxy=*/false>::field(cont), | |
| value); | |
| } | |
| // Like C++20's std::erase_if, for RepeatedFieldOrProxy. | |
| template <int&... DeductionBarrier, typename T, typename Pred> | |
| size_t erase_if(internal::RepeatedFieldOrProxy<T> cont, Pred pred) { | |
| return google::protobuf::erase_if( | |
| internal::RepeatedFieldProxyInternalPrivateAccessHelper< | |
| T, /*kOrProxy=*/true>::field(cont), | |
| pred); | |
| } | |
| // Like C++20's std::erase, for RepeatedFieldOrProxy. | |
| template <int&... DeductionBarrier, typename T, typename U> | |
| size_t erase(internal::RepeatedFieldOrProxy<T> cont, const U& value) { | |
| return google::protobuf::erase(internal::RepeatedFieldProxyInternalPrivateAccessHelper< | |
| T, /*kOrProxy=*/true>::field(cont), | |
| value); | |
| } | |
| // Like C++20's std::sort, for RepeatedFieldProxy. | |
| template <int&... DeductionBarrier, typename T, typename Compare> | |
| void c_sort(RepeatedFieldProxy<T> cont, Compare cmp) { | |
| google::protobuf::sort(cont.begin(), cont.end(), cmp); | |
| } | |
| // Like C++20's std::sort, for RepeatedFieldProxy, with default comparison. | |
| template <int&... DeductionBarrier, typename T> | |
| void c_sort(RepeatedFieldProxy<T> cont) { | |
| google::protobuf::sort(cont.begin(), cont.end()); | |
| } | |
| // Like C++20's std::stable_sort, for RepeatedFieldProxy. | |
| template <int&... DeductionBarrier, typename T, typename Compare> | |
| void c_stable_sort(RepeatedFieldProxy<T> cont, Compare cmp) { | |
| google::protobuf::stable_sort(cont.begin(), cont.end(), cmp); | |
| } | |
| // Like C++20's std::stable_sort, for RepeatedFieldProxy, with default | |
| // comparison. | |
| template <int&... DeductionBarrier, typename T> | |
| void c_stable_sort(RepeatedFieldProxy<T> cont) { | |
| google::protobuf::stable_sort(cont.begin(), cont.end()); | |
| } | |
| // Like C++20's std::sort, for RepeatedFieldOrProxy. | |
| template <int&..., typename T, typename Compare> | |
| void c_sort(internal::RepeatedFieldOrProxy<T> cont, Compare cmp) { | |
| google::protobuf::sort(cont.begin(), cont.end(), cmp); | |
| } | |
| // Like C++20's std::sort, for RepeatedFieldOrProxy, with default comparison. | |
| template <int&..., typename T> | |
| void c_sort(internal::RepeatedFieldOrProxy<T> cont) { | |
| google::protobuf::sort(cont.begin(), cont.end()); | |
| } | |
| // Like C++20's std::stable_sort, for RepeatedFieldOrProxy. | |
| template <int&..., typename T, typename Compare> | |
| void c_stable_sort(internal::RepeatedFieldOrProxy<T> cont, Compare cmp) { | |
| google::protobuf::stable_sort(cont.begin(), cont.end(), cmp); | |
| } | |
| // Like C++20's std::stable_sort, for RepeatedFieldOrProxy, with default | |
| // comparison. | |
| template <int&..., typename T> | |
| void c_stable_sort(internal::RepeatedFieldOrProxy<T> cont) { | |
| google::protobuf::stable_sort(cont.begin(), cont.end()); | |
| } | |
| // Provides a back insert iterator for RepeatedFieldOrProxy instances, | |
| // similar to std::back_inserter(). | |
| template <typename T> | |
| auto RepeatedFieldBackInserter(RepeatedFieldProxy<T> field) { | |
| return internal::RepeatedFieldProxyBackInsertIteratorImpl<T, | |
| /*kOrProxy=*/false>( | |
| field); | |
| } | |
| // Provides a back insert iterator for RepeatedFieldOrProxy instances, | |
| // similar to std::back_inserter(). | |
| template <typename T> | |
| auto RepeatedFieldBackInserter(internal::RepeatedFieldOrProxy<T> field) { | |
| return internal::RepeatedFieldProxyBackInsertIteratorImpl<T, | |
| /*kOrProxy=*/true>( | |
| field); | |
| } | |
| } // namespace protobuf | |
| } // namespace google | |
| // NOLINTEND(readability-const-return-type) | |
| #include "google/protobuf/port_undef.inc" | |
| #endif // GOOGLE_PROTOBUF_REPEATED_FIELD_PROXY_H__ |