From c3edc9036dcdb7f229767fc7dd9b1bcc466ee6df Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Tue, 13 Jun 2023 17:17:23 -0700 Subject: [PATCH] Internal change. PiperOrigin-RevId: 540118699 --- src/google/protobuf/BUILD.bazel | 2 + src/google/protobuf/internal_message_util.cc | 119 ++++++++++++++++++ src/google/protobuf/internal_message_util.h | 50 ++++++++ .../internal_message_util_unittest.cc | 45 +++++++ src/google/protobuf/message.h | 2 + src/google/protobuf/unittest.proto | 3 + 6 files changed, 221 insertions(+) create mode 100644 src/google/protobuf/internal_message_util.cc create mode 100644 src/google/protobuf/internal_message_util.h create mode 100644 src/google/protobuf/internal_message_util_unittest.cc diff --git a/src/google/protobuf/BUILD.bazel b/src/google/protobuf/BUILD.bazel index b93bf7e7e7..e5af5ab5be 100644 --- a/src/google/protobuf/BUILD.bazel +++ b/src/google/protobuf/BUILD.bazel @@ -425,6 +425,7 @@ cc_library( "generated_message_reflection.cc", "generated_message_tctable_full.cc", "generated_message_tctable_gen.cc", + "internal_message_util.cc", "map_field.cc", "message.cc", "reflection_mode.cc", @@ -446,6 +447,7 @@ cc_library( "generated_message_bases.h", "generated_message_reflection.h", "generated_message_tctable_gen.h", + "internal_message_util.h", "map_entry.h", "map_field.h", "map_field_inl.h", diff --git a/src/google/protobuf/internal_message_util.cc b/src/google/protobuf/internal_message_util.cc new file mode 100644 index 0000000000..da1e26c9d1 --- /dev/null +++ b/src/google/protobuf/internal_message_util.cc @@ -0,0 +1,119 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/internal_message_util.h" + +#include + +#include "google/protobuf/map_field.h" + +namespace google { +namespace protobuf { +namespace internal { + +class MessageUtil { + public: + static const internal::MapFieldBase* GetMapData( + const Reflection* reflection, const Message& message, + const FieldDescriptor* field) { + return reflection->GetMapData(message, field); + } + + // Walks the entire message tree and eager parses all lazy fields. + static void EagerParseLazyField(Message* message); +}; + +namespace { + +// Returns true if the field is a map that contains non-message value. +bool IsNonMessageMap(const FieldDescriptor* field) { + if (!field->is_map()) { + return false; + } + constexpr int kValueIndex = 1; + return field->message_type()->field(kValueIndex)->cpp_type() != + FieldDescriptor::CPPTYPE_MESSAGE; +} + +inline bool UseMapIterator(const Reflection* reflection, const Message& message, + const FieldDescriptor* field) { + return field->is_map() && + MessageUtil::GetMapData(reflection, message, field)->IsMapValid(); +} + +inline bool IsNonMessageField(const FieldDescriptor* field) { + return field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE || + IsNonMessageMap(field); +} + +} // namespace + +// To eagerly parse lazy fields in the entire message tree, mutates all the +// message fields (optional, repeated, extensions). +void MessageUtil::EagerParseLazyField(Message* message) { + const Reflection* reflection = message->GetReflection(); + std::vector fields; + reflection->ListFields(*message, &fields); + + for (const auto* field : fields) { + if (IsNonMessageField(field)) continue; + + if (!field->is_repeated()) { + EagerParseLazyField(reflection->MutableMessage(message, field)); + continue; + } + + // Map values cannot be lazy but their child message may be. + if (UseMapIterator(reflection, *message, field)) { + auto end = reflection->MapEnd(message, field); + for (auto it = reflection->MapBegin(message, field); it != end; ++it) { + EagerParseLazyField(it.MutableValueRef()->MutableMessageValue()); + } + continue; + } + + // Repeated messages cannot be lazy but their child messages may be. + if (field->is_repeated()) { + for (int i = 0, end = reflection->FieldSize(*message, field); i < end; + ++i) { + EagerParseLazyField( + reflection->MutableRepeatedMessage(message, field, i)); + } + } + } +} + +void EagerParseLazyField(Message& message) { + MessageUtil::EagerParseLazyField(&message); +} + +} // namespace internal +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/internal_message_util.h b/src/google/protobuf/internal_message_util.h new file mode 100644 index 0000000000..4672dcc5c4 --- /dev/null +++ b/src/google/protobuf/internal_message_util.h @@ -0,0 +1,50 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// This file contains miscellaneous (non-lite) helper code not suitable to +// generated_message_util.h. This should not be used directly by users. + +#ifndef GOOGLE_PROTOBUF_INTERNAL_MESSAGE_UTIL_H__ +#define GOOGLE_PROTOBUF_INTERNAL_MESSAGE_UTIL_H__ + +#include "google/protobuf/message.h" + +namespace google { +namespace protobuf { +namespace internal { + +// Walks the entire message tree and eager parses all lazy fields. +void EagerParseLazyField(Message& message); + +} // namespace internal +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_INTERNAL_MESSAGE_UTIL_H__ diff --git a/src/google/protobuf/internal_message_util_unittest.cc b/src/google/protobuf/internal_message_util_unittest.cc new file mode 100644 index 0000000000..85571861f2 --- /dev/null +++ b/src/google/protobuf/internal_message_util_unittest.cc @@ -0,0 +1,45 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2023 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "google/protobuf/internal_message_util.h" + +#include +#include +#include "google/protobuf/map_unittest.pb.h" +#include "google/protobuf/unittest.pb.h" + +namespace google { +namespace protobuf { +namespace { + + +} // namespace +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h index fd0bccc8ed..670ff5e547 100644 --- a/src/google/protobuf/message.h +++ b/src/google/protobuf/message.h @@ -161,6 +161,7 @@ namespace internal { struct FuzzPeer; struct DescriptorTable; class MapFieldBase; +class MessageUtil; class SwapFieldHelper; class CachedSize; struct TailCallTableInfo; @@ -1119,6 +1120,7 @@ class PROTOBUF_EXPORT Reflection final { friend class expr::CelMapReflectionFriend; friend class internal::MapFieldReflectionTest; friend class internal::MapKeySorter; + friend class internal::MessageUtil; friend class internal::WireFormat; friend class internal::ReflectionOps; friend class internal::SwapFieldHelper; diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto index aec4b60666..e5966b7c74 100644 --- a/src/google/protobuf/unittest.proto +++ b/src/google/protobuf/unittest.proto @@ -588,6 +588,9 @@ message TestEagerMessage { message TestLazyMessage { optional TestAllTypes sub_message = 1 [lazy=true]; } +message TestLazyMessageRepeated { + repeated TestLazyMessage repeated_message = 1; +} message TestEagerMaybeLazy { message NestedMessage { optional TestPackedTypes packed = 1;