|  | // Protocol Buffers - Google's data interchange format | 
|  | // Copyright 2023 Google LLC.  All rights reserved. | 
|  | // | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file or at | 
|  | // https://developers.google.com/open-source/licenses/bsd | 
|  |  | 
|  | #include "hpb_generator/gen_repeated_fields.h" | 
|  |  | 
|  | #include <string> | 
|  | #include <vector> | 
|  |  | 
|  | #include "google/protobuf/descriptor.pb.h" | 
|  | #include "absl/strings/string_view.h" | 
|  | #include "hpb_generator/context.h" | 
|  | #include "hpb_generator/gen_accessors.h" | 
|  | #include "hpb_generator/gen_enums.h" | 
|  | #include "hpb_generator/gen_extensions.h" | 
|  | #include "hpb_generator/gen_utils.h" | 
|  | #include "hpb_generator/names.h" | 
|  | #include "google/protobuf/descriptor.h" | 
|  | #include "upb_generator/c/names.h" | 
|  | #include "upb_generator/common.h" | 
|  | #include "upb_generator/file_layout.h" | 
|  |  | 
|  | namespace google { | 
|  | namespace protobuf { | 
|  | namespace hpb_generator { | 
|  |  | 
|  | // Adds using accessors to reuse base Access class members from a Proxy/CProxy. | 
|  | void WriteRepeatedFieldUsingAccessors(const google::protobuf::FieldDescriptor* field, | 
|  | absl::string_view class_name, | 
|  | absl::string_view resolved_field_name, | 
|  | Context& ctx, bool read_only) { | 
|  | if (field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { | 
|  | ctx.Emit({{"class_name", class_name}, {"field_name", resolved_field_name}}, | 
|  | R"cc( | 
|  | using $class_name$Access::$field_name$; | 
|  | using $class_name$Access::$field_name$_size; | 
|  | )cc"); | 
|  | if (!read_only) { | 
|  | ctx.Emit( | 
|  | {{"class_name", class_name}, {"field_name", resolved_field_name}}, | 
|  | R"cc( | 
|  | using $class_name$Access::add_$field_name$; | 
|  | using $class_name$Access::add_alias_$field_name$; | 
|  | using $class_name$Access::mutable_$field_name$; | 
|  | )cc"); | 
|  | } | 
|  | } else { | 
|  | ctx.Emit({{"class_name", class_name}, {"field_name", resolved_field_name}}, | 
|  | R"cc( | 
|  | using $class_name$Access::$field_name$; | 
|  | using $class_name$Access::$field_name$_size; | 
|  | )cc"); | 
|  | if (!read_only) { | 
|  | ctx.Emit( | 
|  | {{"class_name", class_name}, {"field_name", resolved_field_name}}, | 
|  | R"cc( | 
|  | using $class_name$Access::add_$field_name$; | 
|  | using $class_name$Access::mutable_$field_name$; | 
|  | using $class_name$Access::resize_$field_name$; | 
|  | using $class_name$Access::set_$field_name$; | 
|  | )cc"); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void WriteRepeatedFieldsInMessageHeader(const google::protobuf::Descriptor* desc, | 
|  | const google::protobuf::FieldDescriptor* field, | 
|  | absl::string_view resolved_field_name, | 
|  | absl::string_view resolved_upbc_name, | 
|  | Context& ctx) { | 
|  | ctx.Emit( | 
|  | {{"upb_msg_name", upb::generator::CApiMessageType(desc->full_name())}, | 
|  | {"field_name", resolved_field_name}, | 
|  | {"upbc_name", resolved_upbc_name}}, | 
|  | R"cc( | 
|  | inline size_t $field_name$_size() const { | 
|  | size_t len; | 
|  | $upb_msg_name$_$upbc_name$(msg_, &len); | 
|  | return len; | 
|  | } | 
|  | )cc"); | 
|  |  | 
|  | if (field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_MESSAGE) { | 
|  | ctx.Emit( | 
|  | {{"mut_ptr_type", MessagePtrConstType(field, /* const */ false)}, | 
|  | {"const_ptr_type", MessagePtrConstType(field, /* const */ true)}, | 
|  | {"field_name", resolved_field_name}, | 
|  | {"upbc_name", resolved_upbc_name}, | 
|  | {"msg_base_type", MessageBaseType(field, /* maybe_const */ false)}}, | 
|  | R"cc( | 
|  | $const_ptr_type$ $field_name$(size_t index) const; | 
|  | const ::hpb::RepeatedField<const $msg_base_type$>::CProxy $field_name$() const; | 
|  | ::hpb::Ptr<::hpb::RepeatedField<$msg_base_type$>> mutable_$field_name$(); | 
|  | absl::StatusOr<$mut_ptr_type$> add_$field_name$(); | 
|  | /** | 
|  | * Re-points submsg of repeated field to given target. | 
|  | * | 
|  | * REQUIRES: both messages must be in the same arena. | 
|  | */ | 
|  | bool add_alias_$field_name$($mut_ptr_type$ target); | 
|  | $mut_ptr_type$ mutable_$field_name$(size_t index) const; | 
|  | )cc"); | 
|  | } else if (field->cpp_type() == google::protobuf::FieldDescriptor::CPPTYPE_STRING) { | 
|  | ctx.Emit({{"cpp_const_type", CppConstType(field)}, | 
|  | {"field_name", resolved_field_name}}, | 
|  | R"cc( | 
|  | $cpp_const_type$ $field_name$(size_t index) const; | 
|  | const ::hpb::RepeatedField<$cpp_const_type$>::CProxy $field_name$() const; | 
|  | ::hpb::Ptr<::hpb::RepeatedField<$cpp_const_type$>> mutable_$field_name$(); | 
|  | bool add_$field_name$($cpp_const_type$ val); | 
|  | void set_$field_name$(size_t index, $cpp_const_type$ val); | 
|  | bool resize_$field_name$(size_t len); | 
|  | )cc"); | 
|  | } else { | 
|  | ctx.Emit({{"cpp_const_type", CppConstType(field)}, | 
|  | {"field_name", resolved_field_name}}, | 
|  | R"cc( | 
|  | $cpp_const_type$ $field_name$(size_t index) const; | 
|  | const ::hpb::RepeatedField<$cpp_const_type$>::CProxy $field_name$() const; | 
|  | ::hpb::Ptr<::hpb::RepeatedField<$cpp_const_type$>> mutable_$field_name$(); | 
|  | bool add_$field_name$($cpp_const_type$ val); | 
|  | void set_$field_name$(size_t index, $cpp_const_type$ val); | 
|  | bool resize_$field_name$(size_t len); | 
|  | )cc"); | 
|  | } | 
|  | } | 
|  |  | 
|  | void WriteRepeatedMessageAccessor(const google::protobuf::Descriptor* desc, | 
|  | const google::protobuf::FieldDescriptor* field, | 
|  | const absl::string_view resolved_field_name, | 
|  | const absl::string_view class_name, | 
|  | Context& ctx) { | 
|  | const char arena_expression[] = "arena_"; | 
|  | absl::string_view upbc_name = field->name(); | 
|  | ctx.Emit( | 
|  | {{"class_name", class_name}, | 
|  | {"const_ptr_type", MessagePtrConstType(field, /* is_const */ true)}, | 
|  | {"field_name", resolved_field_name}, | 
|  | {"upb_msg_name", upb::generator::CApiMessageType(desc->full_name())}, | 
|  | {"msg_base_type", MessageBaseType(field, /* maybe_const */ false)}, | 
|  | {"upbc_name", upbc_name}}, | 
|  | R"cc( | 
|  | $const_ptr_type$ $class_name$::$field_name$(size_t index) const { | 
|  | size_t len; | 
|  | auto* ptr = $upb_msg_name$_$upbc_name$(msg_, &len); | 
|  | assert(index < len); | 
|  | return ::hpb::interop::upb::MakeCHandle<$msg_base_type$>( | 
|  | (upb_Message*)*(ptr + index), arena_); | 
|  | } | 
|  | )cc"); | 
|  | ctx.Emit( | 
|  | {{"class_name", class_name}, | 
|  | {"mut_ptr_type", MessagePtrConstType(field, /* const */ false)}, | 
|  | {"field_name", resolved_field_name}, | 
|  | {"upb_msg_name", upb::generator::CApiMessageType(desc->full_name())}, | 
|  | {"msg_base_type", MessageBaseType(field, /* maybe_const */ false)}, | 
|  | {"arena_expr", arena_expression}, | 
|  | {"upbc_name", upbc_name}, | 
|  | {"upb_field_msg_name", | 
|  | upb::generator::CApiMessageType(field->message_type()->full_name())}}, | 
|  | R"cc( | 
|  | absl::StatusOr<$mut_ptr_type$> $class_name$::add_$field_name$() { | 
|  | auto new_msg = $upb_msg_name$_add_$upbc_name$(msg_, $arena_expr$); | 
|  | if (!new_msg) { | 
|  | return ::hpb::MessageAllocationError(); | 
|  | } | 
|  | return hpb::interop::upb::MakeHandle<$msg_base_type$>( | 
|  | (upb_Message*)new_msg, $arena_expr$); | 
|  | } | 
|  |  | 
|  | bool $class_name$::add_alias_$field_name$($mut_ptr_type$ target) { | 
|  | #ifndef NDEBUG | 
|  | ABSL_CHECK( | 
|  | upb_Arena_IsFused(arena_, hpb::interop::upb::GetArena(target)) || | 
|  | upb_Arena_HasRef(arena_, hpb::interop::upb::GetArena(target))); | 
|  | #endif | 
|  | size_t size = 0; | 
|  | $upb_msg_name$_$field_name$(msg_, &size); | 
|  | auto elements = $upb_msg_name$_resize_$field_name$(msg_, size + 1, arena_); | 
|  | if (!elements) { | 
|  | return false; | 
|  | } | 
|  | elements[size] = ($upb_field_msg_name$*)hpb::interop::upb::GetMessage(target); | 
|  | return true; | 
|  | } | 
|  | )cc"); | 
|  | ctx.Emit( | 
|  | {{"class_name", class_name}, | 
|  | {"mut_ptr_type", MessagePtrConstType(field, /* is_const */ false)}, | 
|  | {"field_name", resolved_field_name}, | 
|  | {"upb_msg_name", upb::generator::CApiMessageType(desc->full_name())}, | 
|  | {"msg_base_type", MessageBaseType(field, /* maybe_const */ false)}, | 
|  | {"arena_expr", arena_expression}, | 
|  | {"upbc_name", upbc_name}}, | 
|  | R"cc( | 
|  | $mut_ptr_type$ $class_name$::mutable_$field_name$(size_t index) const { | 
|  | size_t len; | 
|  | auto* ptr = $upb_msg_name$_$upbc_name$(msg_, &len); | 
|  | assert(index < len); | 
|  | return hpb::interop::upb::MakeHandle<$msg_base_type$>( | 
|  | (upb_Message*)*(ptr + index), $arena_expr$); | 
|  | } | 
|  | )cc"); | 
|  | ctx.Emit( | 
|  | {{"class_name", class_name}, | 
|  | {"msg_base_type", MessageBaseType(field, /* maybe_const */ false)}, | 
|  | {"field_name", resolved_field_name}, | 
|  | {"upb_msg_name", upb::generator::CApiMessageType(desc->full_name())}, | 
|  | {"upbc_name", upbc_name}, | 
|  | {"getter_postfix", upb::generator::kRepeatedFieldArrayGetterPostfix}, | 
|  | {"mutable_getter_postfix", | 
|  | upb::generator::kRepeatedFieldMutableArrayGetterPostfix}}, | 
|  | R"cc( | 
|  | const ::hpb::RepeatedField<const $msg_base_type$>::CProxy | 
|  | $class_name$::$field_name$() const { | 
|  | size_t size; | 
|  | const upb_Array* arr = | 
|  | _$upb_msg_name$_$upbc_name$_$getter_postfix$(msg_, &size); | 
|  | return ::hpb::RepeatedField<const $msg_base_type$>::CProxy(arr, arena_); | 
|  | }; | 
|  | ::hpb::Ptr<::hpb::RepeatedField<$msg_base_type$>> | 
|  | $class_name$::mutable_$field_name$() { | 
|  | size_t size; | 
|  | upb_Array* arr = _$upb_msg_name$_$upbc_name$_$mutable_getter_postfix$( | 
|  | msg_, &size, arena_); | 
|  | return ::hpb::RepeatedField<$msg_base_type$>::Proxy(arr, arena_); | 
|  | } | 
|  | )cc"); | 
|  | } | 
|  |  | 
|  | void WriteRepeatedStringAccessor(const google::protobuf::Descriptor* desc, | 
|  | const google::protobuf::FieldDescriptor* field, | 
|  | const absl::string_view resolved_field_name, | 
|  | const absl::string_view class_name, | 
|  | Context& ctx) { | 
|  | absl::string_view upbc_name = field->name(); | 
|  | ctx.Emit( | 
|  | {{"class_name", class_name}, | 
|  | {"cpp_const_type", CppConstType(field)}, | 
|  | {"field_name", resolved_field_name}, | 
|  | {"upb_msg_name", upb::generator::CApiMessageType(desc->full_name())}, | 
|  | {"upbc_name", upbc_name}}, | 
|  | R"cc( | 
|  | $cpp_const_type$ $class_name$::$field_name$(size_t index) const { | 
|  | size_t len; | 
|  | auto* ptr = $upb_msg_name$_mutable_$upbc_name$(msg_, &len); | 
|  | assert(index < len); | 
|  | return hpb::interop::upb::FromUpbStringView(*(ptr + index)); | 
|  | } | 
|  | )cc"); | 
|  | ctx.Emit( | 
|  | {{"class_name", class_name}, | 
|  | {"field_name", resolved_field_name}, | 
|  | {"upb_msg_name", upb::generator::CApiMessageType(desc->full_name())}, | 
|  | {"upbc_name", upbc_name}}, | 
|  | R"cc( | 
|  | bool $class_name$::resize_$field_name$(size_t len) { | 
|  | return $upb_msg_name$_resize_$upbc_name$(msg_, len, arena_); | 
|  | } | 
|  | )cc"); | 
|  | ctx.Emit( | 
|  | {{"class_name", class_name}, | 
|  | {"cpp_const_type", CppConstType(field)}, | 
|  | {"field_name", resolved_field_name}, | 
|  | {"upb_msg_name", upb::generator::CApiMessageType(desc->full_name())}, | 
|  | {"upbc_name", upbc_name}}, | 
|  | R"cc( | 
|  | bool $class_name$::add_$field_name$($cpp_const_type$ val) { | 
|  | return $upb_msg_name$_add_$upbc_name$( | 
|  | msg_, hpb::interop::upb::CopyToUpbStringView(val, arena_), | 
|  | arena_); | 
|  | } | 
|  | )cc"); | 
|  | ctx.Emit( | 
|  | {{"class_name", class_name}, | 
|  | {"cpp_const_type", CppConstType(field)}, | 
|  | {"field_name", resolved_field_name}, | 
|  | {"upb_msg_name", upb::generator::CApiMessageType(desc->full_name())}, | 
|  | {"upbc_name", upbc_name}}, | 
|  | R"cc( | 
|  | void $class_name$::set_$field_name$(size_t index, | 
|  | $cpp_const_type$ val) { | 
|  | size_t len; | 
|  | auto* ptr = $upb_msg_name$_mutable_$upbc_name$(msg_, &len); | 
|  | assert(index < len); | 
|  | *(ptr + index) = hpb::interop::upb::CopyToUpbStringView(val, arena_); | 
|  | } | 
|  | )cc"); | 
|  | ctx.Emit( | 
|  | {{"class_name", class_name}, | 
|  | {"cpp_const_type", CppConstType(field)}, | 
|  | {"field_name", resolved_field_name}, | 
|  | {"upb_msg_name", upb::generator::CApiMessageType(desc->full_name())}, | 
|  | {"upbc_name", upbc_name}, | 
|  | {"getter_postfix", upb::generator::kRepeatedFieldArrayGetterPostfix}, | 
|  | {"mutable_getter_postfix", | 
|  | upb::generator::kRepeatedFieldMutableArrayGetterPostfix}}, | 
|  | R"cc( | 
|  | const ::hpb::RepeatedField<$cpp_const_type$>::CProxy | 
|  | $class_name$::$field_name$() const { | 
|  | size_t size; | 
|  | const upb_Array* arr = | 
|  | _$upb_msg_name$_$upbc_name$_$getter_postfix$(msg_, &size); | 
|  | return ::hpb::RepeatedField<$cpp_const_type$>::CProxy(arr, arena_); | 
|  | }; | 
|  | ::hpb::Ptr<::hpb::RepeatedField<$cpp_const_type$>> | 
|  | $class_name$::mutable_$field_name$() { | 
|  | size_t size; | 
|  | upb_Array* arr = _$upb_msg_name$_$upbc_name$_$mutable_getter_postfix$( | 
|  | msg_, &size, arena_); | 
|  | return ::hpb::RepeatedField<$cpp_const_type$>::Proxy(arr, arena_); | 
|  | } | 
|  | )cc"); | 
|  | } | 
|  |  | 
|  | void WriteRepeatedScalarAccessor(const google::protobuf::Descriptor* desc, | 
|  | const google::protobuf::FieldDescriptor* field, | 
|  | const absl::string_view resolved_field_name, | 
|  | const absl::string_view class_name, | 
|  | Context& ctx) { | 
|  | absl::string_view upbc_name = field->name(); | 
|  | ctx.Emit( | 
|  | {{"class_name", class_name}, | 
|  | {"cpp_const_type", CppConstType(field)}, | 
|  | {"field_name", resolved_field_name}, | 
|  | {"upb_msg_name", upb::generator::CApiMessageType(desc->full_name())}, | 
|  | {"upbc_name", upbc_name}}, | 
|  | R"cc( | 
|  | $cpp_const_type$ $class_name$::$field_name$(size_t index) const { | 
|  | size_t len; | 
|  | auto* ptr = $upb_msg_name$_mutable_$upbc_name$(msg_, &len); | 
|  | assert(index < len); | 
|  | return *(ptr + index); | 
|  | } | 
|  | )cc"); | 
|  | ctx.Emit( | 
|  | {{"class_name", class_name}, | 
|  | {"field_name", resolved_field_name}, | 
|  | {"upb_msg_name", upb::generator::CApiMessageType(desc->full_name())}, | 
|  | {"upbc_name", upbc_name}}, | 
|  | R"cc( | 
|  | bool $class_name$::resize_$field_name$(size_t len) { | 
|  | return $upb_msg_name$_resize_$upbc_name$(msg_, len, arena_); | 
|  | } | 
|  | )cc"); | 
|  | ctx.Emit( | 
|  | {{"class_name", class_name}, | 
|  | {"cpp_const_type", CppConstType(field)}, | 
|  | {"field_name", resolved_field_name}, | 
|  | {"upb_msg_name", upb::generator::CApiMessageType(desc->full_name())}, | 
|  | {"upbc_name", upbc_name}}, | 
|  | R"cc( | 
|  | bool $class_name$::add_$field_name$($cpp_const_type$ val) { | 
|  | return $upb_msg_name$_add_$upbc_name$(msg_, val, arena_); | 
|  | } | 
|  | )cc"); | 
|  | ctx.Emit( | 
|  | {{"class_name", class_name}, | 
|  | {"cpp_const_type", CppConstType(field)}, | 
|  | {"field_name", resolved_field_name}, | 
|  | {"upb_msg_name", upb::generator::CApiMessageType(desc->full_name())}, | 
|  | {"upbc_name", upbc_name}}, | 
|  | R"cc( | 
|  | void $class_name$::set_$field_name$(size_t index, | 
|  | $cpp_const_type$ val) { | 
|  | size_t len; | 
|  | auto* ptr = $upb_msg_name$_mutable_$upbc_name$(msg_, &len); | 
|  | assert(index < len); | 
|  | *(ptr + index) = val; | 
|  | } | 
|  | )cc"); | 
|  | ctx.Emit( | 
|  | {{"class_name", class_name}, | 
|  | {"cpp_const_type", CppConstType(field)}, | 
|  | {"field_name", resolved_field_name}, | 
|  | {"upb_msg_name", upb::generator::CApiMessageType(desc->full_name())}, | 
|  | {"upbc_name", upbc_name}, | 
|  | {"getter_postfix", upb::generator::kRepeatedFieldArrayGetterPostfix}, | 
|  | {"mutable_getter_postfix", | 
|  | upb::generator::kRepeatedFieldMutableArrayGetterPostfix}}, | 
|  | R"cc( | 
|  | const ::hpb::RepeatedField<$cpp_const_type$>::CProxy | 
|  | $class_name$::$field_name$() const { | 
|  | size_t size; | 
|  | const upb_Array* arr = | 
|  | _$upb_msg_name$_$upbc_name$_$getter_postfix$(msg_, &size); | 
|  | return ::hpb::RepeatedField<$cpp_const_type$>::CProxy(arr, arena_); | 
|  | }; | 
|  | ::hpb::Ptr<::hpb::RepeatedField<$cpp_const_type$>> | 
|  | $class_name$::mutable_$field_name$() { | 
|  | size_t size; | 
|  | upb_Array* arr = _$upb_msg_name$_$upbc_name$_$mutable_getter_postfix$( | 
|  | msg_, &size, arena_); | 
|  | return ::hpb::RepeatedField<$cpp_const_type$>::Proxy(arr, arena_); | 
|  | } | 
|  | )cc"); | 
|  | } | 
|  |  | 
|  | }  // namespace hpb_generator | 
|  | }  // namespace protobuf | 
|  | }  // namespace google |