Add EagerParseLazyField no IgnoreParse

PiperOrigin-RevId: 612999269
pull/15973/head
Protobuf Team Bot 12 months ago committed by Copybara-Service
parent 9f001a9658
commit 6332267b1d
  1. 95
      src/google/protobuf/reflection_visit_fields.h
  2. 41
      src/google/protobuf/reflection_visit_fields_test.cc

@ -60,6 +60,12 @@ class ReflectionVisit final {
template <typename MessageT, typename CallbackFn>
static void VisitFields(MessageT& message, CallbackFn&& func, FieldMask mask);
template <typename CallbackFn>
static void VisitMessageFields(const Message& message, CallbackFn&& func);
template <typename CallbackFn>
static void VisitMessageFields(Message& message, CallbackFn&& func);
private:
static const internal::ReflectionSchema& GetSchema(
const Reflection* reflection) {
@ -396,10 +402,95 @@ void ReflectionVisit::VisitFields(MessageT& message, CallbackFn&& func,
});
}
template <typename CallbackFn>
void ReflectionVisit::VisitMessageFields(const Message& message,
CallbackFn&& func) {
ReflectionVisit::VisitFields(
message,
[&](auto info) {
if constexpr (info.is_map) {
auto value_type = info.value_type();
if (value_type != FieldDescriptor::TYPE_MESSAGE &&
value_type != FieldDescriptor::TYPE_GROUP) {
return;
}
info.VisitElements([&](auto key, auto val) {
if constexpr (val.cpp_type == FieldDescriptor::CPPTYPE_MESSAGE) {
func(val.Get());
}
});
} else if constexpr (info.cpp_type ==
FieldDescriptor::CPPTYPE_MESSAGE) {
if constexpr (info.is_repeated) {
for (const auto& it : info.Get()) {
func(DownCast<const Message&>(it));
}
} else {
func(info.Get());
}
}
},
FieldMask::kMessage);
}
template <typename CallbackFn>
void ReflectionVisit::VisitMessageFields(Message& message, CallbackFn&& func) {
ReflectionVisit::VisitFields(
message,
[&](auto info) {
if constexpr (info.is_map) {
auto value_type = info.value_type();
if (value_type != FieldDescriptor::TYPE_MESSAGE &&
value_type != FieldDescriptor::TYPE_GROUP) {
return;
}
info.VisitElements([&](auto key, auto val) {
if constexpr (val.cpp_type == FieldDescriptor::CPPTYPE_MESSAGE) {
func(*val.Mutable());
}
});
} else if constexpr (info.cpp_type ==
FieldDescriptor::CPPTYPE_MESSAGE) {
if constexpr (info.is_repeated) {
for (auto& it : info.Mutable()) {
func(DownCast<Message&>(it));
}
} else {
func(info.Mutable());
}
}
},
FieldMask::kMessage);
}
// Visits present fields of "message" and calls the callback function "func".
// Skips fields whose ctypes are missing in "mask".
template <typename MessageT, typename CallbackFn>
void VisitFields(MessageT& message, CallbackFn&& func, FieldMask mask) {
internal::ReflectionVisit::VisitFields(message,
std::forward<CallbackFn>(func), mask);
ReflectionVisit::VisitFields(message, std::forward<CallbackFn>(func), mask);
}
// Visits message fields of "message" and calls "func". Expects "func" to
// accept const Message&. Note the following divergence from VisitFields.
//
// --Each of N elements of a repeated message field is visited (total N).
// --Each of M elements of a map field whose value type is message are visited
// (total M).
// --A map field whose value type is not message is ignored.
//
// This is a helper API built on top of VisitFields to hide specifics about
// extensions, repeated fields, etc.
template <typename CallbackFn>
void VisitMessageFields(const Message& message, CallbackFn&& func) {
ReflectionVisit::VisitMessageFields(message, std::forward<CallbackFn>(func));
}
// Same as VisitMessageFields above but expects "func" to accept Message&. This
// is useful when mutable access is required. As mutable access can be
// expensive, use it only if it's necessary.
template <typename CallbackFn>
void VisitMutableMessageFields(Message& message, CallbackFn&& func) {
ReflectionVisit::VisitMessageFields(message, std::forward<CallbackFn>(func));
}
#endif // __cpp_if_constexpr

@ -80,6 +80,47 @@ TEST_P(VisitFieldsTest, VisitedMessageFieldsCountMatchesListFields) {
EXPECT_EQ(count, message_count);
}
// Counts present message fields using ListFields() where:
// --N elements in a repeated message field are counted N times
// --M message values in a map field are counted M times.
// --A map field whose value type is not message is ignored.
int CountAllMessageFieldsViaListFields(const Reflection* reflection,
const Message& message) {
std::vector<const FieldDescriptor*> fields;
reflection->ListFields(message, &fields);
int message_count = 0;
for (auto field : fields) {
if (field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) continue;
if (field->is_map()) {
if (field->message_type()->map_value()->cpp_type() !=
FieldDescriptor::CPPTYPE_MESSAGE)
continue;
}
if (field->is_repeated()) {
message_count += reflection->FieldSize(message, field);
} else {
++message_count;
}
}
return message_count;
}
TEST_P(VisitFieldsTest, VisitMessageFieldsCountIncludesRepeatedElements) {
int count = 0;
VisitMessageFields(*message_, [&](const Message& msg) { ++count; });
EXPECT_EQ(count, CountAllMessageFieldsViaListFields(reflection_, *message_));
}
TEST_P(VisitFieldsTest,
VisitMutableMessageFieldsCountIncludesRepeatedElements) {
int count = 0;
VisitMutableMessageFields(*message_, [&](Message& msg) { ++count; });
EXPECT_EQ(count, CountAllMessageFieldsViaListFields(reflection_, *message_));
}
TEST_P(VisitFieldsTest, ClearByVisitFieldsMustBeEmpty) {
VisitFields(*message_, [](auto info) { info.Clear(); });

Loading…
Cancel
Save