Merge tag 'refs/tags/sync-piper' into sync-stage
This commit is contained in:
commit
e94aa9ff0b
@ -87,8 +87,8 @@ set(libprotoc_files
|
||||
set(libprotoc_headers
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/code_generator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/command_line_interface.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/file.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/cpp_generator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/file.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/generator.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/helpers.h
|
||||
${protobuf_SOURCE_DIR}/src/google/protobuf/compiler/cpp/names.h
|
||||
|
@ -74,8 +74,8 @@ nobase_include_HEADERS = \
|
||||
google/protobuf/arenaz_sampler.h \
|
||||
google/protobuf/compiler/code_generator.h \
|
||||
google/protobuf/compiler/command_line_interface.h \
|
||||
google/protobuf/compiler/cpp/file.h \
|
||||
google/protobuf/compiler/cpp/cpp_generator.h \
|
||||
google/protobuf/compiler/cpp/file.h \
|
||||
google/protobuf/compiler/cpp/generator.h \
|
||||
google/protobuf/compiler/cpp/helpers.h \
|
||||
google/protobuf/compiler/cpp/names.h \
|
||||
|
@ -37,6 +37,7 @@
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/wire_format.h>
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
#include <google/protobuf/compiler/cpp/field.h>
|
||||
#include <google/protobuf/compiler/cpp/helpers.h>
|
||||
|
||||
namespace google {
|
||||
@ -55,8 +56,9 @@ void SetEnumVariables(const FieldDescriptor* descriptor,
|
||||
(*variables)["default"] = Int32ToString(default_value->number());
|
||||
(*variables)["full_name"] = descriptor->full_name();
|
||||
(*variables)["cached_byte_size_name"] = MakeVarintCachedSizeName(descriptor);
|
||||
bool cold = ShouldSplit(descriptor, options);
|
||||
(*variables)["cached_byte_size_field"] =
|
||||
MakeVarintCachedSizeFieldName(descriptor);
|
||||
MakeVarintCachedSizeFieldName(descriptor, cold);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@ -110,6 +112,7 @@ void EnumFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
" $field$ = value;\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$($type$ value) {\n"
|
||||
"$maybe_prepare_split_message$"
|
||||
" _internal_set_$name$(value);\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set:$full_name$)\n"
|
||||
@ -162,6 +165,10 @@ void EnumFieldGenerator::GenerateConstexprAggregateInitializer(
|
||||
void EnumFieldGenerator::GenerateAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("decltype(Impl_::Split::$name$_){$default$}");
|
||||
return;
|
||||
}
|
||||
format("decltype($field$){$default$}");
|
||||
}
|
||||
|
||||
|
@ -101,7 +101,9 @@ class RepeatedEnumFieldGenerator : public FieldGenerator {
|
||||
void GenerateMergingCode(io::Printer* printer) const override;
|
||||
void GenerateSwappingCode(io::Printer* printer) const override;
|
||||
void GenerateConstructorCode(io::Printer* printer) const override;
|
||||
void GenerateCopyConstructorCode(io::Printer* printer) const override {}
|
||||
void GenerateCopyConstructorCode(io::Printer* /*printer*/) const override {
|
||||
GOOGLE_CHECK(!ShouldSplit(descriptor_, options_));
|
||||
}
|
||||
void GenerateDestructorCode(io::Printer* printer) const override;
|
||||
void GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const override;
|
||||
|
@ -244,7 +244,8 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
|
||||
(*variables)["number"] = StrCat(descriptor->number());
|
||||
(*variables)["classname"] = ClassName(FieldScope(descriptor), false);
|
||||
(*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
|
||||
(*variables)["field"] = FieldMemberName(descriptor);
|
||||
bool split = ShouldSplit(descriptor, options);
|
||||
(*variables)["field"] = FieldMemberName(descriptor, split);
|
||||
|
||||
(*variables)["tag_size"] = StrCat(
|
||||
WireFormat::TagSize(descriptor->number(), descriptor->type()));
|
||||
@ -252,6 +253,8 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
|
||||
|
||||
(*variables)["set_hasbit"] = "";
|
||||
(*variables)["clear_hasbit"] = "";
|
||||
(*variables)["maybe_prepare_split_message"] =
|
||||
split ? " PrepareSplitMessageForWrite();\n" : "";
|
||||
|
||||
AddAccessorAnnotations(descriptor, options, variables);
|
||||
|
||||
@ -299,6 +302,10 @@ void FieldGenerator::SetInlinedStringIndex(int32_t inlined_string_index) {
|
||||
|
||||
void FieldGenerator::GenerateAggregateInitializer(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("decltype(Impl_::Split::$name$_){arena}");
|
||||
return;
|
||||
}
|
||||
format("decltype($field$){arena}");
|
||||
}
|
||||
|
||||
@ -314,6 +321,15 @@ void FieldGenerator::GenerateCopyAggregateInitializer(
|
||||
format("decltype($field$){from.$field$}");
|
||||
}
|
||||
|
||||
void FieldGenerator::GenerateCopyConstructorCode(io::Printer* printer) const {
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
// There is no copy constructor for the `Split` struct, so we need to copy
|
||||
// the value here.
|
||||
Formatter format(printer, variables_);
|
||||
format("$field$ = from.$field$;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void SetCommonOneofFieldVariables(
|
||||
const FieldDescriptor* descriptor,
|
||||
std::map<std::string, std::string>* variables) {
|
||||
|
@ -136,7 +136,7 @@ class FieldGenerator {
|
||||
virtual void GenerateMergingCode(io::Printer* printer) const = 0;
|
||||
|
||||
// Generates a copy constructor
|
||||
virtual void GenerateCopyConstructorCode(io::Printer* printer) const = 0;
|
||||
virtual void GenerateCopyConstructorCode(io::Printer* printer) const;
|
||||
|
||||
// Generate lines of code (statements, not declarations) which swaps
|
||||
// this field and the corresponding field of another message, which
|
||||
@ -150,6 +150,9 @@ class FieldGenerator {
|
||||
// method, invoked by each of the generated constructors.
|
||||
virtual void GenerateConstructorCode(io::Printer* printer) const = 0;
|
||||
|
||||
// Generate initialization code for private members in the cold struct.
|
||||
virtual void GenerateCreateSplitMessageCode(io::Printer* printer) const {}
|
||||
|
||||
// Generate any code that needs to go in the class's SharedDtor() method,
|
||||
// invoked by the destructor.
|
||||
// Most field types don't need this, so the default implementation is empty.
|
||||
|
@ -480,10 +480,40 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx,
|
||||
io::Printer* printer) {
|
||||
Formatter format(printer, variables_);
|
||||
MessageGenerator* generator = message_generators_[idx].get();
|
||||
// Generate the split instance first because it's needed in the constexpr
|
||||
// constructor.
|
||||
if (ShouldSplit(generator->descriptor_, options_)) {
|
||||
// Use a union to disable the destructor of the _instance member.
|
||||
// We can constant initialize, but the object will still have a non-trivial
|
||||
// destructor that we need to elide.
|
||||
format(
|
||||
"struct $1$ {\n"
|
||||
" PROTOBUF_CONSTEXPR $1$()\n"
|
||||
" : _instance{",
|
||||
DefaultInstanceType(generator->descriptor_, options_,
|
||||
/*split=*/true));
|
||||
generator->GenerateInitDefaultSplitInstance(printer);
|
||||
format(
|
||||
"} {}\n"
|
||||
" ~$1$() {}\n"
|
||||
" union {\n"
|
||||
" $2$ _instance;\n"
|
||||
" };\n"
|
||||
"};\n",
|
||||
DefaultInstanceType(generator->descriptor_, options_, /*split=*/true),
|
||||
StrCat(generator->classname_, "::Impl_::Split"));
|
||||
// NO_DESTROY is not necessary for correctness. The empty destructor is
|
||||
// enough. However, the empty destructor fails to be elided in some
|
||||
// configurations (like non-opt or with certain sanitizers). NO_DESTROY is
|
||||
// there just to improve performance and binary size in these builds.
|
||||
format(
|
||||
"PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT "
|
||||
"PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $1$ $2$;\n",
|
||||
DefaultInstanceType(generator->descriptor_, options_, /*split=*/true),
|
||||
DefaultInstanceName(generator->descriptor_, options_, /*split=*/true));
|
||||
}
|
||||
|
||||
generator->GenerateConstexprConstructor(printer);
|
||||
// Use a union to disable the destructor of the _instance member.
|
||||
// We can constant initialize, but the object will still have a non-trivial
|
||||
// destructor that we need to elide.
|
||||
format(
|
||||
"struct $1$ {\n"
|
||||
" PROTOBUF_CONSTEXPR $1$()\n"
|
||||
@ -495,14 +525,11 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx,
|
||||
"};\n",
|
||||
DefaultInstanceType(generator->descriptor_, options_),
|
||||
generator->classname_);
|
||||
// NO_DESTROY is not necessary for correctness. The empty destructor is
|
||||
// enough. However, the empty destructor fails to be elided in some
|
||||
// configurations (like non-opt or with certain sanitizers). NO_DESTROY is
|
||||
// there just to improve performance and binary size in these builds.
|
||||
format("PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT "
|
||||
"PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $1$ $2$;\n",
|
||||
DefaultInstanceType(generator->descriptor_, options_),
|
||||
DefaultInstanceName(generator->descriptor_, options_));
|
||||
format(
|
||||
"PROTOBUF_ATTRIBUTE_NO_DESTROY PROTOBUF_CONSTINIT "
|
||||
"PROTOBUF_ATTRIBUTE_INIT_PRIORITY1 $1$ $2$;\n",
|
||||
DefaultInstanceType(generator->descriptor_, options_),
|
||||
DefaultInstanceName(generator->descriptor_, options_));
|
||||
|
||||
for (int i = 0; i < generator->descriptor_->field_count(); i++) {
|
||||
const FieldDescriptor* field = generator->descriptor_->field(i);
|
||||
@ -514,7 +541,7 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx,
|
||||
"($3$._instance.$4$.Init(), std::true_type{});\n",
|
||||
ClassName(generator->descriptor_), FieldName(field),
|
||||
DefaultInstanceName(generator->descriptor_, options_),
|
||||
FieldMemberName(field));
|
||||
FieldMemberName(field, ShouldSplit(field, options_)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -947,6 +974,7 @@ class FileGenerator::ForwardDeclarations {
|
||||
public:
|
||||
void AddMessage(const Descriptor* d) { classes_[ClassName(d)] = d; }
|
||||
void AddEnum(const EnumDescriptor* d) { enums_[ClassName(d)] = d; }
|
||||
void AddSplit(const Descriptor* d) { splits_[ClassName(d)] = d; }
|
||||
|
||||
void Print(const Formatter& format, const Options& options) const {
|
||||
for (const auto& p : enums_) {
|
||||
@ -967,6 +995,14 @@ class FileGenerator::ForwardDeclarations {
|
||||
class_desc, classname, DefaultInstanceType(class_desc, options),
|
||||
DefaultInstanceName(class_desc, options));
|
||||
}
|
||||
for (const auto& p : splits_) {
|
||||
const Descriptor* class_desc = p.second;
|
||||
format(
|
||||
"struct $1$;\n"
|
||||
"$dllexport_decl $extern $1$ $2$;\n",
|
||||
DefaultInstanceType(class_desc, options, /*split=*/true),
|
||||
DefaultInstanceName(class_desc, options, /*split=*/true));
|
||||
}
|
||||
}
|
||||
|
||||
void PrintTopLevelDecl(const Formatter& format,
|
||||
@ -982,6 +1018,7 @@ class FileGenerator::ForwardDeclarations {
|
||||
private:
|
||||
std::map<std::string, const Descriptor*> classes_;
|
||||
std::map<std::string, const EnumDescriptor*> enums_;
|
||||
std::map<std::string, const Descriptor*> splits_;
|
||||
};
|
||||
|
||||
static void PublicImportDFS(const FileDescriptor* fd,
|
||||
@ -1027,6 +1064,12 @@ void FileGenerator::GenerateForwardDeclarations(io::Printer* printer) {
|
||||
if (d && !public_set.count(d->file()))
|
||||
decls[Namespace(d, options_)].AddEnum(d);
|
||||
}
|
||||
for (const auto& mg : message_generators_) {
|
||||
const Descriptor* d = mg->descriptor_;
|
||||
if ((d != nullptr) && (public_set.count(d->file()) == 0u) &&
|
||||
ShouldSplit(mg->descriptor_, options_))
|
||||
decls[Namespace(d, options_)].AddSplit(d);
|
||||
}
|
||||
|
||||
{
|
||||
NamespaceOpener ns(format);
|
||||
|
@ -38,6 +38,7 @@
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
@ -185,6 +186,80 @@ bool AllocExpected(const Descriptor* descriptor) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Describes different approaches to detect non-canonical int32 encoding. Only
|
||||
// kNever or kAlways is eligible for *simple* verification methods.
|
||||
enum class VerifyInt32Type {
|
||||
kCustom, // Only check if field number matches.
|
||||
kNever, // Do not check.
|
||||
kAlways, // Always check.
|
||||
};
|
||||
|
||||
inline VerifySimpleType VerifyInt32TypeToVerifyCustom(VerifyInt32Type t) {
|
||||
static VerifySimpleType kCustomTypes[] = {
|
||||
VerifySimpleType::kCustom, VerifySimpleType::kCustomInt32Never,
|
||||
VerifySimpleType::kCustomInt32Always};
|
||||
return kCustomTypes[static_cast<int32_t>(t) -
|
||||
static_cast<int32_t>(VerifyInt32Type::kCustom)];
|
||||
}
|
||||
|
||||
// Returns one of int32 verification types: kNever, kCustom, kAlways.
|
||||
//
|
||||
// We need to verify int32 encoding to detect non-canonical encoding (5B for
|
||||
// negative int32) and fallback to eager parsing.
|
||||
//
|
||||
// kNever skips int32 check because there is no int32 field. kAlways
|
||||
// unconditionally verifies int32 encoding because all or almost varint fields
|
||||
// are int32. Otherwise, kCustom verifies int32 encoding only on exact field
|
||||
// number match. Note the following tweaks:
|
||||
// --uint32 very likely causes false positives. Having one requires kCustom.
|
||||
// --kCustom may be cheap enough if all int32 fields fit into a bitmask.
|
||||
// --Otherwise, try always check if X% of varint fields are int32.
|
||||
VerifyInt32Type ShouldVerifyInt32(const Descriptor* descriptor) {
|
||||
int num_int32 = 0;
|
||||
int num_int32_big_number = 0;
|
||||
int num_uint32 = 0;
|
||||
int num_other_varint = 0;
|
||||
|
||||
for (const auto* field : FieldRange(descriptor)) {
|
||||
switch (field->type()) {
|
||||
case FieldDescriptor::TYPE_INT32:
|
||||
++num_int32;
|
||||
if (field->number() > 64) ++num_int32_big_number;
|
||||
break;
|
||||
case FieldDescriptor::TYPE_UINT32:
|
||||
++num_uint32;
|
||||
++num_other_varint;
|
||||
break;
|
||||
default:
|
||||
if (internal::WireFormat::WireTypeForFieldType(field->type()) ==
|
||||
internal::WireFormatLite::WIRETYPE_VARINT) {
|
||||
++num_other_varint;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no int32 fields, no need to check int32 encoding.
|
||||
if (num_int32 == 0) return VerifyInt32Type::kNever;
|
||||
|
||||
// If all varint fields are int32, *always* check int32 encoding.
|
||||
if (num_other_varint == 0) return VerifyInt32Type::kAlways;
|
||||
|
||||
// Negative uint32 encoding will cause fallback eager parsing as it appears
|
||||
// non-canonical encoding. Also, if all int32 fields fit into a 64 bit mask,
|
||||
// checking bitmask is affordable. Try exact match in these cases.
|
||||
if (num_uint32 > 0 || num_int32_big_number == 0) {
|
||||
return VerifyInt32Type::kCustom;
|
||||
}
|
||||
|
||||
// If a given varint is likely int32, we should just always check. Let's use
|
||||
// an arbitrary threshold of 75% (#int32 / #varints).
|
||||
constexpr int kLikelyInt32Pct = 75;
|
||||
return (100 * num_int32) / (num_int32 + num_other_varint) >= kLikelyInt32Pct
|
||||
? VerifyInt32Type::kAlways
|
||||
: VerifyInt32Type::kCustom;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool IsLazy(const FieldDescriptor* field, const Options& options,
|
||||
@ -261,6 +336,8 @@ void SetCommonMessageDataVariables(
|
||||
(*variables)["oneof_case"] = prefix + "_oneof_case_";
|
||||
(*variables)["tracker"] = "Impl_::_tracker_";
|
||||
(*variables)["weak_field_map"] = prefix + "_weak_field_map_";
|
||||
(*variables)["split"] = prefix + "_split_";
|
||||
(*variables)["cached_split_ptr"] = "cached_split_ptr";
|
||||
}
|
||||
|
||||
void SetUnknownFieldsVariable(const Descriptor* descriptor,
|
||||
@ -425,29 +502,32 @@ std::string Namespace(const EnumDescriptor* d, const Options& options) {
|
||||
}
|
||||
|
||||
std::string DefaultInstanceType(const Descriptor* descriptor,
|
||||
const Options& options) {
|
||||
return ClassName(descriptor) + "DefaultTypeInternal";
|
||||
const Options& /*options*/, bool split) {
|
||||
return ClassName(descriptor) + (split ? "__Impl_Split" : "") +
|
||||
"DefaultTypeInternal";
|
||||
}
|
||||
|
||||
std::string DefaultInstanceName(const Descriptor* descriptor,
|
||||
const Options& options) {
|
||||
return "_" + ClassName(descriptor, false) + "_default_instance_";
|
||||
const Options& /*options*/, bool split) {
|
||||
return "_" + ClassName(descriptor, false) + (split ? "__Impl_Split" : "") +
|
||||
"_default_instance_";
|
||||
}
|
||||
|
||||
std::string DefaultInstancePtr(const Descriptor* descriptor,
|
||||
const Options& options) {
|
||||
return DefaultInstanceName(descriptor, options) + "ptr_";
|
||||
const Options& options, bool split) {
|
||||
return DefaultInstanceName(descriptor, options, split) + "ptr_";
|
||||
}
|
||||
|
||||
std::string QualifiedDefaultInstanceName(const Descriptor* descriptor,
|
||||
const Options& options) {
|
||||
const Options& options, bool split) {
|
||||
return QualifiedFileLevelSymbol(
|
||||
descriptor->file(), DefaultInstanceName(descriptor, options), options);
|
||||
descriptor->file(), DefaultInstanceName(descriptor, options, split),
|
||||
options);
|
||||
}
|
||||
|
||||
std::string QualifiedDefaultInstancePtr(const Descriptor* descriptor,
|
||||
const Options& options) {
|
||||
return QualifiedDefaultInstanceName(descriptor, options) + "ptr_";
|
||||
const Options& options, bool split) {
|
||||
return QualifiedDefaultInstanceName(descriptor, options, split) + "ptr_";
|
||||
}
|
||||
|
||||
std::string DescriptorTableName(const FileDescriptor* file,
|
||||
@ -487,12 +567,15 @@ std::string FieldName(const FieldDescriptor* field) {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string FieldMemberName(const FieldDescriptor* field) {
|
||||
std::string FieldMemberName(const FieldDescriptor* field, bool split) {
|
||||
StringPiece prefix =
|
||||
IsMapEntryMessage(field->containing_type()) ? "" : "_impl_.";
|
||||
StringPiece split_prefix = split ? "_split_->" : "";
|
||||
if (field->real_containing_oneof() == nullptr) {
|
||||
return StrCat(prefix, FieldName(field), "_");
|
||||
return StrCat(prefix, split_prefix, FieldName(field), "_");
|
||||
}
|
||||
// Oneof fields are enver split.
|
||||
GOOGLE_CHECK(!split);
|
||||
return StrCat(prefix, field->containing_oneof()->name(), "_.",
|
||||
FieldName(field), "_");
|
||||
}
|
||||
@ -875,6 +958,9 @@ bool HasLazyFields(const FileDescriptor* file, const Options& options,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ShouldSplit(const Descriptor*, const Options&) { return false; }
|
||||
bool ShouldSplit(const FieldDescriptor*, const Options&) { return false; }
|
||||
|
||||
static bool HasRepeatedFields(const Descriptor* descriptor) {
|
||||
for (int i = 0; i < descriptor->field_count(); ++i) {
|
||||
if (descriptor->field(i)->label() == FieldDescriptor::LABEL_REPEATED) {
|
||||
@ -1016,9 +1102,9 @@ bool IsUtf8String(const FieldDescriptor* field) {
|
||||
field->type() == FieldDescriptor::TYPE_STRING;
|
||||
}
|
||||
|
||||
bool ShouldVerifySimple(const Descriptor* descriptor) {
|
||||
VerifySimpleType ShouldVerifySimple(const Descriptor* descriptor) {
|
||||
(void)descriptor;
|
||||
return false;
|
||||
return VerifySimpleType::kCustom;
|
||||
}
|
||||
|
||||
bool IsStringOrMessage(const FieldDescriptor* field) {
|
||||
|
@ -153,24 +153,26 @@ std::string QualifiedExtensionName(const FieldDescriptor* d);
|
||||
|
||||
// Type name of default instance.
|
||||
std::string DefaultInstanceType(const Descriptor* descriptor,
|
||||
const Options& options);
|
||||
const Options& options, bool split = false);
|
||||
|
||||
// Non-qualified name of the default_instance of this message.
|
||||
std::string DefaultInstanceName(const Descriptor* descriptor,
|
||||
const Options& options);
|
||||
const Options& options, bool split = false);
|
||||
|
||||
// Non-qualified name of the default instance pointer. This is used only for
|
||||
// implicit weak fields, where we need an extra indirection.
|
||||
std::string DefaultInstancePtr(const Descriptor* descriptor,
|
||||
const Options& options);
|
||||
const Options& options, bool split = false);
|
||||
|
||||
// Fully qualified name of the default_instance of this message.
|
||||
std::string QualifiedDefaultInstanceName(const Descriptor* descriptor,
|
||||
const Options& options);
|
||||
const Options& options,
|
||||
bool split = false);
|
||||
|
||||
// Fully qualified name of the default instance pointer.
|
||||
std::string QualifiedDefaultInstancePtr(const Descriptor* descriptor,
|
||||
const Options& options);
|
||||
const Options& options,
|
||||
bool split = false);
|
||||
|
||||
// DescriptorTable variable name.
|
||||
std::string DescriptorTableName(const FileDescriptor* file,
|
||||
@ -194,7 +196,7 @@ std::string ResolveKeyword(const std::string& name);
|
||||
std::string FieldName(const FieldDescriptor* field);
|
||||
|
||||
// Returns the (unqualified) private member name for this field in C++ code.
|
||||
std::string FieldMemberName(const FieldDescriptor* field);
|
||||
std::string FieldMemberName(const FieldDescriptor* field, bool split);
|
||||
|
||||
// Returns an estimate of the compiler's alignment for the field. This
|
||||
// can't guarantee to be correct because the generated code could be compiled on
|
||||
@ -369,6 +371,12 @@ bool IsEagerlyVerifiedLazy(const FieldDescriptor* field, const Options& options,
|
||||
|
||||
bool IsLazilyVerifiedLazy(const FieldDescriptor* field, const Options& options);
|
||||
|
||||
// Is the given message being split (go/pdsplit)?
|
||||
bool ShouldSplit(const Descriptor* desc, const Options& options);
|
||||
|
||||
// Is the given field being split out?
|
||||
bool ShouldSplit(const FieldDescriptor* field, const Options& options);
|
||||
|
||||
inline bool IsFieldUsed(const FieldDescriptor* /* field */,
|
||||
const Options& /* options */) {
|
||||
return true;
|
||||
@ -508,8 +516,10 @@ inline std::string MakeVarintCachedSizeName(const FieldDescriptor* field) {
|
||||
// MakeVarintCachedSizeFieldName, in case the field exists at some nested level
|
||||
// like:
|
||||
// internal_container_._field_cached_byte_size_;
|
||||
inline std::string MakeVarintCachedSizeFieldName(const FieldDescriptor* field) {
|
||||
return StrCat("_impl_._", FieldName(field), "_cached_byte_size_");
|
||||
inline std::string MakeVarintCachedSizeFieldName(const FieldDescriptor* field,
|
||||
bool split) {
|
||||
return StrCat("_impl_.", split ? "_split_->" : "", "_",
|
||||
FieldName(field), "_cached_byte_size_");
|
||||
}
|
||||
|
||||
// Note: A lot of libraries detect Any protos based on Descriptor::full_name()
|
||||
@ -1021,7 +1031,24 @@ bool ShouldVerify(const Descriptor* descriptor, const Options& options,
|
||||
bool ShouldVerify(const FileDescriptor* file, const Options& options,
|
||||
MessageSCCAnalyzer* scc_analyzer);
|
||||
|
||||
bool ShouldVerifySimple(const Descriptor* descriptor);
|
||||
// Indicates whether to use predefined verify methods for a given message. If a
|
||||
// message is "simple" and needs no special verification per field (e.g. message
|
||||
// field, repeated packed, UTF8 string, etc.), we can use either VerifySimple or
|
||||
// VerifySimpleAlwaysCheckInt32 methods as all verification can be done based on
|
||||
// the wire type.
|
||||
//
|
||||
// Otherwise, we need "custom" verify methods tailored to a message to pass
|
||||
// which field needs a special verification; i.e. InternalVerify.
|
||||
enum class VerifySimpleType {
|
||||
kSimpleInt32Never, // Use VerifySimple
|
||||
kSimpleInt32Always, // Use VerifySimpleAlwaysCheckInt32
|
||||
kCustom, // Use InternalVerify and check only for int32
|
||||
kCustomInt32Never, // Use InternalVerify but never check for int32
|
||||
kCustomInt32Always, // Use InternalVerify and always check for int32
|
||||
};
|
||||
|
||||
// Returns VerifySimpleType if messages can be verified by predefined methods.
|
||||
VerifySimpleType ShouldVerifySimple(const Descriptor* descriptor);
|
||||
|
||||
bool IsUtf8String(const FieldDescriptor* field);
|
||||
|
||||
|
@ -136,6 +136,7 @@ void MapFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
"}\n"
|
||||
"inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
|
||||
"$classname$::_internal_mutable_$name$() {\n"
|
||||
"$maybe_prepare_split_message$"
|
||||
" return $field$.MutableMap();\n"
|
||||
"}\n"
|
||||
"inline ::$proto_ns$::Map< $key_cpp$, $val_cpp$ >*\n"
|
||||
@ -291,6 +292,12 @@ void MapFieldGenerator::GenerateCopyAggregateInitializer(
|
||||
void MapFieldGenerator::GenerateAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format(
|
||||
"/*decltype($classname$::Split::$name$_)*/"
|
||||
"{::_pbi::ArenaInitialized(), arena}");
|
||||
return;
|
||||
}
|
||||
// MapField has no move constructor.
|
||||
format("/*decltype($field$)*/{::_pbi::ArenaInitialized(), arena}");
|
||||
}
|
||||
@ -299,6 +306,11 @@ void MapFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
|
||||
GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_));
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("$cached_split_ptr$->$name$_.Destruct();\n");
|
||||
format("$cached_split_ptr$->$name$_.~MapField$lite$();\n");
|
||||
return;
|
||||
}
|
||||
format("$field$.Destruct();\n");
|
||||
format("$field$.~MapField$lite$();\n");
|
||||
}
|
||||
|
@ -346,10 +346,10 @@ bool IsRequired(const std::vector<const FieldDescriptor*>& v) {
|
||||
return v.front()->is_required();
|
||||
}
|
||||
|
||||
bool HasSingularString(const Descriptor* desc, const Options& options) {
|
||||
bool HasNonSplitOptionalString(const Descriptor* desc, const Options& options) {
|
||||
for (const auto* field : FieldRange(desc)) {
|
||||
if (IsString(field, options) && !field->is_repeated() &&
|
||||
!field->real_containing_oneof()) {
|
||||
!field->real_containing_oneof() && !ShouldSplit(field, options)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1202,6 +1202,9 @@ void MessageGenerator::GenerateFieldClear(const FieldDescriptor* field,
|
||||
format.Outdent();
|
||||
format("}\n");
|
||||
} else {
|
||||
if (ShouldSplit(field, options_)) {
|
||||
format("if (IsSplitMessageDefault()) return;\n");
|
||||
}
|
||||
field_generators_.get(field).GenerateClearingCode(format.printer());
|
||||
if (HasHasbit(field)) {
|
||||
int has_bit_index = HasBitIndex(field);
|
||||
@ -1242,13 +1245,12 @@ void MessageGenerator::GenerateFieldAccessorDefinitions(io::Printer* printer) {
|
||||
} else {
|
||||
format(
|
||||
"inline int $classname$::_internal_$name$_size() const {\n"
|
||||
" return $1$$2$.size();\n"
|
||||
" return $field$$1$.size();\n"
|
||||
"}\n"
|
||||
"inline int $classname$::$name$_size() const {\n"
|
||||
"$annotate_size$"
|
||||
" return _internal_$name$_size();\n"
|
||||
"}\n",
|
||||
FieldMemberName(field),
|
||||
IsImplicitWeakField(field, options_, scc_analyzer_) &&
|
||||
field->message_type()
|
||||
? ".weak"
|
||||
@ -1752,6 +1754,17 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) {
|
||||
"\n");
|
||||
}
|
||||
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format(
|
||||
"private:\n"
|
||||
"inline bool IsSplitMessageDefault() const {\n"
|
||||
" return $split$ == reinterpret_cast<Impl_::Split*>(&$1$);\n"
|
||||
"}\n"
|
||||
"PROTOBUF_NOINLINE void PrepareSplitMessageForWrite();\n"
|
||||
"public:\n",
|
||||
DefaultInstanceName(descriptor_, options_, /*split=*/true));
|
||||
}
|
||||
|
||||
format(
|
||||
"// nested types ----------------------------------------------------\n"
|
||||
"\n");
|
||||
@ -1896,7 +1909,24 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) {
|
||||
for (auto field : optimized_order_) {
|
||||
const FieldGenerator& generator = field_generators_.get(field);
|
||||
generator.GenerateStaticMembers(printer);
|
||||
generator.GeneratePrivateMembers(printer);
|
||||
if (!ShouldSplit(field, options_)) {
|
||||
generator.GeneratePrivateMembers(printer);
|
||||
}
|
||||
}
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("struct Split {\n");
|
||||
format.Indent();
|
||||
for (auto field : optimized_order_) {
|
||||
if (!ShouldSplit(field, options_)) continue;
|
||||
const FieldGenerator& generator = field_generators_.get(field);
|
||||
generator.GeneratePrivateMembers(printer);
|
||||
}
|
||||
format.Outdent();
|
||||
format(
|
||||
" typedef void InternalArenaConstructable_;\n"
|
||||
" typedef void DestructorSkippable_;\n"
|
||||
"};\n"
|
||||
"Split* _split_;\n");
|
||||
}
|
||||
|
||||
// For each oneof generate a union
|
||||
@ -1955,6 +1985,14 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) {
|
||||
format("union { Impl_ _impl_; };\n");
|
||||
}
|
||||
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format(
|
||||
"static Impl_::Split* CreateSplitMessage("
|
||||
"::$proto_ns$::Arena* arena);\n");
|
||||
format("friend struct $1$;\n",
|
||||
DefaultInstanceType(descriptor_, options_, /*split=*/true));
|
||||
}
|
||||
|
||||
// The TableStruct struct needs access to the private parts, in order to
|
||||
// construct the offsets of all members.
|
||||
format("friend struct ::$tablename$;\n");
|
||||
@ -2094,7 +2132,8 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) {
|
||||
format("};\n\n");
|
||||
for (auto field : FieldRange(descriptor_)) {
|
||||
if (!IsFieldStripped(field, options_)) {
|
||||
field_generators_.get(field).GenerateInternalAccessorDefinitions(printer);
|
||||
field_generators_.get(field).GenerateInternalAccessorDefinitions(
|
||||
printer);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2154,6 +2193,15 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) {
|
||||
format("\n");
|
||||
}
|
||||
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format(
|
||||
"void $classname$::PrepareSplitMessageForWrite() {\n"
|
||||
" if (IsSplitMessageDefault()) {\n"
|
||||
" $split$ = CreateSplitMessage(GetArenaForAllocation());\n"
|
||||
" }\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
GenerateVerify(printer);
|
||||
|
||||
GenerateSwap(printer);
|
||||
@ -2242,7 +2290,11 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets(
|
||||
// Don't use the top bit because that is for unused fields.
|
||||
format("::_pbi::kInvalidFieldOffsetTag");
|
||||
} else {
|
||||
format("PROTOBUF_FIELD_OFFSET($classtype$, $1$)", FieldMemberName(field));
|
||||
format("PROTOBUF_FIELD_OFFSET($classtype$$1$, $2$)",
|
||||
ShouldSplit(field, options_) ? "::Impl_::Split" : "",
|
||||
ShouldSplit(field, options_)
|
||||
? FieldName(field) + "_"
|
||||
: FieldMemberName(field, /*cold=*/false));
|
||||
}
|
||||
|
||||
// Some information about a field is in the pdproto profile. The profile is
|
||||
@ -2338,9 +2390,17 @@ void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) {
|
||||
// Initialize member variables with arena constructor.
|
||||
for (auto field : optimized_order_) {
|
||||
GOOGLE_DCHECK(!IsFieldStripped(field, options_));
|
||||
if (ShouldSplit(field, options_)) {
|
||||
continue;
|
||||
}
|
||||
put_sep();
|
||||
field_generators_.get(field).GenerateAggregateInitializer(printer);
|
||||
}
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
put_sep();
|
||||
format("decltype($split$){reinterpret_cast<Impl_::Split*>(&$1$)}",
|
||||
DefaultInstanceName(descriptor_, options_, /*split=*/true));
|
||||
}
|
||||
for (auto oneof : OneOfRange(descriptor_)) {
|
||||
put_sep();
|
||||
format("decltype(_impl_.$1$_){}", oneof->name());
|
||||
@ -2394,6 +2454,9 @@ void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) {
|
||||
}
|
||||
|
||||
for (const FieldDescriptor* field : optimized_order_) {
|
||||
if (ShouldSplit(field, options_)) {
|
||||
continue;
|
||||
}
|
||||
field_generators_.get(field).GenerateConstructorCode(printer);
|
||||
}
|
||||
|
||||
@ -2405,6 +2468,63 @@ void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) {
|
||||
format("}\n\n");
|
||||
}
|
||||
|
||||
void MessageGenerator::GenerateCreateSplitMessage(io::Printer* printer) {
|
||||
Formatter format(printer, variables_);
|
||||
format(
|
||||
"$classname$::Impl_::Split* "
|
||||
"$classname$::CreateSplitMessage(::$proto_ns$::Arena* arena) {\n");
|
||||
format.Indent();
|
||||
const char* field_sep = " ";
|
||||
const auto put_sep = [&] {
|
||||
format("\n$1$ ", field_sep);
|
||||
field_sep = ",";
|
||||
};
|
||||
format(
|
||||
"const size_t size = sizeof(Impl_::Split);\n"
|
||||
"void* chunk = (arena == nullptr) ?\n"
|
||||
" ::operator new(size) :\n"
|
||||
" arena->AllocateAligned(size, alignof(Impl_::Split));\n"
|
||||
"Impl_::Split* ptr = reinterpret_cast<Impl_::Split*>(chunk);\n"
|
||||
"new (ptr) Impl_::Split{");
|
||||
format.Indent();
|
||||
for (const FieldDescriptor* field : optimized_order_) {
|
||||
GOOGLE_DCHECK(!IsFieldStripped(field, options_));
|
||||
if (ShouldSplit(field, options_)) {
|
||||
put_sep();
|
||||
field_generators_.get(field).GenerateAggregateInitializer(printer);
|
||||
}
|
||||
}
|
||||
format.Outdent();
|
||||
format("};\n");
|
||||
for (const FieldDescriptor* field : optimized_order_) {
|
||||
GOOGLE_DCHECK(!IsFieldStripped(field, options_));
|
||||
if (ShouldSplit(field, options_)) {
|
||||
field_generators_.get(field).GenerateCreateSplitMessageCode(printer);
|
||||
}
|
||||
}
|
||||
format("return ptr;\n");
|
||||
format.Outdent();
|
||||
format("}\n");
|
||||
}
|
||||
|
||||
void MessageGenerator::GenerateInitDefaultSplitInstance(io::Printer* printer) {
|
||||
if (!ShouldSplit(descriptor_, options_)) return;
|
||||
|
||||
Formatter format(printer, variables_);
|
||||
const char* field_sep = " ";
|
||||
const auto put_sep = [&] {
|
||||
format("\n$1$ ", field_sep);
|
||||
field_sep = ",";
|
||||
};
|
||||
for (const auto* field : optimized_order_) {
|
||||
if (ShouldSplit(field, options_)) {
|
||||
put_sep();
|
||||
field_generators_.get(field).GenerateConstexprAggregateInitializer(
|
||||
printer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) {
|
||||
if (HasSimpleBaseClass(descriptor_, options_)) return;
|
||||
Formatter format(printer, variables_);
|
||||
@ -2420,8 +2540,24 @@ void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) {
|
||||
// Write the destructors for each field except oneof members.
|
||||
// optimized_order_ does not contain oneof fields.
|
||||
for (auto field : optimized_order_) {
|
||||
if (ShouldSplit(field, options_)) {
|
||||
continue;
|
||||
}
|
||||
field_generators_.get(field).GenerateDestructorCode(printer);
|
||||
}
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("if (!IsSplitMessageDefault()) {\n");
|
||||
format.Indent();
|
||||
format("auto* $cached_split_ptr$ = $split$;\n");
|
||||
for (auto field : optimized_order_) {
|
||||
if (ShouldSplit(field, options_)) {
|
||||
field_generators_.get(field).GenerateDestructorCode(printer);
|
||||
}
|
||||
}
|
||||
format("delete $cached_split_ptr$;\n");
|
||||
format.Outdent();
|
||||
format("}\n");
|
||||
}
|
||||
|
||||
// Generate code to destruct oneofs. Clearing should do the work.
|
||||
for (auto oneof : OneOfRange(descriptor_)) {
|
||||
@ -2475,10 +2611,23 @@ void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) {
|
||||
|
||||
// Process non-oneof fields first.
|
||||
for (auto field : optimized_order_) {
|
||||
if (IsFieldStripped(field, options_)) continue;
|
||||
if (IsFieldStripped(field, options_) || ShouldSplit(field, options_))
|
||||
continue;
|
||||
const FieldGenerator& fg = field_generators_.get(field);
|
||||
fg.GenerateArenaDestructorCode(printer);
|
||||
}
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("if (!_this->IsSplitMessageDefault()) {\n");
|
||||
format.Indent();
|
||||
for (auto field : optimized_order_) {
|
||||
if (IsFieldStripped(field, options_) || !ShouldSplit(field, options_))
|
||||
continue;
|
||||
const FieldGenerator& fg = field_generators_.get(field);
|
||||
fg.GenerateArenaDestructorCode(printer);
|
||||
}
|
||||
format.Outdent();
|
||||
format("}\n");
|
||||
}
|
||||
|
||||
// Process oneof fields.
|
||||
for (auto oneof : OneOfRange(descriptor_)) {
|
||||
@ -2532,9 +2681,19 @@ void MessageGenerator::GenerateConstexprConstructor(io::Printer* printer) {
|
||||
}
|
||||
}
|
||||
for (auto field : optimized_order_) {
|
||||
if (ShouldSplit(field, options_)) {
|
||||
continue;
|
||||
}
|
||||
put_sep();
|
||||
field_generators_.get(field).GenerateConstexprAggregateInitializer(printer);
|
||||
field_generators_.get(field).GenerateConstexprAggregateInitializer(
|
||||
printer);
|
||||
}
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
put_sep();
|
||||
format("/*decltype($split$)*/&$1$._instance",
|
||||
DefaultInstanceName(descriptor_, options_, /*split=*/true));
|
||||
}
|
||||
|
||||
for (auto oneof : OneOfRange(descriptor_)) {
|
||||
put_sep();
|
||||
format("/*decltype(_impl_.$1$_)*/{}", oneof->name());
|
||||
@ -2570,16 +2729,33 @@ void MessageGenerator::GenerateCopyConstructorBody(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
|
||||
const RunMap runs =
|
||||
FindRuns(optimized_order_,
|
||||
[](const FieldDescriptor* field) { return IsPOD(field); });
|
||||
FindRuns(optimized_order_, [this](const FieldDescriptor* field) {
|
||||
return IsPOD(field) && !ShouldSplit(field, options_);
|
||||
});
|
||||
|
||||
std::string pod_template =
|
||||
"::memcpy(&$first$, &from.$first$,\n"
|
||||
" static_cast<size_t>(reinterpret_cast<char*>(&$last$) -\n"
|
||||
" reinterpret_cast<char*>(&$first$)) + sizeof($last$));\n";
|
||||
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("if (!from.IsSplitMessageDefault()) {\n");
|
||||
format.Indent();
|
||||
format("_this->PrepareSplitMessageForWrite();\n");
|
||||
for (auto field : optimized_order_) {
|
||||
if (ShouldSplit(field, options_)) {
|
||||
field_generators_.get(field).GenerateCopyConstructorCode(printer);
|
||||
}
|
||||
}
|
||||
format.Outdent();
|
||||
format("}\n");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < optimized_order_.size(); ++i) {
|
||||
const FieldDescriptor* field = optimized_order_[i];
|
||||
if (ShouldSplit(field, options_)) {
|
||||
continue;
|
||||
}
|
||||
const auto it = runs.find(field);
|
||||
|
||||
// We only apply the memset technique to runs of more than one field, as
|
||||
@ -2587,9 +2763,10 @@ void MessageGenerator::GenerateCopyConstructorBody(io::Printer* printer) const {
|
||||
if (it != runs.end() && it->second > 1) {
|
||||
// Use a memset, then skip run_length fields.
|
||||
const size_t run_length = it->second;
|
||||
const std::string first_field_name = FieldMemberName(field);
|
||||
const std::string first_field_name =
|
||||
FieldMemberName(field, /*cold=*/false);
|
||||
const std::string last_field_name =
|
||||
FieldMemberName(optimized_order_[i + run_length - 1]);
|
||||
FieldMemberName(optimized_order_[i + run_length - 1], /*cold=*/false);
|
||||
|
||||
format.Set("first", first_field_name);
|
||||
format.Set("last", last_field_name);
|
||||
@ -2682,9 +2859,17 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) {
|
||||
|
||||
// Initialize member variables with arena constructor.
|
||||
for (auto field : optimized_order_) {
|
||||
if (ShouldSplit(field, options_)) {
|
||||
continue;
|
||||
}
|
||||
put_sep();
|
||||
field_generators_.get(field).GenerateCopyAggregateInitializer(printer);
|
||||
}
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
put_sep();
|
||||
format("decltype($split$){reinterpret_cast<Impl_::Split*>(&$1$)}",
|
||||
DefaultInstanceName(descriptor_, options_, /*split=*/true));
|
||||
}
|
||||
for (auto oneof : OneOfRange(descriptor_)) {
|
||||
put_sep();
|
||||
format("decltype(_impl_.$1$_){}", oneof->name());
|
||||
@ -2760,6 +2945,10 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) {
|
||||
// Generate the shared constructor code.
|
||||
GenerateSharedConstructorCode(printer);
|
||||
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
GenerateCreateSplitMessage(printer);
|
||||
}
|
||||
|
||||
// Generate the destructor.
|
||||
if (!HasSimpleBaseClass(descriptor_, options_)) {
|
||||
format(
|
||||
@ -2857,6 +3046,7 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
|
||||
// (memset) per chunk, and if present it will be at the beginning.
|
||||
bool same = HasByteIndex(a) == HasByteIndex(b) &&
|
||||
a->is_repeated() == b->is_repeated() &&
|
||||
ShouldSplit(a, options_) == ShouldSplit(b, options_) &&
|
||||
(CanInitializeByZeroing(a) == CanInitializeByZeroing(b) ||
|
||||
(CanInitializeByZeroing(a) &&
|
||||
(chunk_count == 1 || merge_zero_init)));
|
||||
@ -2875,7 +3065,7 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
|
||||
const FieldDescriptor* memset_start = nullptr;
|
||||
const FieldDescriptor* memset_end = nullptr;
|
||||
bool saw_non_zero_init = false;
|
||||
|
||||
bool chunk_is_cold = !chunk.empty() && ShouldSplit(chunk.front(), options_);
|
||||
for (const auto& field : chunk) {
|
||||
if (CanInitializeByZeroing(field)) {
|
||||
GOOGLE_CHECK(!saw_non_zero_init);
|
||||
@ -2915,17 +3105,25 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
|
||||
format.Indent();
|
||||
}
|
||||
|
||||
if (chunk_is_cold) {
|
||||
format("if (!IsSplitMessageDefault()) {\n");
|
||||
format.Indent();
|
||||
}
|
||||
|
||||
if (memset_start) {
|
||||
if (memset_start == memset_end) {
|
||||
// For clarity, do not memset a single field.
|
||||
field_generators_.get(memset_start)
|
||||
.GenerateMessageClearingCode(printer);
|
||||
} else {
|
||||
GOOGLE_CHECK_EQ(chunk_is_cold, ShouldSplit(memset_start, options_));
|
||||
GOOGLE_CHECK_EQ(chunk_is_cold, ShouldSplit(memset_end, options_));
|
||||
format(
|
||||
"::memset(&$1$, 0, static_cast<size_t>(\n"
|
||||
" reinterpret_cast<char*>(&$2$) -\n"
|
||||
" reinterpret_cast<char*>(&$1$)) + sizeof($2$));\n",
|
||||
FieldMemberName(memset_start), FieldMemberName(memset_end));
|
||||
FieldMemberName(memset_start, chunk_is_cold),
|
||||
FieldMemberName(memset_end, chunk_is_cold));
|
||||
}
|
||||
}
|
||||
|
||||
@ -2954,6 +3152,11 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
|
||||
}
|
||||
}
|
||||
|
||||
if (chunk_is_cold) {
|
||||
format.Outdent();
|
||||
format("}\n");
|
||||
}
|
||||
|
||||
if (have_outer_if) {
|
||||
format.Outdent();
|
||||
format("}\n");
|
||||
@ -3052,7 +3255,7 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) {
|
||||
std::map<std::string, std::string> vars;
|
||||
SetUnknownFieldsVariable(descriptor_, options_, &vars);
|
||||
format.AddMap(vars);
|
||||
if (HasSingularString(descriptor_, options_)) {
|
||||
if (HasNonSplitOptionalString(descriptor_, options_)) {
|
||||
format(
|
||||
"auto* lhs_arena = GetArenaForAllocation();\n"
|
||||
"auto* rhs_arena = other->GetArenaForAllocation();\n");
|
||||
@ -3068,11 +3271,15 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) {
|
||||
// If possible, we swap several fields at once, including padding.
|
||||
const RunMap runs =
|
||||
FindRuns(optimized_order_, [this](const FieldDescriptor* field) {
|
||||
return CanBeManipulatedAsRawBytes(field, options_, scc_analyzer_);
|
||||
return !ShouldSplit(field, options_) &&
|
||||
CanBeManipulatedAsRawBytes(field, options_, scc_analyzer_);
|
||||
});
|
||||
|
||||
for (int i = 0; i < optimized_order_.size(); ++i) {
|
||||
for (size_t i = 0; i < optimized_order_.size(); ++i) {
|
||||
const FieldDescriptor* field = optimized_order_[i];
|
||||
if (ShouldSplit(field, options_)) {
|
||||
continue;
|
||||
}
|
||||
const auto it = runs.find(field);
|
||||
|
||||
// We only apply the memswap technique to runs of more than one field, as
|
||||
@ -3081,9 +3288,10 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) {
|
||||
if (it != runs.end() && it->second > 1) {
|
||||
// Use a memswap, then skip run_length fields.
|
||||
const size_t run_length = it->second;
|
||||
const std::string first_field_name = FieldMemberName(field);
|
||||
const std::string last_field_name =
|
||||
FieldMemberName(optimized_order_[i + run_length - 1]);
|
||||
const std::string first_field_name =
|
||||
FieldMemberName(field, /*cold=*/false);
|
||||
const std::string last_field_name = FieldMemberName(
|
||||
optimized_order_[i + run_length - 1], /*cold=*/false);
|
||||
|
||||
format.Set("first", first_field_name);
|
||||
format.Set("last", last_field_name);
|
||||
@ -3102,6 +3310,9 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) {
|
||||
field_generators_.get(field).GenerateSwappingCode(printer);
|
||||
}
|
||||
}
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("swap($split$, other->$split$);\n");
|
||||
}
|
||||
|
||||
for (auto oneof : OneOfRange(descriptor_)) {
|
||||
format("swap(_impl_.$1$_, other->_impl_.$1$_);\n", oneof->name());
|
||||
@ -3208,10 +3419,18 @@ void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) {
|
||||
"$uint32$ cached_has_bits = 0;\n"
|
||||
"(void) cached_has_bits;\n\n");
|
||||
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format(
|
||||
"if (!from.IsSplitMessageDefault()) {\n"
|
||||
" _this->PrepareSplitMessageForWrite();\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
std::vector<std::vector<const FieldDescriptor*>> chunks = CollectFields(
|
||||
optimized_order_,
|
||||
[&](const FieldDescriptor* a, const FieldDescriptor* b) -> bool {
|
||||
return HasByteIndex(a) == HasByteIndex(b);
|
||||
return HasByteIndex(a) == HasByteIndex(b) &&
|
||||
ShouldSplit(a, options_) == ShouldSplit(b, options_);
|
||||
});
|
||||
|
||||
ColdChunkSkipper cold_skipper(descriptor_, options_, chunks, has_bit_indices_,
|
||||
@ -3999,7 +4218,8 @@ void MessageGenerator::GenerateByteSize(io::Printer* printer) {
|
||||
std::vector<std::vector<const FieldDescriptor*>> chunks = CollectFields(
|
||||
optimized_order_,
|
||||
[&](const FieldDescriptor* a, const FieldDescriptor* b) -> bool {
|
||||
return a->label() == b->label() && HasByteIndex(a) == HasByteIndex(b);
|
||||
return a->label() == b->label() && HasByteIndex(a) == HasByteIndex(b) &&
|
||||
ShouldSplit(a, options_) == ShouldSplit(b, options_);
|
||||
});
|
||||
|
||||
// Remove chunks with required fields.
|
||||
|
@ -119,6 +119,9 @@ class MessageGenerator {
|
||||
// default instance.
|
||||
void GenerateConstexprConstructor(io::Printer* printer);
|
||||
|
||||
void GenerateCreateSplitMessage(io::Printer* printer);
|
||||
void GenerateInitDefaultSplitInstance(io::Printer* printer);
|
||||
|
||||
// Generate standard Message methods.
|
||||
void GenerateClear(io::Printer* printer);
|
||||
void GenerateOneofClear(io::Printer* printer);
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <google/protobuf/compiler/cpp/message_field.h>
|
||||
|
||||
#include <google/protobuf/io/printer.h>
|
||||
#include <google/protobuf/compiler/cpp/field.h>
|
||||
#include <google/protobuf/compiler/cpp/helpers.h>
|
||||
|
||||
#include <google/protobuf/stubs/strutil.h>
|
||||
@ -178,6 +179,7 @@ void MessageFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
format(
|
||||
"inline void $classname$::unsafe_arena_set_allocated_$name$(\n"
|
||||
" $type$* $name$) {\n"
|
||||
"$maybe_prepare_split_message$"
|
||||
// If we're not on an arena, free whatever we were holding before.
|
||||
// (If we are on arena, we can just forget the earlier pointer.)
|
||||
" if (GetArenaForAllocation() == nullptr) {\n"
|
||||
@ -203,6 +205,7 @@ void MessageFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
"inline $type$* $classname$::$release_name$() {\n"
|
||||
"$type_reference_function$"
|
||||
"$annotate_release$"
|
||||
"$maybe_prepare_split_message$"
|
||||
" $clear_hasbit$\n"
|
||||
" $type$* temp = $casted_member$;\n"
|
||||
" $field$ = nullptr;\n"
|
||||
@ -221,6 +224,7 @@ void MessageFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
"$annotate_release$"
|
||||
" // @@protoc_insertion_point(field_release:$full_name$)\n"
|
||||
"$type_reference_function$"
|
||||
"$maybe_prepare_split_message$"
|
||||
" $clear_hasbit$\n"
|
||||
" $type$* temp = $casted_member$;\n"
|
||||
" $field$ = nullptr;\n"
|
||||
@ -243,6 +247,9 @@ void MessageFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
" return $casted_member$;\n"
|
||||
"}\n"
|
||||
"inline $type$* $classname$::mutable_$name$() {\n"
|
||||
// TODO(b/122856539): add tests to make sure all write accessors are able
|
||||
// to prepare split message allocation.
|
||||
"$maybe_prepare_split_message$"
|
||||
" $type$* _msg = _internal_mutable_$name$();\n"
|
||||
"$annotate_mutable$"
|
||||
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
|
||||
@ -254,7 +261,9 @@ void MessageFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
format(
|
||||
"inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
|
||||
" ::$proto_ns$::Arena* message_arena = GetArenaForAllocation();\n");
|
||||
format(" if (message_arena == nullptr) {\n");
|
||||
format(
|
||||
"$maybe_prepare_split_message$"
|
||||
" if (message_arena == nullptr) {\n");
|
||||
if (IsCrossFileMessage(descriptor_)) {
|
||||
format(
|
||||
" delete reinterpret_cast< ::$proto_ns$::MessageLite*>($field$);\n");
|
||||
@ -434,6 +443,10 @@ void MessageFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
|
||||
// care when handling them.
|
||||
format("if (this != internal_default_instance()) ");
|
||||
}
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("delete $cached_split_ptr$->$name$_;\n");
|
||||
return;
|
||||
}
|
||||
format("delete $field$;\n");
|
||||
}
|
||||
|
||||
@ -504,6 +517,10 @@ void MessageFieldGenerator::GenerateCopyAggregateInitializer(
|
||||
void MessageFieldGenerator::GenerateAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("decltype(Impl_::Split::$name$_){nullptr}");
|
||||
return;
|
||||
}
|
||||
format("decltype($field$){nullptr}");
|
||||
}
|
||||
|
||||
|
@ -899,11 +899,14 @@ void ParseFunctionGenerator::GenerateFastFieldEntries(Formatter& format) {
|
||||
if (info.func_name.empty()) {
|
||||
format("{::_pbi::TcParser::MiniParse, {}},\n");
|
||||
} else {
|
||||
bool cold = ShouldSplit(info.field, options_);
|
||||
format(
|
||||
"{$1$,\n"
|
||||
" {$2$, $3$, $4$, PROTOBUF_FIELD_OFFSET($classname$, $5$)}},\n",
|
||||
" {$2$, $3$, $4$, PROTOBUF_FIELD_OFFSET($classname$$5$, $6$)}},\n",
|
||||
info.func_name, info.coded_tag, info.hasbit_idx, info.aux_idx,
|
||||
FieldMemberName(info.field));
|
||||
cold ? "::Impl_::Split" : "",
|
||||
cold ? FieldName(info.field) + "_"
|
||||
: FieldMemberName(info.field, /*cold=*/false));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1048,8 +1051,11 @@ void ParseFunctionGenerator::GenerateFieldEntries(Formatter& format) {
|
||||
format("/* weak */ 0, 0, 0, 0");
|
||||
} else {
|
||||
const OneofDescriptor* oneof = field->real_containing_oneof();
|
||||
format("PROTOBUF_FIELD_OFFSET($classname$, $1$), $2$, $3$,\n ",
|
||||
FieldMemberName(field),
|
||||
bool cold = ShouldSplit(field, options_);
|
||||
format("PROTOBUF_FIELD_OFFSET($classname$$1$, $2$), $3$, $4$,\n ",
|
||||
cold ? "::Impl_::Split" : "",
|
||||
cold ? FieldName(field) + "_"
|
||||
: FieldMemberName(field, /*cold=*/false),
|
||||
(oneof ? oneof->index() : entry.hasbit_idx), entry.aux_idx);
|
||||
FormatFieldKind(format, entry, options_, scc_analyzer_);
|
||||
}
|
||||
@ -1550,7 +1556,8 @@ void ParseFunctionGenerator::GenerateFieldSwitch(
|
||||
format.Indent();
|
||||
|
||||
for (const auto* field : fields) {
|
||||
format.Set("field", FieldMemberName(field));
|
||||
bool cold = ShouldSplit(field, options_);
|
||||
format.Set("field", FieldMemberName(field, cold));
|
||||
PrintFieldComment(format, field);
|
||||
format("case $1$:\n", field->number());
|
||||
format.Indent();
|
||||
@ -1559,6 +1566,9 @@ void ParseFunctionGenerator::GenerateFieldSwitch(
|
||||
format("if (PROTOBUF_PREDICT_TRUE(static_cast<$uint8$>(tag) == $1$)) {\n",
|
||||
expected_tag & 0xFF);
|
||||
format.Indent();
|
||||
if (cold) {
|
||||
format("$msg$PrepareSplitMessageForWrite();\n");
|
||||
}
|
||||
auto wiretype = WireFormatLite::GetTagWireType(expected_tag);
|
||||
uint32_t tag = WireFormatLite::MakeTag(field->number(), wiretype);
|
||||
int tag_size = io::CodedOutputStream::VarintSize32(tag);
|
||||
|
@ -105,8 +105,9 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
|
||||
(*variables)["type"] = PrimitiveTypeName(options, descriptor->cpp_type());
|
||||
(*variables)["default"] = DefaultValue(options, descriptor);
|
||||
(*variables)["cached_byte_size_name"] = MakeVarintCachedSizeName(descriptor);
|
||||
bool cold = ShouldSplit(descriptor, options);
|
||||
(*variables)["cached_byte_size_field"] =
|
||||
MakeVarintCachedSizeFieldName(descriptor);
|
||||
MakeVarintCachedSizeFieldName(descriptor, cold);
|
||||
(*variables)["tag"] = StrCat(internal::WireFormat::MakeTag(descriptor));
|
||||
int fixed_size = FixedSize(descriptor->type());
|
||||
if (fixed_size != -1) {
|
||||
@ -165,6 +166,7 @@ void PrimitiveFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
" $field$ = value;\n"
|
||||
"}\n"
|
||||
"inline void $classname$::set_$name$($type$ value) {\n"
|
||||
"$maybe_prepare_split_message$"
|
||||
" _internal_set_$name$(value);\n"
|
||||
"$annotate_set$"
|
||||
" // @@protoc_insertion_point(field_set:$full_name$)\n"
|
||||
@ -233,6 +235,10 @@ void PrimitiveFieldGenerator::GenerateConstexprAggregateInitializer(
|
||||
void PrimitiveFieldGenerator::GenerateAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("decltype(Impl_::Split::$name$_){$default$}");
|
||||
return;
|
||||
}
|
||||
format("decltype($field$){$default$}");
|
||||
}
|
||||
|
||||
|
@ -102,7 +102,9 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
|
||||
void GenerateMergingCode(io::Printer* printer) const override;
|
||||
void GenerateSwappingCode(io::Printer* printer) const override;
|
||||
void GenerateConstructorCode(io::Printer* printer) const override {}
|
||||
void GenerateCopyConstructorCode(io::Printer* printer) const override {}
|
||||
void GenerateCopyConstructorCode(io::Printer* /*printer*/) const override {
|
||||
GOOGLE_CHECK(!ShouldSplit(descriptor_, options_));
|
||||
}
|
||||
void GenerateDestructorCode(io::Printer* printer) const override;
|
||||
void GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const override;
|
||||
|
@ -115,11 +115,7 @@ void StringFieldGenerator::GeneratePrivateMembers(io::Printer* printer) const {
|
||||
// allocating arena is null. This is required to support message-owned
|
||||
// arena (go/path-to-arenas) where a root proto is destroyed but
|
||||
// InlinedStringField may have arena-allocated memory.
|
||||
//
|
||||
// `_init_inline_xxx` is used for initializing default instances.
|
||||
format(
|
||||
"::$proto_ns$::internal::InlinedStringField $name$_;\n"
|
||||
"static std::true_type _init_inline_$name$_;\n");
|
||||
format("::$proto_ns$::internal::InlinedStringField $name$_;\n");
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,6 +126,10 @@ void StringFieldGenerator::GenerateStaticMembers(io::Printer* printer) const {
|
||||
"static const ::$proto_ns$::internal::LazyString"
|
||||
" $default_variable_name$;\n");
|
||||
}
|
||||
if (inlined_) {
|
||||
// `_init_inline_xxx` is used for initializing default instances.
|
||||
format("static std::true_type _init_inline_$name$_;\n");
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateAccessorDeclarations(
|
||||
@ -215,6 +215,7 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
"template <typename ArgT0, typename... ArgT>\n"
|
||||
"inline PROTOBUF_ALWAYS_INLINE\n"
|
||||
"void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n"
|
||||
"$maybe_prepare_split_message$"
|
||||
" $set_hasbit$\n"
|
||||
" $field$.$setter$(static_cast<ArgT0 &&>(arg0),"
|
||||
" args..., GetArenaForAllocation());\n"
|
||||
@ -226,6 +227,7 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
"template <typename ArgT0, typename... ArgT>\n"
|
||||
"inline PROTOBUF_ALWAYS_INLINE\n"
|
||||
"void $classname$::set_$name$(ArgT0&& arg0, ArgT... args) {\n"
|
||||
"$maybe_prepare_split_message$"
|
||||
" $set_hasbit$\n"
|
||||
" $field$.$setter$(static_cast<ArgT0 &&>(arg0),"
|
||||
" args..., GetArenaForAllocation(), _internal_$name$_donated(), "
|
||||
@ -240,6 +242,7 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
}
|
||||
format(
|
||||
"inline std::string* $classname$::mutable_$name$() {\n"
|
||||
"$maybe_prepare_split_message$"
|
||||
" std::string* _s = _internal_mutable_$name$();\n"
|
||||
"$annotate_mutable$"
|
||||
" // @@protoc_insertion_point(field_mutable:$full_name$)\n"
|
||||
@ -280,6 +283,7 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
format(
|
||||
"inline std::string* $classname$::$release_name$() {\n"
|
||||
"$annotate_release$"
|
||||
"$maybe_prepare_split_message$"
|
||||
" // @@protoc_insertion_point(field_release:$full_name$)\n");
|
||||
|
||||
if (HasHasbit(descriptor_)) {
|
||||
@ -311,6 +315,7 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions(
|
||||
format(
|
||||
"}\n"
|
||||
"inline void $classname$::set_allocated_$name$(std::string* $name$) {\n"
|
||||
"$maybe_prepare_split_message$"
|
||||
" if ($name$ != nullptr) {\n"
|
||||
" $set_hasbit$\n"
|
||||
" } else {\n"
|
||||
@ -440,6 +445,21 @@ void StringFieldGenerator::GenerateConstructorCode(io::Printer* printer) const {
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateCreateSplitMessageCode(
|
||||
io::Printer* printer) const {
|
||||
GOOGLE_CHECK(ShouldSplit(descriptor_, options_));
|
||||
GOOGLE_CHECK(!inlined_);
|
||||
Formatter format(printer, variables_);
|
||||
format("ptr->$name$_.InitDefault();\n");
|
||||
if (IsString(descriptor_, options_) &&
|
||||
descriptor_->default_value_string().empty()) {
|
||||
format(
|
||||
"#ifdef PROTOBUF_FORCE_COPY_DEFAULT_STRING\n"
|
||||
" ptr->$name$_.Set(\"\", GetArenaForAllocation());\n"
|
||||
"#endif // PROTOBUF_FORCE_COPY_DEFAULT_STRING\n");
|
||||
}
|
||||
}
|
||||
|
||||
void StringFieldGenerator::GenerateCopyConstructorCode(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
@ -474,6 +494,10 @@ void StringFieldGenerator::GenerateCopyConstructorCode(
|
||||
void StringFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (!inlined_) {
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
format("$cached_split_ptr$->$name$_.Destroy();\n");
|
||||
return;
|
||||
}
|
||||
format("$field$.Destroy();\n");
|
||||
return;
|
||||
}
|
||||
@ -481,6 +505,7 @@ void StringFieldGenerator::GenerateDestructorCode(io::Printer* printer) const {
|
||||
// Destructor has been implicitly skipped as a union, and even the
|
||||
// message-owned arena is enabled, arena could still be missing for
|
||||
// Arena::CreateMessage(nullptr).
|
||||
GOOGLE_DCHECK(!ShouldSplit(descriptor_, options_));
|
||||
format("$field$.~InlinedStringField();\n");
|
||||
}
|
||||
|
||||
@ -541,6 +566,11 @@ void StringFieldGenerator::GenerateConstexprAggregateInitializer(
|
||||
void StringFieldGenerator::GenerateAggregateInitializer(
|
||||
io::Printer* printer) const {
|
||||
Formatter format(printer, variables_);
|
||||
if (ShouldSplit(descriptor_, options_)) {
|
||||
GOOGLE_CHECK(!inlined_);
|
||||
format("decltype(Impl_::Split::$name$_){}");
|
||||
return;
|
||||
}
|
||||
if (!inlined_) {
|
||||
format("decltype($field$){}");
|
||||
} else {
|
||||
|
@ -63,6 +63,7 @@ class StringFieldGenerator : public FieldGenerator {
|
||||
void GenerateMergingCode(io::Printer* printer) const override;
|
||||
void GenerateSwappingCode(io::Printer* printer) const override;
|
||||
void GenerateConstructorCode(io::Printer* printer) const override;
|
||||
void GenerateCreateSplitMessageCode(io::Printer* printer) const override;
|
||||
void GenerateCopyConstructorCode(io::Printer* printer) const override;
|
||||
void GenerateDestructorCode(io::Printer* printer) const override;
|
||||
void GenerateArenaDestructorCode(io::Printer* printer) const override;
|
||||
@ -115,7 +116,9 @@ class RepeatedStringFieldGenerator : public FieldGenerator {
|
||||
void GenerateMergingCode(io::Printer* printer) const override;
|
||||
void GenerateSwappingCode(io::Printer* printer) const override;
|
||||
void GenerateConstructorCode(io::Printer* printer) const override {}
|
||||
void GenerateCopyConstructorCode(io::Printer* printer) const override {}
|
||||
void GenerateCopyConstructorCode(io::Printer* /*printer*/) const override {
|
||||
GOOGLE_CHECK(!ShouldSplit(descriptor_, options_));
|
||||
}
|
||||
void GenerateDestructorCode(io::Printer* printer) const override;
|
||||
void GenerateSerializeWithCachedSizesToArray(
|
||||
io::Printer* printer) const override;
|
||||
|
@ -1286,4 +1286,133 @@ message TestExtensionRangeSerialize {
|
||||
}
|
||||
}
|
||||
|
||||
message TestVerifyInt32Simple {
|
||||
optional int32 optional_int32_1 = 1;
|
||||
optional int32 optional_int32_2 = 2;
|
||||
optional int32 optional_int32_63 = 63;
|
||||
optional int32 optional_int32_64 = 64;
|
||||
}
|
||||
|
||||
message TestVerifyInt32 {
|
||||
optional int32 optional_int32_1 = 1;
|
||||
optional int32 optional_int32_2 = 2;
|
||||
optional int32 optional_int32_63 = 63;
|
||||
optional int32 optional_int32_64 = 64;
|
||||
|
||||
optional TestAllTypes optional_all_types = 9;
|
||||
repeated TestAllTypes repeated_all_types = 10;
|
||||
}
|
||||
|
||||
message TestVerifyMostlyInt32 {
|
||||
optional int64 optional_int64_30 = 30;
|
||||
|
||||
optional int32 optional_int32_1 = 1;
|
||||
optional int32 optional_int32_2 = 2;
|
||||
optional int32 optional_int32_3 = 3;
|
||||
optional int32 optional_int32_4 = 4;
|
||||
optional int32 optional_int32_63 = 63;
|
||||
optional int32 optional_int32_64 = 64;
|
||||
|
||||
optional TestAllTypes optional_all_types = 9;
|
||||
repeated TestAllTypes repeated_all_types = 10;
|
||||
}
|
||||
|
||||
message TestVerifyMostlyInt32BigFieldNumber {
|
||||
optional int64 optional_int64_30 = 30;
|
||||
optional int32 optional_int32_300 = 300;
|
||||
|
||||
optional int32 optional_int32_1 = 1;
|
||||
optional int32 optional_int32_2 = 2;
|
||||
optional int32 optional_int32_3 = 3;
|
||||
optional int32 optional_int32_4 = 4;
|
||||
optional int32 optional_int32_63 = 63;
|
||||
optional int32 optional_int32_64 = 64;
|
||||
|
||||
optional TestAllTypes optional_all_types = 9;
|
||||
repeated TestAllTypes repeated_all_types = 10;
|
||||
}
|
||||
|
||||
message TestVerifyUint32Simple {
|
||||
optional uint32 optional_uint32_1 = 1;
|
||||
optional uint32 optional_uint32_2 = 2;
|
||||
optional uint32 optional_uint32_63 = 63;
|
||||
optional uint32 optional_uint32_64 = 64;
|
||||
}
|
||||
|
||||
message TestVerifyUint32 {
|
||||
optional uint32 optional_uint32_1 = 1;
|
||||
optional uint32 optional_uint32_2 = 2;
|
||||
optional uint32 optional_uint32_63 = 63;
|
||||
optional uint32 optional_uint32_64 = 64;
|
||||
|
||||
optional TestAllTypes optional_all_types = 9;
|
||||
repeated TestAllTypes repeated_all_types = 10;
|
||||
}
|
||||
|
||||
message TestVerifyOneUint32 {
|
||||
optional uint32 optional_uint32_1 = 1;
|
||||
optional int32 optional_int32_2 = 2;
|
||||
optional int32 optional_int32_63 = 63;
|
||||
optional int32 optional_int32_64 = 64;
|
||||
|
||||
optional TestAllTypes optional_all_types = 9;
|
||||
repeated TestAllTypes repeated_all_types = 10;
|
||||
}
|
||||
|
||||
message TestVerifyOneInt32BigFieldNumber {
|
||||
optional int32 optional_int32_65 = 65;
|
||||
|
||||
optional int64 optional_int64_1 = 1;
|
||||
optional int64 optional_int64_2 = 2;
|
||||
optional int64 optional_int64_63 = 63;
|
||||
optional int64 optional_int64_64 = 64;
|
||||
|
||||
optional TestAllTypes optional_all_types = 9;
|
||||
repeated TestAllTypes repeated_all_types = 10;
|
||||
}
|
||||
|
||||
message TestVerifyInt32BigFieldNumber {
|
||||
optional int32 optional_int32_1000 = 1000;
|
||||
optional int32 optional_int32_65 = 65;
|
||||
|
||||
optional int32 optional_int32_1 = 1;
|
||||
optional int32 optional_int32_2 = 2;
|
||||
optional int32 optional_int32_63 = 63;
|
||||
optional int32 optional_int32_64 = 64;
|
||||
|
||||
optional TestAllTypes optional_all_types = 9;
|
||||
repeated TestAllTypes repeated_all_types = 10;
|
||||
}
|
||||
|
||||
message TestVerifyUint32BigFieldNumber {
|
||||
optional uint32 optional_uint32_1000 = 1000;
|
||||
optional uint32 optional_uint32_65 = 65;
|
||||
|
||||
optional uint32 optional_uint32_1 = 1;
|
||||
optional uint32 optional_uint32_2 = 2;
|
||||
optional uint32 optional_uint32_63 = 63;
|
||||
optional uint32 optional_uint32_64 = 64;
|
||||
|
||||
optional TestAllTypes optional_all_types = 9;
|
||||
repeated TestAllTypes repeated_all_types = 10;
|
||||
}
|
||||
|
||||
message TestVerifyBigFieldNumberUint32 {
|
||||
message Nested {
|
||||
optional uint32 optional_uint32_5000 = 5000;
|
||||
optional uint32 optional_uint32_1000 = 1000;
|
||||
optional uint32 optional_uint32_66 = 66;
|
||||
optional uint32 optional_uint32_65 = 65;
|
||||
|
||||
optional uint32 optional_uint32_1 = 1;
|
||||
optional uint32 optional_uint32_2 = 2;
|
||||
optional uint32 optional_uint32_63 = 63;
|
||||
optional uint32 optional_uint32_64 = 64;
|
||||
|
||||
optional Nested optional_nested = 9;
|
||||
repeated Nested repeated_nested = 10;
|
||||
}
|
||||
optional Nested optional_nested = 1;
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user