662 lines
20 KiB
C++
662 lines
20 KiB
C++
// Protocol Buffers - Google's data interchange format
|
|
// Copyright 2008 Google Inc. 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
|
|
|
|
// Author: kenton@google.com (Kenton Varda)
|
|
// Based on original Protocol Buffers design by
|
|
// Sanjay Ghemawat, Jeff Dean, and others.
|
|
|
|
#include <cstddef>
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "absl/log/absl_check.h"
|
|
#include "absl/log/absl_log.h"
|
|
#include "absl/memory/memory.h"
|
|
#include "absl/types/optional.h"
|
|
#include "google/protobuf/compiler/cpp/field.h"
|
|
#include "google/protobuf/compiler/cpp/field_generators/generators.h"
|
|
#include "google/protobuf/compiler/cpp/helpers.h"
|
|
#include "google/protobuf/compiler/cpp/options.h"
|
|
#include "google/protobuf/descriptor.h"
|
|
#include "google/protobuf/descriptor.pb.h"
|
|
#include "google/protobuf/io/printer.h"
|
|
#include "google/protobuf/wire_format.h"
|
|
|
|
namespace google {
|
|
namespace protobuf {
|
|
namespace compiler {
|
|
namespace cpp {
|
|
namespace {
|
|
using ::google::protobuf::internal::WireFormat;
|
|
using ::google::protobuf::internal::WireFormatLite;
|
|
using Sub = ::google::protobuf::io::Printer::Sub;
|
|
using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
|
|
|
|
// For encodings with fixed sizes, returns that size in bytes.
|
|
absl::optional<size_t> FixedSize(FieldDescriptor::Type type) {
|
|
switch (type) {
|
|
case FieldDescriptor::TYPE_INT32:
|
|
case FieldDescriptor::TYPE_INT64:
|
|
case FieldDescriptor::TYPE_UINT32:
|
|
case FieldDescriptor::TYPE_UINT64:
|
|
case FieldDescriptor::TYPE_SINT32:
|
|
case FieldDescriptor::TYPE_SINT64:
|
|
case FieldDescriptor::TYPE_ENUM:
|
|
case FieldDescriptor::TYPE_STRING:
|
|
case FieldDescriptor::TYPE_BYTES:
|
|
case FieldDescriptor::TYPE_GROUP:
|
|
case FieldDescriptor::TYPE_MESSAGE:
|
|
return absl::nullopt;
|
|
|
|
case FieldDescriptor::TYPE_FIXED32:
|
|
return WireFormatLite::kFixed32Size;
|
|
case FieldDescriptor::TYPE_FIXED64:
|
|
return WireFormatLite::kFixed64Size;
|
|
case FieldDescriptor::TYPE_SFIXED32:
|
|
return WireFormatLite::kSFixed32Size;
|
|
case FieldDescriptor::TYPE_SFIXED64:
|
|
return WireFormatLite::kSFixed64Size;
|
|
case FieldDescriptor::TYPE_FLOAT:
|
|
return WireFormatLite::kFloatSize;
|
|
case FieldDescriptor::TYPE_DOUBLE:
|
|
return WireFormatLite::kDoubleSize;
|
|
case FieldDescriptor::TYPE_BOOL:
|
|
return WireFormatLite::kBoolSize;
|
|
|
|
// No default because we want the compiler to complain if any new
|
|
// types are added.
|
|
}
|
|
|
|
ABSL_LOG(FATAL) << "Can't get here.";
|
|
return absl::nullopt;
|
|
}
|
|
|
|
std::vector<Sub> Vars(const FieldDescriptor* field, const Options& options) {
|
|
bool cold = ShouldSplit(field, options);
|
|
return {
|
|
{"Type", PrimitiveTypeName(options, field->cpp_type())},
|
|
{"kDefault", DefaultValue(options, field)},
|
|
{"_field_cached_byte_size_", MakeVarintCachedSizeFieldName(field, cold)},
|
|
};
|
|
}
|
|
|
|
class SingularPrimitive final : public FieldGeneratorBase {
|
|
public:
|
|
SingularPrimitive(const FieldDescriptor* field, const Options& opts,
|
|
MessageSCCAnalyzer* scc)
|
|
: FieldGeneratorBase(field, opts, scc), opts_(&opts) {}
|
|
~SingularPrimitive() override = default;
|
|
|
|
std::vector<Sub> MakeVars() const override { return Vars(field_, *opts_); }
|
|
|
|
void GeneratePrivateMembers(io::Printer* p) const override {
|
|
p->Emit(R"cc(
|
|
$Type$ $name$_;
|
|
)cc");
|
|
}
|
|
|
|
void GenerateClearingCode(io::Printer* p) const override {
|
|
p->Emit(R"cc(
|
|
$field_$ = $kDefault$;
|
|
)cc");
|
|
}
|
|
|
|
void GenerateMergingCode(io::Printer* p) const override {
|
|
p->Emit(R"cc(
|
|
_this->$field_$ = from.$field_$;
|
|
)cc");
|
|
}
|
|
|
|
void GenerateSwappingCode(io::Printer* p) const override {
|
|
if (is_oneof()) {
|
|
// Don't print any swapping code. Swapping the union will swap this field.
|
|
return;
|
|
}
|
|
|
|
p->Emit(R"cc(
|
|
//~ A `using std::swap;` is already present in this function.
|
|
swap($field_$, other->$field_$);
|
|
)cc");
|
|
}
|
|
|
|
void GenerateConstructorCode(io::Printer* p) const override {
|
|
if (!is_oneof()) {
|
|
return;
|
|
}
|
|
|
|
p->Emit(R"cc(
|
|
$pkg$::_$Msg$_default_instance_.$field_$ = $kDefault$;
|
|
)cc");
|
|
}
|
|
|
|
void GenerateCopyConstructorCode(io::Printer* p) const override {
|
|
p->Emit(R"cc(
|
|
_this->$field_$ = from.$field_$;
|
|
)cc");
|
|
}
|
|
|
|
void GenerateConstexprAggregateInitializer(io::Printer* p) const override {
|
|
p->Emit(R"cc(
|
|
/*decltype($field_$)*/ $kDefault$,
|
|
)cc");
|
|
}
|
|
|
|
void GenerateAggregateInitializer(io::Printer* p) const override {
|
|
p->Emit(R"cc(
|
|
decltype($field_$){$kDefault$},
|
|
)cc");
|
|
}
|
|
|
|
void GenerateCopyAggregateInitializer(io::Printer* p) const override {
|
|
p->Emit(R"cc(
|
|
decltype($field_$){},
|
|
)cc");
|
|
}
|
|
|
|
void GenerateAccessorDeclarations(io::Printer* p) const override;
|
|
void GenerateInlineAccessorDefinitions(io::Printer* p) const override;
|
|
void GenerateSerializeWithCachedSizesToArray(io::Printer* p) const override;
|
|
void GenerateByteSize(io::Printer* p) const override;
|
|
|
|
private:
|
|
const Options* opts_;
|
|
};
|
|
|
|
void SingularPrimitive::GenerateAccessorDeclarations(io::Printer* p) const {
|
|
auto v = p->WithVars(
|
|
AnnotatedAccessors(field_, {"", "_internal_", "_internal_set_"}));
|
|
auto vs = p->WithVars(AnnotatedAccessors(field_, {"set_"}, Semantic::kSet));
|
|
p->Emit(R"cc(
|
|
$DEPRECATED$ $Type$ $name$() const;
|
|
$DEPRECATED$ void $set_name$($Type$ value);
|
|
|
|
private:
|
|
$Type$ $_internal_name$() const;
|
|
void $_internal_set_name$($Type$ value);
|
|
|
|
public:
|
|
)cc");
|
|
}
|
|
|
|
void SingularPrimitive::GenerateInlineAccessorDefinitions(
|
|
io::Printer* p) const {
|
|
p->Emit(R"cc(
|
|
inline $Type$ $Msg$::$name$() const {
|
|
$WeakDescriptorSelfPin$;
|
|
$annotate_get$;
|
|
// @@protoc_insertion_point(field_get:$pkg.Msg.field$)
|
|
return _internal_$name_internal$();
|
|
}
|
|
)cc");
|
|
|
|
if (is_oneof()) {
|
|
p->Emit(R"cc(
|
|
inline void $Msg$::set_$name$($Type$ value) {
|
|
$WeakDescriptorSelfPin$;
|
|
$PrepareSplitMessageForWrite$;
|
|
if ($not_has_field$) {
|
|
clear_$oneof_name$();
|
|
set_has_$name_internal$();
|
|
}
|
|
$field_$ = value;
|
|
$annotate_set$;
|
|
// @@protoc_insertion_point(field_set:$pkg.Msg.field$)
|
|
}
|
|
inline $Type$ $Msg$::_internal_$name_internal$() const {
|
|
if ($has_field$) {
|
|
return $field_$;
|
|
}
|
|
return $kDefault$;
|
|
}
|
|
)cc");
|
|
} else {
|
|
p->Emit(R"cc(
|
|
inline void $Msg$::set_$name$($Type$ value) {
|
|
$WeakDescriptorSelfPin$;
|
|
$PrepareSplitMessageForWrite$;
|
|
_internal_set_$name_internal$(value);
|
|
$set_hasbit$;
|
|
$annotate_set$;
|
|
// @@protoc_insertion_point(field_set:$pkg.Msg.field$)
|
|
}
|
|
inline $Type$ $Msg$::_internal_$name_internal$() const {
|
|
$TsanDetectConcurrentRead$;
|
|
return $field_$;
|
|
}
|
|
inline void $Msg$::_internal_set_$name_internal$($Type$ value) {
|
|
$TsanDetectConcurrentMutation$;
|
|
$field_$ = value;
|
|
}
|
|
)cc");
|
|
}
|
|
}
|
|
|
|
void SingularPrimitive::GenerateSerializeWithCachedSizesToArray(
|
|
io::Printer* p) const {
|
|
if ((field_->number() < 16) &&
|
|
(field_->type() == FieldDescriptor::TYPE_INT32 ||
|
|
field_->type() == FieldDescriptor::TYPE_INT64 ||
|
|
field_->type() == FieldDescriptor::TYPE_ENUM)) {
|
|
// Call special non-inlined routine with tag number hardcoded as a
|
|
// template parameter that handles the EnsureSpace and the writing
|
|
// of the tag+value to the array
|
|
p->Emit(R"cc(
|
|
target = ::$proto_ns$::internal::WireFormatLite::
|
|
Write$declared_type$ToArrayWithField<$number$>(
|
|
stream, this->_internal_$name$(), target);
|
|
)cc");
|
|
} else {
|
|
p->Emit(R"cc(
|
|
target = stream->EnsureSpace(target);
|
|
target = ::_pbi::WireFormatLite::Write$DeclaredType$ToArray(
|
|
$number$, this->_internal_$name$(), target);
|
|
)cc");
|
|
}
|
|
}
|
|
|
|
void SingularPrimitive::GenerateByteSize(io::Printer* p) const {
|
|
size_t tag_size = WireFormat::TagSize(field_->number(), field_->type());
|
|
|
|
auto fixed_size = FixedSize(field_->type());
|
|
if (fixed_size.has_value()) {
|
|
p->Emit({{"kFixedBytes", tag_size + *fixed_size}}, R"cc(
|
|
total_size += $kFixedBytes$;
|
|
)cc");
|
|
return;
|
|
}
|
|
|
|
// Adding one is very common and it turns out it can be done for
|
|
// free inside of WireFormatLite, so we can save an instruction here.
|
|
if (tag_size == 1) {
|
|
p->Emit(R"cc(
|
|
total_size += ::_pbi::WireFormatLite::$DeclaredType$SizePlusOne(
|
|
this->_internal_$name$());
|
|
)cc");
|
|
return;
|
|
}
|
|
|
|
p->Emit(R"cc(
|
|
total_size += $kTagBytes$ + ::_pbi::WireFormatLite::$DeclaredType$Size(
|
|
this->_internal_$name$());
|
|
)cc");
|
|
}
|
|
|
|
class RepeatedPrimitive final : public FieldGeneratorBase {
|
|
public:
|
|
RepeatedPrimitive(const FieldDescriptor* field, const Options& opts,
|
|
MessageSCCAnalyzer* scc)
|
|
: FieldGeneratorBase(field, opts, scc), opts_(&opts) {}
|
|
~RepeatedPrimitive() override = default;
|
|
|
|
std::vector<Sub> MakeVars() const override { return Vars(field_, *opts_); }
|
|
|
|
void GenerateClearingCode(io::Printer* p) const override {
|
|
if (should_split()) {
|
|
p->Emit("$field_$.ClearIfNotDefault();\n");
|
|
} else {
|
|
p->Emit("$field_$.Clear();\n");
|
|
}
|
|
}
|
|
|
|
void GenerateMergingCode(io::Printer* p) const override {
|
|
// TODO: experiment with simplifying this to be
|
|
// `if (!from.empty()) { body(); }` for both split and non-split cases.
|
|
auto body = [&] {
|
|
p->Emit(R"cc(
|
|
_this->_internal_mutable_$name$()->MergeFrom(from._internal_$name$());
|
|
)cc");
|
|
};
|
|
if (!should_split()) {
|
|
body();
|
|
} else {
|
|
p->Emit({{"body", body}}, R"cc(
|
|
if (!from.$field_$.IsDefault()) {
|
|
$body$;
|
|
}
|
|
)cc");
|
|
}
|
|
}
|
|
|
|
void GenerateSwappingCode(io::Printer* p) const override {
|
|
ABSL_CHECK(!should_split());
|
|
p->Emit(R"cc(
|
|
$field_$.InternalSwap(&other->$field_$);
|
|
)cc");
|
|
}
|
|
|
|
void GenerateDestructorCode(io::Printer* p) const override {
|
|
if (should_split()) {
|
|
p->Emit(R"cc(
|
|
$field_$.DeleteIfNotDefault();
|
|
)cc");
|
|
}
|
|
}
|
|
|
|
void GenerateConstructorCode(io::Printer* p) const override {}
|
|
|
|
void GenerateCopyConstructorCode(io::Printer* p) const override {
|
|
if (should_split()) {
|
|
p->Emit(R"cc(
|
|
if (!from._internal_$name$().empty()) {
|
|
_internal_mutable_$name$()->MergeFrom(from._internal_$name$());
|
|
}
|
|
)cc");
|
|
}
|
|
}
|
|
|
|
void GenerateConstexprAggregateInitializer(io::Printer* p) const override {
|
|
p->Emit(R"cc(
|
|
/*decltype($field_$)*/ {},
|
|
)cc");
|
|
GenerateCacheSizeInitializer(p);
|
|
}
|
|
|
|
void GenerateAggregateInitializer(io::Printer* p) const override {
|
|
ABSL_CHECK(!should_split());
|
|
p->Emit(R"cc(
|
|
decltype($field_$){arena},
|
|
)cc");
|
|
GenerateCacheSizeInitializer(p);
|
|
}
|
|
|
|
void GenerateCopyAggregateInitializer(io::Printer* p) const override {
|
|
ABSL_CHECK(!should_split());
|
|
p->Emit(R"cc(
|
|
decltype($field_$){from.$field_$},
|
|
)cc");
|
|
GenerateCacheSizeInitializer(p);
|
|
}
|
|
|
|
void GenerateMemberConstexprConstructor(io::Printer* p) const override {
|
|
p->Emit("$name$_{}");
|
|
if (HasCachedSize()) {
|
|
p->Emit(",\n_$name$_cached_byte_size_{0}");
|
|
}
|
|
}
|
|
|
|
void GenerateMemberConstructor(io::Printer* p) const override {
|
|
p->Emit("$name$_{visibility, arena}");
|
|
if (HasCachedSize()) {
|
|
p->Emit(",\n_$name$_cached_byte_size_{0}");
|
|
}
|
|
}
|
|
|
|
void GenerateMemberCopyConstructor(io::Printer* p) const override {
|
|
p->Emit("$name$_{visibility, arena, from.$name$_}");
|
|
if (HasCachedSize()) {
|
|
p->Emit(",\n_$name$_cached_byte_size_{0}");
|
|
}
|
|
}
|
|
|
|
void GenerateOneofCopyConstruct(io::Printer* p) const override {
|
|
ABSL_LOG(FATAL) << "Not supported";
|
|
}
|
|
|
|
void GeneratePrivateMembers(io::Printer* p) const override;
|
|
void GenerateAccessorDeclarations(io::Printer* p) const override;
|
|
void GenerateInlineAccessorDefinitions(io::Printer* p) const override;
|
|
void GenerateSerializeWithCachedSizesToArray(io::Printer* p) const override;
|
|
void GenerateByteSize(io::Printer* p) const override;
|
|
|
|
private:
|
|
bool HasCachedSize() const {
|
|
bool is_packed_varint =
|
|
field_->is_packed() && !FixedSize(field_->type()).has_value();
|
|
return is_packed_varint && HasGeneratedMethods(field_->file(), *opts_) &&
|
|
!should_split();
|
|
}
|
|
|
|
void GenerateCacheSizeInitializer(io::Printer* p) const {
|
|
if (!HasCachedSize()) return;
|
|
// std::atomic has no move constructor, which prevents explicit aggregate
|
|
// initialization pre-C++17.
|
|
p->Emit(R"cc(
|
|
/* $_field_cached_byte_size_$ = */ {0},
|
|
)cc");
|
|
}
|
|
|
|
const Options* opts_;
|
|
};
|
|
|
|
void RepeatedPrimitive::GeneratePrivateMembers(io::Printer* p) const {
|
|
if (should_split()) {
|
|
p->Emit(R"cc(
|
|
$pbi$::RawPtr<$pb$::RepeatedField<$Type$>> $name$_;
|
|
)cc");
|
|
} else {
|
|
p->Emit(R"cc(
|
|
$pb$::RepeatedField<$Type$> $name$_;
|
|
)cc");
|
|
}
|
|
|
|
if (HasCachedSize()) {
|
|
p->Emit({{"_cached_size_", MakeVarintCachedSizeName(field_)}},
|
|
R"cc(
|
|
mutable $pbi$::CachedSize $_cached_size_$;
|
|
)cc");
|
|
}
|
|
}
|
|
|
|
void RepeatedPrimitive::GenerateAccessorDeclarations(io::Printer* p) const {
|
|
auto v = p->WithVars(
|
|
AnnotatedAccessors(field_, {"", "_internal_", "_internal_mutable_"}));
|
|
auto vs =
|
|
p->WithVars(AnnotatedAccessors(field_, {"set_", "add_"}, Semantic::kSet));
|
|
auto va =
|
|
p->WithVars(AnnotatedAccessors(field_, {"mutable_"}, Semantic::kAlias));
|
|
p->Emit(R"cc(
|
|
$DEPRECATED$ $Type$ $name$(int index) const;
|
|
$DEPRECATED$ void $set_name$(int index, $Type$ value);
|
|
$DEPRECATED$ void $add_name$($Type$ value);
|
|
$DEPRECATED$ const $pb$::RepeatedField<$Type$>& $name$() const;
|
|
$DEPRECATED$ $pb$::RepeatedField<$Type$>* $mutable_name$();
|
|
|
|
private:
|
|
const $pb$::RepeatedField<$Type$>& $_internal_name$() const;
|
|
$pb$::RepeatedField<$Type$>* $_internal_mutable_name$();
|
|
|
|
public:
|
|
)cc");
|
|
}
|
|
|
|
void RepeatedPrimitive::GenerateInlineAccessorDefinitions(
|
|
io::Printer* p) const {
|
|
p->Emit(R"cc(
|
|
inline $Type$ $Msg$::$name$(int index) const {
|
|
$WeakDescriptorSelfPin$;
|
|
$annotate_get$;
|
|
// @@protoc_insertion_point(field_get:$pkg.Msg.field$)
|
|
return _internal_$name_internal$().Get(index);
|
|
}
|
|
)cc");
|
|
p->Emit(R"cc(
|
|
inline void $Msg$::set_$name$(int index, $Type$ value) {
|
|
$WeakDescriptorSelfPin$;
|
|
$annotate_set$;
|
|
_internal_mutable_$name_internal$()->Set(index, value);
|
|
// @@protoc_insertion_point(field_set:$pkg.Msg.field$)
|
|
}
|
|
)cc");
|
|
p->Emit(R"cc(
|
|
inline void $Msg$::add_$name$($Type$ value) {
|
|
$WeakDescriptorSelfPin$;
|
|
$TsanDetectConcurrentMutation$;
|
|
_internal_mutable_$name_internal$()->Add(value);
|
|
$annotate_add$;
|
|
// @@protoc_insertion_point(field_add:$pkg.Msg.field$)
|
|
}
|
|
)cc");
|
|
p->Emit(R"cc(
|
|
inline const $pb$::RepeatedField<$Type$>& $Msg$::$name$() const
|
|
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
|
$WeakDescriptorSelfPin$;
|
|
$annotate_list$;
|
|
// @@protoc_insertion_point(field_list:$pkg.Msg.field$)
|
|
return _internal_$name_internal$();
|
|
}
|
|
)cc");
|
|
p->Emit(R"cc(
|
|
inline $pb$::RepeatedField<$Type$>* $Msg$::mutable_$name$()
|
|
ABSL_ATTRIBUTE_LIFETIME_BOUND {
|
|
$WeakDescriptorSelfPin$;
|
|
$annotate_mutable_list$;
|
|
// @@protoc_insertion_point(field_mutable_list:$pkg.Msg.field$)
|
|
$TsanDetectConcurrentMutation$;
|
|
return _internal_mutable_$name_internal$();
|
|
}
|
|
)cc");
|
|
|
|
if (should_split()) {
|
|
p->Emit(R"cc(
|
|
inline const $pb$::RepeatedField<$Type$>&
|
|
$Msg$::_internal_$name_internal$() const {
|
|
$TsanDetectConcurrentRead$;
|
|
return *$field_$;
|
|
}
|
|
inline $pb$::RepeatedField<$Type$>* $Msg$::_internal_mutable_$name_internal$() {
|
|
$TsanDetectConcurrentRead$;
|
|
$PrepareSplitMessageForWrite$;
|
|
if ($field_$.IsDefault()) {
|
|
$field_$.Set($pb$::Arena::Create<$pb$::RepeatedField<$Type$>>(GetArena()));
|
|
}
|
|
return $field_$.Get();
|
|
}
|
|
)cc");
|
|
} else {
|
|
p->Emit(R"cc(
|
|
inline const $pb$::RepeatedField<$Type$>&
|
|
$Msg$::_internal_$name_internal$() const {
|
|
$TsanDetectConcurrentRead$;
|
|
return $field_$;
|
|
}
|
|
inline $pb$::RepeatedField<$Type$>* $Msg$::_internal_mutable_$name_internal$() {
|
|
$TsanDetectConcurrentRead$;
|
|
return &$field_$;
|
|
}
|
|
)cc");
|
|
}
|
|
}
|
|
|
|
void RepeatedPrimitive::GenerateSerializeWithCachedSizesToArray(
|
|
io::Printer* p) const {
|
|
if (!field_->is_packed()) {
|
|
p->Emit(R"cc(
|
|
for (int i = 0, n = this->_internal_$name$_size(); i < n; ++i) {
|
|
target = stream->EnsureSpace(target);
|
|
target = ::_pbi::WireFormatLite::Write$DeclaredType$ToArray(
|
|
$number$, this->_internal_$name$().Get(i), target);
|
|
}
|
|
)cc");
|
|
return;
|
|
}
|
|
|
|
if (FixedSize(field_->type()).has_value()) {
|
|
p->Emit(R"cc(
|
|
if (this->_internal_$name$_size() > 0) {
|
|
target = stream->WriteFixedPacked($number$, _internal_$name$(), target);
|
|
}
|
|
)cc");
|
|
return;
|
|
}
|
|
|
|
p->Emit(
|
|
{
|
|
{"byte_size",
|
|
[&] {
|
|
if (HasCachedSize()) {
|
|
p->Emit(R"cc($_field_cached_byte_size_$.Get();)cc");
|
|
} else {
|
|
p->Emit(R"cc(
|
|
::_pbi::WireFormatLite::$DeclaredType$Size(
|
|
this->_internal_$name$());
|
|
)cc");
|
|
}
|
|
}},
|
|
},
|
|
R"cc(
|
|
{
|
|
int byte_size = $byte_size$;
|
|
if (byte_size > 0) {
|
|
target = stream->Write$DeclaredType$Packed(
|
|
$number$, _internal_$name$(), byte_size, target);
|
|
}
|
|
}
|
|
)cc");
|
|
}
|
|
|
|
void RepeatedPrimitive::GenerateByteSize(io::Printer* p) const {
|
|
p->Emit(
|
|
{
|
|
Sub{"data_size",
|
|
[&] {
|
|
auto fixed_size = FixedSize(field_->type());
|
|
if (fixed_size.has_value()) {
|
|
p->Emit({{"kFixed", *fixed_size}}, R"cc(
|
|
std::size_t{$kFixed$} *
|
|
::_pbi::FromIntSize(this->_internal_$name$_size())
|
|
)cc");
|
|
} else {
|
|
p->Emit(R"cc(
|
|
::_pbi::WireFormatLite::$DeclaredType$Size(
|
|
this->_internal_$name$())
|
|
)cc");
|
|
}
|
|
}} // Here and below, we need to disable the default ;-chomping
|
|
// that closure substitutions do.
|
|
.WithSuffix(""),
|
|
{"maybe_cache_data_size",
|
|
[&] {
|
|
if (!HasCachedSize()) return;
|
|
p->Emit(R"cc(
|
|
$_field_cached_byte_size_$.Set(::_pbi::ToCachedSize(data_size));
|
|
)cc");
|
|
}},
|
|
Sub{"tag_size",
|
|
[&] {
|
|
if (field_->is_packed()) {
|
|
p->Emit(R"cc(
|
|
data_size == 0
|
|
? 0
|
|
: $kTagBytes$ + ::_pbi::WireFormatLite::Int32Size(
|
|
static_cast<int32_t>(data_size))
|
|
)cc");
|
|
} else {
|
|
p->Emit(R"cc(
|
|
std::size_t{$kTagBytes$} *
|
|
::_pbi::FromIntSize(this->_internal_$name$_size());
|
|
)cc");
|
|
}
|
|
}}
|
|
.WithSuffix(""),
|
|
},
|
|
R"cc(
|
|
std::size_t data_size = $data_size$;
|
|
$maybe_cache_data_size$;
|
|
std::size_t tag_size = $tag_size$;
|
|
total_size += tag_size + data_size;
|
|
)cc");
|
|
}
|
|
} // namespace
|
|
|
|
std::unique_ptr<FieldGeneratorBase> MakeSinguarPrimitiveGenerator(
|
|
const FieldDescriptor* desc, const Options& options,
|
|
MessageSCCAnalyzer* scc) {
|
|
return absl::make_unique<SingularPrimitive>(desc, options, scc);
|
|
}
|
|
|
|
std::unique_ptr<FieldGeneratorBase> MakeRepeatedPrimitiveGenerator(
|
|
const FieldDescriptor* desc, const Options& options,
|
|
MessageSCCAnalyzer* scc) {
|
|
return absl::make_unique<RepeatedPrimitive>(desc, options, scc);
|
|
}
|
|
|
|
} // namespace cpp
|
|
} // namespace compiler
|
|
} // namespace protobuf
|
|
} // namespace google
|