Add iteration to proxies for repeated message fields.

Iteration will return Ptr<T>/Ptr<const T> objects.

PiperOrigin-RevId: 563410054
pull/13872/head
Protobuf Team Bot 2 years ago committed by Copybara-Service
parent c23ae49776
commit 0ed6737695
  1. 2
      upb/protos/BUILD
  2. 17
      upb/protos/repeated_field.h
  3. 44
      upb/protos/repeated_field_iterator.h
  4. 24
      upb/protos_generator/tests/test_generated.cc

@ -54,7 +54,7 @@ cc_library(
"//:collections_internal",
"//:mem",
"//:message_copy",
"//:mini_table",
"//:message_types",
"//:port",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/strings",

@ -108,6 +108,14 @@ class RepeatedFieldProxy
static constexpr bool kIsConst = std::is_const_v<T>;
public:
using value_type = std::remove_const_t<T>;
using size_type = size_t;
using difference_type = ptrdiff_t;
using iterator = internal::Iterator<MessageIteratorPolicy<T>>;
using reference = typename iterator::reference;
using pointer = typename iterator::pointer;
using reverse_iterator = std::reverse_iterator<iterator>;
explicit RepeatedFieldProxy(const upb_Array* arr, upb_Arena* arena)
: RepeatedFieldProxyBase<T>(arr, arena) {}
RepeatedFieldProxy(upb_Array* arr, upb_Arena* arena)
@ -153,6 +161,15 @@ class RepeatedFieldProxy
T moved_msg = std::move(msg);
}
iterator begin() const {
return iterator({static_cast<upb_Message**>(
const_cast<void*>(upb_Array_DataPtr(this->arr_))),
this->arena_});
}
iterator end() const { return begin() + this->size(); }
reverse_iterator rbegin() const { return reverse_iterator(end()); }
reverse_iterator rend() const { return reverse_iterator(begin()); }
private:
friend class ::protos::Ptr<T>;
};

@ -43,6 +43,7 @@
#include "upb/message/copy.h"
// Must be last:
#include "upb/message/types.h"
#include "upb/port/def.inc"
namespace protos {
@ -165,7 +166,9 @@ class Iterator {
using value_type = std::remove_const_t<typename PolicyT::value_type>;
using difference_type = std::ptrdiff_t;
using pointer = Iterator;
using reference = ReferenceProxy<PolicyT>;
using reference =
std::conditional_t<PolicyT::kUseReferenceProxy, ReferenceProxy<PolicyT>,
typename PolicyT::value_type>;
constexpr Iterator() noexcept : it_(nullptr) {}
Iterator(const Iterator& other) = default;
@ -175,7 +178,13 @@ class Iterator {
typename = std::enable_if_t<std::is_const<typename P::value_type>::value>>
Iterator(const Iterator<typename P::RemoveConst>& other) : it_(other.it_) {}
constexpr reference operator*() const noexcept { return reference(it_); }
constexpr reference operator*() const noexcept {
if constexpr (PolicyT::kUseReferenceProxy) {
return reference(it_);
} else {
return it_.Get();
}
}
// No operator-> needed because T is a scalar.
private:
@ -275,6 +284,8 @@ class Iterator {
friend class RepeatedFieldScalarProxy;
template <typename U>
friend class RepeatedFieldStringProxy;
template <typename U>
friend class RepeatedFieldProxy;
// Create from internal::RepeatedFieldScalarProxy.
explicit Iterator(typename PolicyT::Payload it) noexcept : it_(it) {}
@ -285,6 +296,7 @@ class Iterator {
template <typename T>
struct ScalarIteratorPolicy {
static constexpr bool kUseReferenceProxy = true;
using value_type = T;
using RemoveConst = ScalarIteratorPolicy<std::remove_const_t<T>>;
using AddConst = ScalarIteratorPolicy<const T>;
@ -309,6 +321,7 @@ struct ScalarIteratorPolicy {
template <typename T>
struct StringIteratorPolicy {
static constexpr bool kUseReferenceProxy = true;
using value_type = T;
using RemoveConst = StringIteratorPolicy<std::remove_const_t<T>>;
using AddConst = StringIteratorPolicy<const T>;
@ -350,6 +363,33 @@ struct StringIteratorPolicy {
};
};
template <typename T>
struct MessageIteratorPolicy {
static constexpr bool kUseReferenceProxy = false;
using value_type = std::conditional_t<std::is_const_v<T>, typename T::CProxy,
typename T::Proxy>;
using RemoveConst = MessageIteratorPolicy<std::remove_const_t<T>>;
using AddConst = MessageIteratorPolicy<const T>;
struct Payload {
using Array =
std::conditional_t<std::is_const_v<T>, const upb_Array, upb_Array>;
upb_Message** arr;
upb_Arena* arena;
void AddOffset(ptrdiff_t offset) { arr += offset; }
auto Get() const {
if constexpr (std::is_const_v<T>) {
return ::protos::internal::CreateMessage<
typename std::remove_const_t<T>>(*arr, arena);
} else {
return ::protos::internal::CreateMessageProxy<T>(*arr, arena);
}
}
auto Index() const { return arr; }
};
};
} // namespace internal
} // namespace protos

@ -559,6 +559,30 @@ TEST(CppGeneratedCode, RepeatedFieldProxyForMessages) {
ChildModel1 child2;
child2.set_child_str1(kTestStr2);
test_model.mutable_child_models()->push_back(std::move(child2));
int i = 0;
for (auto child : test_model.child_models()) {
EXPECT_FALSE(Requires<decltype(child)>(
[](auto&& x) -> decltype(x.set_child_str1("")) {}));
if (i++ == 0) {
EXPECT_EQ(child.child_str1(), kTestStr1);
} else {
EXPECT_EQ(child.child_str1(), kTestStr2);
}
}
i = 0;
for (auto child : *test_model.mutable_child_models()) {
if (i++ == 0) {
EXPECT_EQ(child.child_str1(), kTestStr1);
} else {
EXPECT_EQ(child.child_str1(), kTestStr2);
}
}
using testing::_;
EXPECT_THAT(test_model.child_models(), ElementsAre(_, _));
EXPECT_EQ(test_model.child_models().size(), 2);
EXPECT_EQ(test_model.child_models()[0].child_str1(), kTestStr1);
EXPECT_EQ(test_model.child_models()[1].child_str1(), kTestStr2);

Loading…
Cancel
Save