protobuf/src/google/protobuf/compiler/cpp/field_generators/enum_field.cc

576 lines
17 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 <memory>
#include <string>
#include <vector>
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
#include "absl/memory/memory.h"
#include "absl/strings/substitute.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"
namespace google {
namespace protobuf {
namespace compiler {
namespace cpp {
namespace {
using Semantic = ::google::protobuf::io::AnnotationCollector::Semantic;
using Sub = ::google::protobuf::io::Printer::Sub;
std::vector<Sub> Vars(const FieldDescriptor* field, const Options& opts) {
const EnumValueDescriptor* default_value = field->default_value_enum();
bool split = ShouldSplit(field, opts);
bool is_open = internal::cpp::HasPreservingUnknownEnumSemantics(field);
auto enum_name = QualifiedClassName(field->enum_type(), opts);
return {
{"Enum", enum_name},
{"kDefault", Int32ToString(default_value->number())},
Sub("assert_valid",
is_open ? ""
: absl::Substitute("assert($0_IsValid(value));", enum_name))
.WithSuffix(";"),
{"cached_size_name", MakeVarintCachedSizeName(field)},
{"cached_size_", MakeVarintCachedSizeFieldName(field, split)},
};
}
class SingularEnum : public FieldGeneratorBase {
public:
SingularEnum(const FieldDescriptor* field, const Options& opts,
MessageSCCAnalyzer* scc)
: FieldGeneratorBase(field, opts, scc), opts_(&opts) {}
~SingularEnum() override = default;
std::vector<Sub> MakeVars() const override { return Vars(field_, *opts_); }
void GeneratePrivateMembers(io::Printer* p) const override {
p->Emit(R"cc(
int $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()) return;
p->Emit(R"cc(
swap($field_$, other->$field_$);
)cc");
}
void GenerateConstructorCode(io::Printer* p) const override {
if (!is_oneof()) return;
p->Emit(R"cc(
$ns$::_$Msg$_default_instance_.$field_$ = $kDefault$;
)cc");
}
void GenerateCopyConstructorCode(io::Printer* p) const override {
p->Emit(R"cc(
_this->$field_$ = from.$field_$;
)cc");
}
void GenerateSerializeWithCachedSizesToArray(io::Printer* p) const override {
p->Emit(R"cc(
target = stream->EnsureSpace(target);
target = ::_pbi::WireFormatLite::WriteEnumToArray(
$number$, this->_internal_$name$(), target);
)cc");
}
void GenerateByteSize(io::Printer* p) const override {
p->Emit(R"cc(
total_size += $kTagBytes$ +
::_pbi::WireFormatLite::EnumSize(this->_internal_$name$());
)cc");
}
void GenerateConstexprAggregateInitializer(io::Printer* p) const override {
p->Emit(R"cc(
/*decltype($field_$)*/ $kDefault$,
)cc");
}
void GenerateAggregateInitializer(io::Printer* p) const override {
if (should_split()) {
p->Emit(R"cc(
decltype(Impl_::Split::$name$_){$kDefault$},
)cc");
} else {
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;
private:
const Options* opts_;
};
void SingularEnum::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$ $Enum$ $name$() const;
$DEPRECATED$ void $set_name$($Enum$ value);
private:
$Enum$ $_internal_name$() const;
void $_internal_set_name$($Enum$ value);
public:
)cc");
}
void SingularEnum::GenerateInlineAccessorDefinitions(io::Printer* p) const {
p->Emit(R"cc(
inline $Enum$ $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$($Enum$ value) {
$WeakDescriptorSelfPin$;
$PrepareSplitMessageForWrite$;
$assert_valid$;
if ($not_has_field$) {
clear_$oneof_name$();
set_has_$name_internal$();
}
$field_$ = value;
$annotate_set$;
// @@protoc_insertion_point(field_set:$pkg.Msg.field$)
}
inline $Enum$ $Msg$::_internal_$name_internal$() const {
if ($has_field$) {
return static_cast<$Enum$>($field_$);
}
return static_cast<$Enum$>($kDefault$);
}
)cc");
} else {
p->Emit(R"cc(
inline void $Msg$::set_$name$($Enum$ value) {
$WeakDescriptorSelfPin$;
$PrepareSplitMessageForWrite$;
_internal_set_$name_internal$(value);
$set_hasbit$;
$annotate_set$;
// @@protoc_insertion_point(field_set:$pkg.Msg.field$)
}
inline $Enum$ $Msg$::_internal_$name_internal$() const {
$TsanDetectConcurrentRead$;
return static_cast<$Enum$>($field_$);
}
inline void $Msg$::_internal_set_$name_internal$($Enum$ value) {
$TsanDetectConcurrentMutation$;
$assert_valid$;
$field_$ = value;
}
)cc");
}
}
class RepeatedEnum : public FieldGeneratorBase {
public:
RepeatedEnum(const FieldDescriptor* field, const Options& opts,
MessageSCCAnalyzer* scc)
: FieldGeneratorBase(field, opts, scc),
opts_(&opts),
has_cached_size_(field_->is_packed() &&
HasGeneratedMethods(field_->file(), opts) &&
!should_split()) {}
~RepeatedEnum() override = default;
std::vector<Sub> MakeVars() const override { return Vars(field_, *opts_); }
void GeneratePrivateMembers(io::Printer* p) const override {
if (should_split()) {
p->Emit(R"cc(
$pbi$::RawPtr<$pb$::RepeatedField<int>> $name$_;
)cc");
} else {
p->Emit(R"cc(
$pb$::RepeatedField<int> $name$_;
)cc");
}
if (has_cached_size_) {
p->Emit(R"cc(
mutable $pbi$::CachedSize $cached_size_name$;
)cc");
}
}
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 GenerateConstexprAggregateInitializer(io::Printer* p) const override {
p->Emit(R"cc(
/*decltype($field_$)*/ {},
)cc");
if (has_cached_size_) {
p->Emit(R"cc(
/*decltype($cached_size_$)*/ {0},
)cc");
}
}
void GenerateAggregateInitializer(io::Printer* p) const override {
p->Emit(R"cc(
decltype($field_$){arena},
)cc");
if (has_cached_size_) {
// std::atomic has no copy constructor, which prevents explicit aggregate
// initialization pre-C++17.
p->Emit(R"cc(
/*decltype($cached_size_$)*/ {0},
)cc");
}
}
void GenerateCopyAggregateInitializer(io::Printer* p) const override {
p->Emit(R"cc(
decltype($field_$){from._internal_$name$()},
)cc");
if (has_cached_size_) {
// std::atomic has no copy constructor.
p->Emit(R"cc(
/*decltype($cached_size_$)*/ {0},
)cc");
}
}
void GenerateMemberConstexprConstructor(io::Printer* p) const override {
p->Emit("$name$_{}");
if (has_cached_size_) {
p->Emit(",\n_$name$_cached_byte_size_{0}");
}
}
void GenerateMemberConstructor(io::Printer* p) const override {
p->Emit("$name$_{visibility, arena}");
if (has_cached_size_) {
p->Emit(",\n_$name$_cached_byte_size_{0}");
}
}
void GenerateMemberCopyConstructor(io::Printer* p) const override {
p->Emit("$name$_{visibility, arena, from.$name$_}");
if (has_cached_size_) {
p->Emit(",\n_$name$_cached_byte_size_{0}");
}
}
void GenerateOneofCopyConstruct(io::Printer* p) const override {
ABSL_LOG(FATAL) << "Not supported";
}
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 GenerateConstructorCode(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:
const Options* opts_;
bool has_cached_size_;
};
void RepeatedEnum::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 vm =
p->WithVars(AnnotatedAccessors(field_, {"mutable_"}, Semantic::kAlias));
p->Emit(R"cc(
public:
$DEPRECATED$ $Enum$ $name$(int index) const;
$DEPRECATED$ void $set_name$(int index, $Enum$ value);
$DEPRECATED$ void $add_name$($Enum$ value);
$DEPRECATED$ const $pb$::RepeatedField<int>& $name$() const;
$DEPRECATED$ $pb$::RepeatedField<int>* $mutable_name$();
private:
const $pb$::RepeatedField<int>& $_internal_name$() const;
$pb$::RepeatedField<int>* $_internal_mutable_name$();
public:
)cc");
}
void RepeatedEnum::GenerateInlineAccessorDefinitions(io::Printer* p) const {
p->Emit(R"cc(
inline $Enum$ $Msg$::$name$(int index) const {
$WeakDescriptorSelfPin$;
$annotate_get$;
// @@protoc_insertion_point(field_get:$pkg.Msg.field$)
return static_cast<$Enum$>(_internal_$name_internal$().Get(index));
}
)cc");
p->Emit(R"cc(
inline void $Msg$::set_$name$(int index, $Enum$ value) {
$WeakDescriptorSelfPin$;
$assert_valid$;
_internal_mutable_$name_internal$()->Set(index, value);
$annotate_set$
// @@protoc_insertion_point(field_set:$pkg.Msg.field$)
}
)cc");
p->Emit(R"cc(
inline void $Msg$::add_$name$($Enum$ value) {
$WeakDescriptorSelfPin$;
$assert_valid$;
$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<int>& $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<int>* $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<int>& $Msg$::_internal_$name_internal$()
const {
$TsanDetectConcurrentRead$;
return *$field_$;
}
inline $pb$::RepeatedField<int>* $Msg$::_internal_mutable_$name_internal$() {
$TsanDetectConcurrentRead$;
$PrepareSplitMessageForWrite$;
if ($field_$.IsDefault()) {
$field_$.Set($pb$::Arena::Create<$pb$::RepeatedField<int>>(GetArena()));
}
return $field_$.Get();
}
)cc");
} else {
p->Emit(R"cc(
inline const $pb$::RepeatedField<int>& $Msg$::_internal_$name_internal$()
const {
$TsanDetectConcurrentRead$;
return $field_$;
}
inline $pb$::RepeatedField<int>* $Msg$::_internal_mutable_$name_internal$() {
$TsanDetectConcurrentRead$;
return &$field_$;
}
)cc");
}
}
void RepeatedEnum::GenerateSerializeWithCachedSizesToArray(
io::Printer* p) const {
if (field_->is_packed()) {
p->Emit(
{
{"byte_size",
[&] {
if (has_cached_size_) {
p->Emit(
R"cc(std::size_t byte_size = $cached_size_$.Get();)cc");
} else {
p->Emit(R"cc(
std::size_t byte_size = 0;
auto count = static_cast<std::size_t>(this->_internal_$name$_size());
for (std::size_t i = 0; i < count; ++i) {
byte_size += ::_pbi::WireFormatLite::EnumSize(
this->_internal_$name$().Get(static_cast<int>(i)));
}
)cc");
}
}},
},
R"cc(
{
$byte_size$;
if (byte_size > 0) {
target = stream->WriteEnumPacked($number$, _internal_$name$(),
byte_size, target);
}
}
)cc");
return;
}
p->Emit(R"cc(
for (int i = 0, n = this->_internal_$name$_size(); i < n; ++i) {
target = stream->EnsureSpace(target);
target = ::_pbi::WireFormatLite::WriteEnumToArray(
$number$, static_cast<$Enum$>(this->_internal_$name$().Get(i)),
target);
}
)cc");
}
void RepeatedEnum::GenerateByteSize(io::Printer* p) const {
p->Emit(
{
{"add_to_size",
[&] {
if (!field_->is_packed()) {
p->Emit(R"cc(
total_size += std::size_t{$kTagBytes$} * count;
)cc");
return;
}
p->Emit(R"cc(
if (data_size > 0) {
total_size += $kTagBytes$;
total_size += ::_pbi::WireFormatLite::Int32Size(
static_cast<int32_t>(data_size));
}
)cc");
if (has_cached_size_) {
p->Emit(R"cc(
$cached_size_$.Set(::_pbi::ToCachedSize(data_size));
)cc");
}
}},
},
R"cc(
std::size_t data_size = 0;
auto count = static_cast<std::size_t>(this->_internal_$name$_size());
for (std::size_t i = 0; i < count; ++i) {
data_size += ::_pbi::WireFormatLite::EnumSize(
this->_internal_$name$().Get(static_cast<int>(i)));
}
total_size += data_size;
$add_to_size$;
)cc");
}
} // namespace
std::unique_ptr<FieldGeneratorBase> MakeSinguarEnumGenerator(
const FieldDescriptor* desc, const Options& options,
MessageSCCAnalyzer* scc) {
return absl::make_unique<SingularEnum>(desc, options, scc);
}
std::unique_ptr<FieldGeneratorBase> MakeRepeatedEnumGenerator(
const FieldDescriptor* desc, const Options& options,
MessageSCCAnalyzer* scc) {
return absl::make_unique<RepeatedEnum>(desc, options, scc);
}
} // namespace cpp
} // namespace compiler
} // namespace protobuf
} // namespace google