From 433e737c0ef50e0ad40848679aa1fb76fe2b96cf Mon Sep 17 00:00:00 2001 From: Protobuf Team Bot Date: Mon, 17 Apr 2023 13:54:44 -0700 Subject: [PATCH] [C++ Upb] Implement copy constructor and assignment operator. PiperOrigin-RevId: 524941810 --- BUILD | 3 ++ protos_generator/BUILD | 1 + protos_generator/gen_messages.cc | 56 +++++++++++++++++----- protos_generator/protoc-gen-upb-protos.cc | 1 + protos_generator/tests/test_generated.cc | 58 +++++++++++++++++++++++ 5 files changed, 108 insertions(+), 11 deletions(-) diff --git a/BUILD b/BUILD index bb28313082..e421be7e7a 100644 --- a/BUILD +++ b/BUILD @@ -421,9 +421,11 @@ cc_library( cc_library( name = "generated_cpp_support__only_for_generated_code_do_not_use__i_give_permission_to_break_me", hdrs = [ + "upb/message/copy.h", "upb/message/extension_internal.h", "upb/message/internal.h", "upb/message/message.h", + "upb/mini_table/common.h", "upb/mini_table/enum_internal.h", "upb/mini_table/extension_internal.h", "upb/mini_table/field_internal.h", @@ -444,6 +446,7 @@ cc_library( ":base", ":collections_internal", ":hash", + ":message_copy", ":mini_table", ":upb", ], diff --git a/protos_generator/BUILD b/protos_generator/BUILD index 9d2c26975c..ed4fbdad22 100644 --- a/protos_generator/BUILD +++ b/protos_generator/BUILD @@ -65,6 +65,7 @@ cc_library( ], visibility = ["//visibility:private"], deps = [ + "//:message_copy", "//upbc:common", "//upbc:file_layout", "//upbc:keywords", diff --git a/protos_generator/gen_messages.cc b/protos_generator/gen_messages.cc index 2971aeabbf..a1e08a07b2 100644 --- a/protos_generator/gen_messages.cc +++ b/protos_generator/gen_messages.cc @@ -97,8 +97,8 @@ void WriteMessageClassDeclarations( output("} // namespace internal\n"); WriteModelPublicDeclaration(descriptor, file_exts, file_enums, output); output("namespace internal {\n"); - WriteModelProxyDeclaration(descriptor, output); WriteModelCProxyDeclaration(descriptor, output); + WriteModelProxyDeclaration(descriptor, output); output("} // namespace internal\n"); } @@ -151,22 +151,38 @@ void WriteModelPublicDeclaration( using Access = internal::$0Access; using Proxy = internal::$0Proxy; using CProxy = internal::$0CProxy; + $0(); - $0(const $0& m) = delete; - $0& operator=(const $0& m) = delete; + + $0(const $0& from); + inline $0& operator=(const $3& from) { + arena_ = owned_arena_.ptr(); + msg_ = ($2*)upb_Message_DeepClone(from.msg_, &$1, arena_); + return *this; + } + + $0(const CProxy& from); + $0(const Proxy& from); + inline $0& operator=(const CProxy& from) { + arena_ = owned_arena_.ptr(); + msg_ = ($2*)upb_Message_DeepClone( + ::protos::internal::GetInternalMsg(from), &$1, arena_); + return *this; + } $0($0&& m) - : Access(m.msg_, m.arena_), + : Access(absl::exchange(m.msg_, nullptr), + absl::exchange(m.arena_, nullptr)), owned_arena_(std::move(m.owned_arena_)) {} + $0& operator=($0&& m) { - msg_ = m.msg_; - arena_ = m.arena_; - m.msg_ = nullptr; - m.arena_ = nullptr; + msg_ = absl::exchange(m.msg_, nullptr); + arena_ = absl::exchange(m.arena_, nullptr); owned_arena_ = std::move(m.owned_arena_); return *this; } )cc", - ClassName(descriptor)); + ClassName(descriptor), ::upbc::MessageInit(descriptor->full_name()), + MessageName(descriptor), QualifiedClassName(descriptor)); WriteUsingAccessorsInHeader(descriptor, MessageClassType::kMessage, output); WriteUsingEnumsInHeader(descriptor, file_enums, output); @@ -274,6 +290,7 @@ void WriteModelCProxyDeclaration(const protobuf::Descriptor* descriptor, public: $0CProxy() = delete; $0CProxy(const $0* m) : internal::$0Access(m->msg_, nullptr) {} + $0CProxy($0Proxy m); using $0Access::GetInternalArena; )cc", ClassName(descriptor), MessageName(descriptor)); @@ -318,15 +335,32 @@ void WriteMessageImplementation( arena_ = owned_arena_.ptr(); msg_ = $1_new(arena_); } + $0::$0(const $0& from) : $0Access() { + arena_ = owned_arena_.ptr(); + msg_ = ($1*)upb_Message_DeepClone(from.msg_, &$2, arena_); + } + $0::$0(const CProxy& from) : $0Access() { + arena_ = owned_arena_.ptr(); + msg_ = ($1*)upb_Message_DeepClone( + ::protos::internal::GetInternalMsg(from), &$2, arena_); + } + $0::$0(const Proxy& from) : $0(static_cast(from)) {} + internal::$0CProxy::$0CProxy($0Proxy m) : $0Access() { + arena_ = m.arena_; + msg_ = ($1*)::protos::internal::GetInternalMsg(m); + } )cc", - ClassName(descriptor), MessageName(descriptor)); + ClassName(descriptor), MessageName(descriptor), + ::upbc::MessageInit(descriptor->full_name()), + QualifiedClassName(descriptor)); + output("\n"); // Minitable - OutputIndenter i(output); output( R"cc( const upb_MiniTable* $0::minitable() { return &$1; } )cc", ClassName(descriptor), ::upbc::MessageInit(descriptor->full_name())); + output("\n"); } WriteAccessorsInSource(descriptor, output); diff --git a/protos_generator/protoc-gen-upb-protos.cc b/protos_generator/protoc-gen-upb-protos.cc index 255f65a6f4..caa71782c8 100644 --- a/protos_generator/protoc-gen-upb-protos.cc +++ b/protos_generator/protoc-gen-upb-protos.cc @@ -134,6 +134,7 @@ void WriteHeader(const protobuf::FileDescriptor* file, Output& output) { #include "absl/strings/string_view.h" #include "absl/status/statusor.h" #include "upb/message/internal.h" +#include "upb/message/copy.h" )cc", ToPreproc(file->name())); diff --git a/protos_generator/tests/test_generated.cc b/protos_generator/tests/test_generated.cc index d62c136581..dcdf460b0c 100644 --- a/protos_generator/tests/test_generated.cc +++ b/protos_generator/tests/test_generated.cc @@ -25,6 +25,7 @@ #include #include +#include #include "gtest/gtest.h" #include "protos/protos.h" @@ -640,3 +641,60 @@ TEST(CppGeneratedCode, UniquePointer) { auto bytes = protos::Serialize(model, arena); EXPECT_TRUE(protos::Parse(model, bytes.value())); } + +TEST(CppGeneratedCode, Assignment) { + TestModel model; + model.set_category(5); + model.mutable_child_model_1()->set_child_str1("text in child"); + TestModel model2 = model; + EXPECT_EQ(5, model2.category()); + EXPECT_EQ(model2.child_model_1()->child_str1(), "text in child"); +} + +TEST(CppGeneratedCode, PtrAssignment) { + TestModel model; + model.mutable_child_model_1()->set_child_str1("text in child"); + ChildModel1 child_from_const_ptr = *model.child_model_1(); + EXPECT_EQ(child_from_const_ptr.child_str1(), "text in child"); + ChildModel1 child_from_ptr = *model.mutable_child_model_1(); + EXPECT_EQ(child_from_ptr.child_str1(), "text in child"); +} + +TEST(CppGeneratedCode, CopyConstructor) { + TestModel model; + model.set_category(6); + TestModel model2(model); + EXPECT_EQ(6, model2.category()); +} + +TEST(CppGeneratedCode, PtrConstructor) { + TestModel model; + model.mutable_child_model_1()->set_child_str1("text in child"); + ChildModel1 child_from_ptr(*model.mutable_child_model_1()); + EXPECT_EQ(child_from_ptr.child_str1(), "text in child"); + ChildModel1 child_from_const_ptr(*model.child_model_1()); + EXPECT_EQ(child_from_const_ptr.child_str1(), "text in child"); +} + +TEST(CppGeneratedCode, MutableToProxy) { + TestModel model; + ::protos::Ptr child = model.mutable_child_model_1(); + (void)child; +} + +TEST(CppGeneratedCode, ProxyToCProxy) { + TestModel model; + ::protos::Ptr child = model.mutable_child_model_1(); + ::protos::Ptr child2 = child; + (void)child2; +} + +bool ProxyToCProxyMethod(::protos::Ptr child) { + return child->child_str1() == "text in child"; +} + +TEST(CppGeneratedCode, PassProxyToCProxy) { + TestModel model; + model.mutable_child_model_1()->set_child_str1("text in child"); + EXPECT_TRUE(ProxyToCProxyMethod(model.mutable_child_model_1())); +}