diff options
author | mikhnenko <[email protected]> | 2024-06-30 20:16:52 +0300 |
---|---|---|
committer | mikhnenko <[email protected]> | 2024-06-30 20:28:14 +0300 |
commit | b91a38fe11269c505fec071351a68e568768e6e8 (patch) | |
tree | 07d43bf92eee00e2fce98bdbf698f135386995c1 /contrib/libs/protoc/src/google/protobuf/compiler/cpp | |
parent | b21e05a2e32e36ae9cc9826acf98084ca4b52d7d (diff) |
Update protobuf to 3.21.2
a628f0376085fcf46dc6d24629f2a7dacb91ae79
Diffstat (limited to 'contrib/libs/protoc/src/google/protobuf/compiler/cpp')
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.h | 1027 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum.cc (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum.cc) | 6 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum.h (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum.h) | 2 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum_field.cc (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.cc) | 75 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum_field.h (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.h) | 19 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/extension.cc (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.cc) | 6 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/extension.h (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.h) | 2 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/field.cc (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.cc) | 58 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/field.h (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.h) | 39 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/file.cc (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.cc) | 83 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/file.h (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.h) | 6 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/generator.cc (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.cc) | 14 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/generator.h (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.h) | 0 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/helpers.cc (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.cc) | 140 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/helpers.h | 1065 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/map_field.cc (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_map_field.cc) | 43 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/map_field.h (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_map_field.h) | 9 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/message.cc (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.cc) | 830 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/message.h (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.h) | 20 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_field.cc (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.cc) | 80 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_field.h (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.h) | 13 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_layout_helper.h (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h) | 2 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/names.h (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_names.h) | 10 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/options.h (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_options.h) | 5 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/padding_optimizer.cc (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc) | 4 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/padding_optimizer.h (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h) | 2 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/parse_function_generator.cc (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc) | 64 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/parse_function_generator.h (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h) | 4 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/primitive_field.cc (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc) | 79 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/primitive_field.h (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.h) | 19 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/service.cc (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_service.cc) | 4 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/service.h (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_service.h) | 2 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/string_field.cc (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.cc) | 98 | ||||
-rw-r--r-- | contrib/libs/protoc/src/google/protobuf/compiler/cpp/string_field.h (renamed from contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.h) | 14 |
34 files changed, 2314 insertions, 1530 deletions
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.h index f7735da12f0..fe2ff1369a1 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -1,1026 +1 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: [email protected] (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. - -#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ -#define GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ - -#include <algorithm> -#include <cstdint> -#include <iterator> -#include <map> -#include <string> - -#include <google/protobuf/compiler/scc.h> -#include <google/protobuf/compiler/code_generator.h> -#include <google/protobuf/compiler/cpp/cpp_names.h> -#include <google/protobuf/compiler/cpp/cpp_options.h> -#include <google/protobuf/descriptor.pb.h> -#include <google/protobuf/io/printer.h> -#include <google/protobuf/descriptor.h> -#include <google/protobuf/port.h> -#include <google/protobuf/stubs/strutil.h> - -// Must be included last. -#include <google/protobuf/port_def.inc> - -namespace google { -namespace protobuf { -namespace compiler { -namespace cpp { - -enum class ArenaDtorNeeds { kNone = 0, kOnDemand = 1, kRequired = 2 }; - -inline TProtoStringType ProtobufNamespace(const Options& /* options */) { - return "PROTOBUF_NAMESPACE_ID"; -} - -inline TProtoStringType MacroPrefix(const Options& /* options */) { - return "GOOGLE_PROTOBUF"; -} - -inline TProtoStringType DeprecatedAttribute(const Options& /* options */, - const FieldDescriptor* d) { - return d->options().deprecated() ? "PROTOBUF_DEPRECATED " : ""; -} - -inline TProtoStringType DeprecatedAttribute(const Options& /* options */, - const EnumValueDescriptor* d) { - return d->options().deprecated() ? "PROTOBUF_DEPRECATED_ENUM " : ""; -} - -// Commonly-used separator comments. Thick is a line of '=', thin is a line -// of '-'. -extern const char kThickSeparator[]; -extern const char kThinSeparator[]; - -void SetCommonVars(const Options& options, - std::map<TProtoStringType, TProtoStringType>* variables); - -// Variables to access message data from the message scope. -void SetCommonMessageDataVariables( - std::map<TProtoStringType, TProtoStringType>* variables); - -void SetUnknownFieldsVariable(const Descriptor* descriptor, - const Options& options, - std::map<TProtoStringType, TProtoStringType>* variables); - -bool GetBootstrapBasename(const Options& options, const TProtoStringType& basename, - TProtoStringType* bootstrap_basename); -bool MaybeBootstrap(const Options& options, GeneratorContext* generator_context, - bool bootstrap_flag, TProtoStringType* basename); -bool IsBootstrapProto(const Options& options, const FileDescriptor* file); - -// Name space of the proto file. This namespace is such that the string -// "<namespace>::some_name" is the correct fully qualified namespace. -// This means if the package is empty the namespace is "", and otherwise -// the namespace is "::foo::bar::...::baz" without trailing semi-colons. -TProtoStringType Namespace(const FileDescriptor* d, const Options& options); -TProtoStringType Namespace(const Descriptor* d, const Options& options); -TProtoStringType Namespace(const FieldDescriptor* d, const Options& options); -TProtoStringType Namespace(const EnumDescriptor* d, const Options& options); - -// Returns true if it's safe to reset "field" to zero. -bool CanInitializeByZeroing(const FieldDescriptor* field); - -TProtoStringType ClassName(const Descriptor* descriptor); -TProtoStringType ClassName(const EnumDescriptor* enum_descriptor); - -TProtoStringType QualifiedClassName(const Descriptor* d, const Options& options); -TProtoStringType QualifiedClassName(const EnumDescriptor* d, const Options& options); - -TProtoStringType QualifiedClassName(const Descriptor* d); -TProtoStringType QualifiedClassName(const EnumDescriptor* d); - -// DEPRECATED just use ClassName or QualifiedClassName, a boolean is very -// unreadable at the callsite. -// Returns the non-nested type name for the given type. If "qualified" is -// true, prefix the type with the full namespace. For example, if you had: -// package foo.bar; -// message Baz { message Qux {} } -// Then the qualified ClassName for Qux would be: -// ::foo::bar::Baz_Qux -// While the non-qualified version would be: -// Baz_Qux -inline TProtoStringType ClassName(const Descriptor* descriptor, bool qualified) { - return qualified ? QualifiedClassName(descriptor, Options()) - : ClassName(descriptor); -} - -inline TProtoStringType ClassName(const EnumDescriptor* descriptor, bool qualified) { - return qualified ? QualifiedClassName(descriptor, Options()) - : ClassName(descriptor); -} - -// Returns the extension name prefixed with the class name if nested but without -// the package name. -TProtoStringType ExtensionName(const FieldDescriptor* d); - -TProtoStringType QualifiedExtensionName(const FieldDescriptor* d, - const Options& options); -TProtoStringType QualifiedExtensionName(const FieldDescriptor* d); - -// Type name of default instance. -TProtoStringType DefaultInstanceType(const Descriptor* descriptor, - const Options& options); - -// Non-qualified name of the default_instance of this message. -TProtoStringType DefaultInstanceName(const Descriptor* descriptor, - const Options& options); - -// Non-qualified name of the default instance pointer. This is used only for -// implicit weak fields, where we need an extra indirection. -TProtoStringType DefaultInstancePtr(const Descriptor* descriptor, - const Options& options); - -// Fully qualified name of the default_instance of this message. -TProtoStringType QualifiedDefaultInstanceName(const Descriptor* descriptor, - const Options& options); - -// Fully qualified name of the default instance pointer. -TProtoStringType QualifiedDefaultInstancePtr(const Descriptor* descriptor, - const Options& options); - -// DescriptorTable variable name. -TProtoStringType DescriptorTableName(const FileDescriptor* file, - const Options& options); - -// When declaring symbol externs from another file, this macro will supply the -// dllexport needed for the target file, if any. -TProtoStringType FileDllExport(const FileDescriptor* file, const Options& options); - -// Name of the base class: google::protobuf::Message or google::protobuf::MessageLite. -TProtoStringType SuperClassName(const Descriptor* descriptor, - const Options& options); - -// Adds an underscore if necessary to prevent conflicting with a keyword. -TProtoStringType ResolveKeyword(const TProtoStringType& name); - -// Get the (unqualified) name that should be used for this field in C++ code. -// The name is coerced to lower-case to emulate proto1 behavior. People -// should be using lowercase-with-underscores style for proto field names -// anyway, so normally this just returns field->name(). -TProtoStringType FieldName(const FieldDescriptor* field); - -// Returns the (unqualified) private member name for this field in C++ code. -TProtoStringType FieldMemberName(const FieldDescriptor* field); - -// 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 -// different systems with different alignment rules. The estimates below assume -// 64-bit pointers. -int EstimateAlignmentSize(const FieldDescriptor* field); - -// Get the unqualified name that should be used for a field's field -// number constant. -TProtoStringType FieldConstantName(const FieldDescriptor* field); - -// Returns the scope where the field was defined (for extensions, this is -// different from the message type to which the field applies). -inline const Descriptor* FieldScope(const FieldDescriptor* field) { - return field->is_extension() ? field->extension_scope() - : field->containing_type(); -} - -// Returns the fully-qualified type name field->message_type(). Usually this -// is just ClassName(field->message_type(), true); -TProtoStringType FieldMessageTypeName(const FieldDescriptor* field, - const Options& options); - -// Get the C++ type name for a primitive type (e.g. "double", "::google::protobuf::int32", etc.). -const char* PrimitiveTypeName(FieldDescriptor::CppType type); -TProtoStringType PrimitiveTypeName(const Options& options, - FieldDescriptor::CppType type); - -// Get the declared type name in CamelCase format, as is used e.g. for the -// methods of WireFormat. For example, TYPE_INT32 becomes "Int32". -const char* DeclaredTypeMethodName(FieldDescriptor::Type type); - -// Return the code that evaluates to the number when compiled. -TProtoStringType Int32ToString(int number); - -// Get code that evaluates to the field's default value. -TProtoStringType DefaultValue(const Options& options, const FieldDescriptor* field); - -// Compatibility function for callers outside proto2. -TProtoStringType DefaultValue(const FieldDescriptor* field); - -// Convert a file name into a valid identifier. -TProtoStringType FilenameIdentifier(const TProtoStringType& filename); - -// For each .proto file generates a unique name. To prevent collisions of -// symbols in the global namespace -TProtoStringType UniqueName(const TProtoStringType& name, const TProtoStringType& filename, - const Options& options); -inline TProtoStringType UniqueName(const TProtoStringType& name, const FileDescriptor* d, - const Options& options) { - return UniqueName(name, d->name(), options); -} -inline TProtoStringType UniqueName(const TProtoStringType& name, const Descriptor* d, - const Options& options) { - return UniqueName(name, d->file(), options); -} -inline TProtoStringType UniqueName(const TProtoStringType& name, const EnumDescriptor* d, - const Options& options) { - return UniqueName(name, d->file(), options); -} -inline TProtoStringType UniqueName(const TProtoStringType& name, - const ServiceDescriptor* d, - const Options& options) { - return UniqueName(name, d->file(), options); -} - -// Versions for call sites that only support the internal runtime (like proto1 -// support). -inline Options InternalRuntimeOptions() { - Options options; - options.opensource_runtime = false; - return options; -} -inline TProtoStringType UniqueName(const TProtoStringType& name, - const TProtoStringType& filename) { - return UniqueName(name, filename, InternalRuntimeOptions()); -} -inline TProtoStringType UniqueName(const TProtoStringType& name, - const FileDescriptor* d) { - return UniqueName(name, d->name(), InternalRuntimeOptions()); -} -inline TProtoStringType UniqueName(const TProtoStringType& name, const Descriptor* d) { - return UniqueName(name, d->file(), InternalRuntimeOptions()); -} -inline TProtoStringType UniqueName(const TProtoStringType& name, - const EnumDescriptor* d) { - return UniqueName(name, d->file(), InternalRuntimeOptions()); -} -inline TProtoStringType UniqueName(const TProtoStringType& name, - const ServiceDescriptor* d) { - return UniqueName(name, d->file(), InternalRuntimeOptions()); -} - -// Return the qualified C++ name for a file level symbol. -TProtoStringType QualifiedFileLevelSymbol(const FileDescriptor* file, - const TProtoStringType& name, - const Options& options); - -// Escape C++ trigraphs by escaping question marks to \? -TProtoStringType EscapeTrigraphs(const TProtoStringType& to_escape); - -// Escaped function name to eliminate naming conflict. -TProtoStringType SafeFunctionName(const Descriptor* descriptor, - const FieldDescriptor* field, - const TProtoStringType& prefix); - -// Returns true if generated messages have public unknown fields accessors -inline bool PublicUnknownFieldsAccessors(const Descriptor* message) { - return message->file()->syntax() != FileDescriptor::SYNTAX_PROTO3; -} - -// Returns the optimize mode for <file>, respecting <options.enforce_lite>. -FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file, - const Options& options); - -// Determines whether unknown fields will be stored in an UnknownFieldSet or -// a string. -inline bool UseUnknownFieldSet(const FileDescriptor* file, - const Options& options) { - return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME; -} - -inline bool IsWeak(const FieldDescriptor* field, const Options& options) { - if (field->options().weak()) { - GOOGLE_CHECK(!options.opensource_runtime); - return true; - } - return false; -} - -bool IsStringInlined(const FieldDescriptor* descriptor, const Options& options); - -// For a string field, returns the effective ctype. If the actual ctype is -// not supported, returns the default of STRING. -FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field, - const Options& options); - -inline bool IsCord(const FieldDescriptor* field, const Options& options) { - return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && - EffectiveStringCType(field, options) == FieldOptions::CORD; -} - -inline bool IsString(const FieldDescriptor* field, const Options& options) { - return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && - EffectiveStringCType(field, options) == FieldOptions::STRING; -} - -inline bool IsStringPiece(const FieldDescriptor* field, - const Options& options) { - return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && - EffectiveStringCType(field, options) == FieldOptions::STRING_PIECE; -} - -class MessageSCCAnalyzer; - -// Does the given FileDescriptor use lazy fields? -bool HasLazyFields(const FileDescriptor* file, const Options& options, - MessageSCCAnalyzer* scc_analyzer); - -// Is the given field a supported lazy field? -bool IsLazy(const FieldDescriptor* field, const Options& options, - MessageSCCAnalyzer* scc_analyzer); - -// Is this an explicit (non-profile driven) lazy field, as denoted by -// lazy/unverified_lazy in the descriptor? -inline bool IsExplicitLazy(const FieldDescriptor* field) { - return field->options().lazy() || field->options().unverified_lazy(); -} - -inline bool IsLazilyVerifiedLazy(const FieldDescriptor* field, - const Options& options) { - // TODO(b/211906113): Make lazy() imply eagerly verified lazy. - return IsExplicitLazy(field) && !field->is_repeated() && - field->type() == FieldDescriptor::TYPE_MESSAGE && - GetOptimizeFor(field->file(), options) != FileOptions::LITE_RUNTIME && - !options.opensource_runtime; -} - -inline bool IsEagerlyVerifiedLazy(const FieldDescriptor* field, - const Options& options, - MessageSCCAnalyzer* scc_analyzer) { - // TODO(b/211906113): Make lazy() imply eagerly verified lazy. - return IsLazy(field, options, scc_analyzer) && !IsExplicitLazy(field); -} - -inline bool IsFieldUsed(const FieldDescriptor* /* field */, - const Options& /* options */) { - return true; -} - -// Returns true if "field" is stripped. -inline bool IsFieldStripped(const FieldDescriptor* /*field*/, - const Options& /*options*/) { - return false; -} - -// Does the file contain any definitions that need extension_set.h? -bool HasExtensionsOrExtendableMessage(const FileDescriptor* file); - -// Does the file have any repeated fields, necessitating the file to include -// repeated_field.h? This does not include repeated extensions, since those are -// all stored internally in an ExtensionSet, not a separate RepeatedField*. -bool HasRepeatedFields(const FileDescriptor* file); - -// Does the file have any string/bytes fields with ctype=STRING_PIECE? This -// does not include extensions, since ctype is ignored for extensions. -bool HasStringPieceFields(const FileDescriptor* file, const Options& options); - -// Does the file have any string/bytes fields with ctype=CORD? This does not -// include extensions, since ctype is ignored for extensions. -bool HasCordFields(const FileDescriptor* file, const Options& options); - -// Does the file have any map fields, necessitating the file to include -// map_field_inl.h and map.h. -bool HasMapFields(const FileDescriptor* file); - -// Does this file have any enum type definitions? -bool HasEnumDefinitions(const FileDescriptor* file); - -// Does this file have generated parsing, serialization, and other -// standard methods for which reflection-based fallback implementations exist? -inline bool HasGeneratedMethods(const FileDescriptor* file, - const Options& options) { - return GetOptimizeFor(file, options) != FileOptions::CODE_SIZE; -} - -// Do message classes in this file have descriptor and reflection methods? -inline bool HasDescriptorMethods(const FileDescriptor* file, - const Options& options) { - return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME; -} - -// Should we generate generic services for this file? -inline bool HasGenericServices(const FileDescriptor* file, - const Options& options) { - return file->service_count() > 0 && - GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME && - file->options().cc_generic_services(); -} - -inline bool IsProto2MessageSet(const Descriptor* descriptor, - const Options& options) { - return !options.opensource_runtime && - options.enforce_mode != EnforceOptimizeMode::kLiteRuntime && - !options.lite_implicit_weak_fields && - descriptor->options().message_set_wire_format() && - descriptor->full_name() == "google.protobuf.bridge.MessageSet"; -} - -inline bool IsMapEntryMessage(const Descriptor* descriptor) { - return descriptor->options().map_entry(); -} - -// Returns true if the field's CPPTYPE is string or message. -bool IsStringOrMessage(const FieldDescriptor* field); - -TProtoStringType UnderscoresToCamelCase(const TProtoStringType& input, - bool cap_next_letter); - -inline bool IsProto3(const FileDescriptor* file) { - return file->syntax() == FileDescriptor::SYNTAX_PROTO3; -} - -inline bool HasHasbit(const FieldDescriptor* field) { - // This predicate includes proto3 message fields only if they have "optional". - // Foo submsg1 = 1; // HasHasbit() == false - // optional Foo submsg2 = 2; // HasHasbit() == true - // This is slightly odd, as adding "optional" to a singular proto3 field does - // not change the semantics or API. However whenever any field in a message - // has a hasbit, it forces reflection to include hasbit offsets for *all* - // fields, even if almost all of them are set to -1 (no hasbit). So to avoid - // causing a sudden size regression for ~all proto3 messages, we give proto3 - // message fields a hasbit only if "optional" is present. If the user is - // explicitly writing "optional", it is likely they are writing it on - // primitive fields also. - return (field->has_optional_keyword() || field->is_required()) && - !field->options().weak(); -} - -// Returns true if 'enum' semantics are such that unknown values are preserved -// in the enum field itself, rather than going to the UnknownFieldSet. -inline bool HasPreservingUnknownEnumSemantics(const FieldDescriptor* field) { - return field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3; -} - -inline bool IsCrossFileMessage(const FieldDescriptor* field) { - return field->type() == FieldDescriptor::TYPE_MESSAGE && - field->message_type()->file() != field->file(); -} - -inline TProtoStringType MakeDefaultName(const FieldDescriptor* field) { - return "_i_give_permission_to_break_this_code_default_" + FieldName(field) + - "_"; -} - -// Semantically distinct from MakeDefaultName in that it gives the C++ code -// referencing a default field from the message scope, rather than just the -// variable name. -// For example, declarations of default variables should always use just -// MakeDefaultName to produce code like: -// Type _i_give_permission_to_break_this_code_default_field_; -// -// Code that references these should use MakeDefaultFieldName, in case the field -// exists at some nested level like: -// internal_container_._i_give_permission_to_break_this_code_default_field_; -inline TProtoStringType MakeDefaultFieldName(const FieldDescriptor* field) { - return MakeDefaultName(field); -} - -inline TProtoStringType MakeVarintCachedSizeName(const FieldDescriptor* field) { - return StrCat("_", FieldName(field), "_cached_byte_size_"); -} - -// Semantically distinct from MakeVarintCachedSizeName in that it gives the C++ -// code referencing the object from the message scope, rather than just the -// variable name. -// For example, declarations of default variables should always use just -// MakeVarintCachedSizeName to produce code like: -// Type _field_cached_byte_size_; -// -// Code that references these variables should use -// MakeVarintCachedSizeFieldName, in case the field exists at some nested level -// like: -// internal_container_._field_cached_byte_size_; -inline TProtoStringType MakeVarintCachedSizeFieldName(const FieldDescriptor* field) { - return StrCat("_", FieldName(field), "_cached_byte_size_"); -} - -// Note: A lot of libraries detect Any protos based on Descriptor::full_name() -// while the two functions below use FileDescriptor::name(). In a sane world the -// two approaches should be equivalent. But if you are dealing with descriptors -// from untrusted sources, you might need to match semantics across libraries. -bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options); -bool IsAnyMessage(const Descriptor* descriptor, const Options& options); - -bool IsWellKnownMessage(const FileDescriptor* descriptor); - -inline TProtoStringType IncludeGuard(const FileDescriptor* file, bool pb_h, - bool deps, - const Options& options) { - // If we are generating a .pb.h file and the proto_h option is enabled, then - // the .pb.h gets an extra suffix. - TProtoStringType filename_identifier = FilenameIdentifier( - file->name() + (deps ? ".deps": "") + (pb_h && options.proto_h ? ".pb.h" : "")); - - if (IsWellKnownMessage(file)) { - // For well-known messages we need third_party/protobuf and net/proto2 to - // have distinct include guards, because some source files include both and - // both need to be defined (the third_party copies will be in the - // google::protobuf_opensource namespace). - return MacroPrefix(options) + "_INCLUDED_" + filename_identifier; - } else { - // Ideally this case would use distinct include guards for opensource and - // google3 protos also. (The behavior of "first #included wins" is not - // ideal). But unfortunately some legacy code includes both and depends on - // the identical include guards to avoid compile errors. - // - // We should clean this up so that this case can be removed. - return "GOOGLE_PROTOBUF_INCLUDED_" + filename_identifier; - } -} - -// Returns the OptimizeMode for this file, furthermore it updates a status -// bool if has_opt_codesize_extension is non-null. If this status bool is true -// it means this file contains an extension that itself is defined as -// optimized_for = CODE_SIZE. -FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file, - const Options& options, - bool* has_opt_codesize_extension); -inline FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file, - const Options& options) { - return GetOptimizeFor(file, options, nullptr); -} -inline bool NeedsEagerDescriptorAssignment(const FileDescriptor* file, - const Options& options) { - bool has_opt_codesize_extension; - if (GetOptimizeFor(file, options, &has_opt_codesize_extension) == - FileOptions::CODE_SIZE && - has_opt_codesize_extension) { - // If this filedescriptor contains an extension from another file which - // is optimized_for = CODE_SIZE. We need to be careful in the ordering so - // we eagerly build the descriptors in the dependencies before building - // the descriptors of this file. - return true; - } else { - // If we have a generated code based parser we never need eager - // initialization of descriptors of our deps. - return false; - } -} - -// This orders the messages in a .pb.cc as it's outputted by file.cc -void FlattenMessagesInFile(const FileDescriptor* file, - std::vector<const Descriptor*>* result); -inline std::vector<const Descriptor*> FlattenMessagesInFile( - const FileDescriptor* file) { - std::vector<const Descriptor*> result; - FlattenMessagesInFile(file, &result); - return result; -} - -template <typename F> -void ForEachMessage(const Descriptor* descriptor, F&& func) { - for (int i = 0; i < descriptor->nested_type_count(); i++) - ForEachMessage(descriptor->nested_type(i), std::forward<F&&>(func)); - func(descriptor); -} - -template <typename F> -void ForEachMessage(const FileDescriptor* descriptor, F&& func) { - for (int i = 0; i < descriptor->message_type_count(); i++) - ForEachMessage(descriptor->message_type(i), std::forward<F&&>(func)); -} - -bool HasWeakFields(const Descriptor* desc, const Options& options); -bool HasWeakFields(const FileDescriptor* desc, const Options& options); - -// Returns true if the "required" restriction check should be ignored for the -// given field. -inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field, - const Options& options) { - // Do not check "required" for lazily verified lazy fields. - return IsLazilyVerifiedLazy(field, options); -} - -struct MessageAnalysis { - bool is_recursive = false; - bool contains_cord = false; - bool contains_extension = false; - bool contains_required = false; - bool contains_weak = false; // Implicit weak as well. -}; - -// This class is used in FileGenerator, to ensure linear instead of -// quadratic performance, if we do this per message we would get O(V*(V+E)). -// Logically this is just only used in message.cc, but in the header for -// FileGenerator to help share it. -class PROTOC_EXPORT MessageSCCAnalyzer { - public: - explicit MessageSCCAnalyzer(const Options& options) : options_(options) {} - - MessageAnalysis GetSCCAnalysis(const SCC* scc); - - bool HasRequiredFields(const Descriptor* descriptor) { - MessageAnalysis result = GetSCCAnalysis(GetSCC(descriptor)); - return result.contains_required || result.contains_extension; - } - bool HasWeakField(const Descriptor* descriptor) { - MessageAnalysis result = GetSCCAnalysis(GetSCC(descriptor)); - return result.contains_weak; - } - const SCC* GetSCC(const Descriptor* descriptor) { - return analyzer_.GetSCC(descriptor); - } - - private: - struct DepsGenerator { - std::vector<const Descriptor*> operator()(const Descriptor* desc) const { - std::vector<const Descriptor*> deps; - for (int i = 0; i < desc->field_count(); i++) { - if (desc->field(i)->message_type()) { - deps.push_back(desc->field(i)->message_type()); - } - } - return deps; - } - }; - SCCAnalyzer<DepsGenerator> analyzer_; - Options options_; - std::map<const SCC*, MessageAnalysis> analysis_cache_; -}; - -void ListAllFields(const Descriptor* d, - std::vector<const FieldDescriptor*>* fields); -void ListAllFields(const FileDescriptor* d, - std::vector<const FieldDescriptor*>* fields); - -template <class T> -void ForEachField(const Descriptor* d, T&& func) { - for (int i = 0; i < d->nested_type_count(); i++) { - ForEachField(d->nested_type(i), std::forward<T&&>(func)); - } - for (int i = 0; i < d->extension_count(); i++) { - func(d->extension(i)); - } - for (int i = 0; i < d->field_count(); i++) { - func(d->field(i)); - } -} - -template <class T> -void ForEachField(const FileDescriptor* d, T&& func) { - for (int i = 0; i < d->message_type_count(); i++) { - ForEachField(d->message_type(i), std::forward<T&&>(func)); - } - for (int i = 0; i < d->extension_count(); i++) { - func(d->extension(i)); - } -} - -void ListAllTypesForServices(const FileDescriptor* fd, - std::vector<const Descriptor*>* types); - -// Indicates whether we should use implicit weak fields for this file. -bool UsingImplicitWeakFields(const FileDescriptor* file, - const Options& options); - -// Indicates whether to treat this field as implicitly weak. -bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options, - MessageSCCAnalyzer* scc_analyzer); - -inline bool HasSimpleBaseClass(const Descriptor* desc, const Options& options) { - if (!HasDescriptorMethods(desc->file(), options)) return false; - if (desc->extension_range_count() != 0) return false; - if (desc->field_count() == 0) return true; - // TODO(jorg): Support additional common message types with only one - // or two fields - return false; -} - -inline bool HasSimpleBaseClasses(const FileDescriptor* file, - const Options& options) { - bool v = false; - ForEachMessage(file, [&v, &options](const Descriptor* desc) { - v |= HasSimpleBaseClass(desc, options); - }); - return v; -} - -inline TProtoStringType SimpleBaseClass(const Descriptor* desc, - const Options& options) { - if (!HasDescriptorMethods(desc->file(), options)) return ""; - if (desc->extension_range_count() != 0) return ""; - if (desc->field_count() == 0) { - return "ZeroFieldsBase"; - } - // TODO(jorg): Support additional common message types with only one - // or two fields - return ""; -} - -// Formatter is a functor class which acts as a closure around printer and -// the variable map. It's much like printer->Print except it supports both named -// variables that are substituted using a key value map and direct arguments. In -// the format string $1$, $2$, etc... are substituted for the first, second, ... -// direct argument respectively in the format call, it accepts both strings and -// integers. The implementation verifies all arguments are used and are "first" -// used in order of appearance in the argument list. For example, -// -// Format("return array[$1$];", 3) -> "return array[3];" -// Format("array[$2$] = $1$;", "Bla", 3) -> FATAL error (wrong order) -// Format("array[$1$] = $2$;", 3, "Bla") -> "array[3] = Bla;" -// -// The arguments can be used more than once like -// -// Format("array[$1$] = $2$; // Index = $1$", 3, "Bla") -> -// "array[3] = Bla; // Index = 3" -// -// If you use more arguments use the following style to help the reader, -// -// Format("int $1$() {\n" -// " array[$2$] = $3$;\n" -// " return $4$;" -// "}\n", -// funname, // 1 -// idx, // 2 -// varname, // 3 -// retval); // 4 -// -// but consider using named variables. Named variables like $foo$, with some -// identifier foo, are looked up in the map. One additional feature is that -// spaces are accepted between the '$' delimiters, $ foo$ will -// substiture to " bar" if foo stands for "bar", but in case it's empty -// will substitute to "". Hence, for example, -// -// Format(vars, "$dllexport $void fun();") -> "void fun();" -// "__declspec(export) void fun();" -// -// which is convenient to prevent double, leading or trailing spaces. -class PROTOC_EXPORT Formatter { - public: - explicit Formatter(io::Printer* printer) : printer_(printer) {} - Formatter(io::Printer* printer, - const std::map<TProtoStringType, TProtoStringType>& vars) - : printer_(printer), vars_(vars) {} - - template <typename T> - void Set(const TProtoStringType& key, const T& value) { - vars_[key] = ToString(value); - } - - void AddMap(const std::map<TProtoStringType, TProtoStringType>& vars) { - for (const auto& keyval : vars) vars_[keyval.first] = keyval.second; - } - - template <typename... Args> - void operator()(const char* format, const Args&... args) const { - printer_->FormatInternal({ToString(args)...}, vars_, format); - } - - void Indent() const { printer_->Indent(); } - void Outdent() const { printer_->Outdent(); } - io::Printer* printer() const { return printer_; } - - class PROTOC_EXPORT ScopedIndenter { - public: - explicit ScopedIndenter(Formatter* format) : format_(format) { - format_->Indent(); - } - ~ScopedIndenter() { format_->Outdent(); } - - private: - Formatter* format_; - }; - - PROTOBUF_NODISCARD ScopedIndenter ScopedIndent() { - return ScopedIndenter(this); - } - template <typename... Args> - PROTOBUF_NODISCARD ScopedIndenter ScopedIndent(const char* format, - const Args&&... args) { - (*this)(format, static_cast<Args&&>(args)...); - return ScopedIndenter(this); - } - - class PROTOC_EXPORT SaveState { - public: - explicit SaveState(Formatter* format) - : format_(format), vars_(format->vars_) {} - ~SaveState() { format_->vars_.swap(vars_); } - - private: - Formatter* format_; - std::map<TProtoStringType, TProtoStringType> vars_; - }; - - private: - io::Printer* printer_; - std::map<TProtoStringType, TProtoStringType> vars_; - - // Convenience overloads to accept different types as arguments. - static TProtoStringType ToString(const TProtoStringType& s) { return s; } - template <typename I, typename = typename std::enable_if< - std::is_integral<I>::value>::type> - static TProtoStringType ToString(I x) { - return StrCat(x); - } - static TProtoStringType ToString(strings::Hex x) { return StrCat(x); } - static TProtoStringType ToString(const FieldDescriptor* d) { return Payload(d); } - static TProtoStringType ToString(const Descriptor* d) { return Payload(d); } - static TProtoStringType ToString(const EnumDescriptor* d) { return Payload(d); } - static TProtoStringType ToString(const EnumValueDescriptor* d) { - return Payload(d); - } - static TProtoStringType ToString(const OneofDescriptor* d) { return Payload(d); } - - template <typename Descriptor> - static TProtoStringType Payload(const Descriptor* descriptor) { - std::vector<int> path; - descriptor->GetLocationPath(&path); - GeneratedCodeInfo::Annotation annotation; - for (int index : path) { - annotation.add_path(index); - } - annotation.set_source_file(descriptor->file()->name()); - return annotation.SerializeAsString(); - } -}; - -template <class T> -void PrintFieldComment(const Formatter& format, const T* field) { - // Print the field's (or oneof's) proto-syntax definition as a comment. - // We don't want to print group bodies so we cut off after the first - // line. - DebugStringOptions options; - options.elide_group_body = true; - options.elide_oneof_body = true; - TProtoStringType def = field->DebugStringWithOptions(options); - format("// $1$\n", def.substr(0, def.find_first_of('\n'))); -} - -class PROTOC_EXPORT NamespaceOpener { - public: - explicit NamespaceOpener(const Formatter& format) - : printer_(format.printer()) {} - NamespaceOpener(const TProtoStringType& name, const Formatter& format) - : NamespaceOpener(format) { - ChangeTo(name); - } - ~NamespaceOpener() { ChangeTo(""); } - - void ChangeTo(const TProtoStringType& name) { - std::vector<TProtoStringType> new_stack_ = - Split(name, "::", true); - size_t len = std::min(name_stack_.size(), new_stack_.size()); - size_t common_idx = 0; - while (common_idx < len) { - if (name_stack_[common_idx] != new_stack_[common_idx]) break; - common_idx++; - } - for (auto it = name_stack_.crbegin(); - it != name_stack_.crend() - common_idx; ++it) { - if (*it == "PROTOBUF_NAMESPACE_ID") { - printer_->Print("PROTOBUF_NAMESPACE_CLOSE\n"); - } else { - printer_->Print("} // namespace $ns$\n", "ns", *it); - } - } - name_stack_.swap(new_stack_); - for (size_t i = common_idx; i < name_stack_.size(); ++i) { - if (name_stack_[i] == "PROTOBUF_NAMESPACE_ID") { - printer_->Print("PROTOBUF_NAMESPACE_OPEN\n"); - } else { - printer_->Print("namespace $ns$ {\n", "ns", name_stack_[i]); - } - } - } - - private: - io::Printer* printer_; - std::vector<TProtoStringType> name_stack_; -}; - -enum class Utf8CheckMode { - kStrict = 0, // Parsing will fail if non UTF-8 data is in string fields. - kVerify = 1, // Only log an error but parsing will succeed. - kNone = 2, // No UTF-8 check. -}; - -Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field, - const Options& options); - -void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, - const Options& options, bool for_parse, - const char* parameters, - const Formatter& format); - -void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, - const Options& options, bool for_parse, - const char* parameters, - const Formatter& format); - -template <typename T> -struct FieldRangeImpl { - struct Iterator { - using iterator_category = std::forward_iterator_tag; - using value_type = const FieldDescriptor*; - using difference_type = int; - - value_type operator*() { return descriptor->field(idx); } - - friend bool operator==(const Iterator& a, const Iterator& b) { - GOOGLE_DCHECK(a.descriptor == b.descriptor); - return a.idx == b.idx; - } - friend bool operator!=(const Iterator& a, const Iterator& b) { - return !(a == b); - } - - Iterator& operator++() { - idx++; - return *this; - } - - int idx; - const T* descriptor; - }; - - Iterator begin() const { return {0, descriptor}; } - Iterator end() const { return {descriptor->field_count(), descriptor}; } - - const T* descriptor; -}; - -template <typename T> -FieldRangeImpl<T> FieldRange(const T* desc) { - return {desc}; -} - -struct OneOfRangeImpl { - struct Iterator { - using iterator_category = std::forward_iterator_tag; - using value_type = const OneofDescriptor*; - using difference_type = int; - - value_type operator*() { return descriptor->oneof_decl(idx); } - - friend bool operator==(const Iterator& a, const Iterator& b) { - GOOGLE_DCHECK(a.descriptor == b.descriptor); - return a.idx == b.idx; - } - friend bool operator!=(const Iterator& a, const Iterator& b) { - return !(a == b); - } - - Iterator& operator++() { - idx++; - return *this; - } - - int idx; - const Descriptor* descriptor; - }; - - Iterator begin() const { return {0, descriptor}; } - Iterator end() const { - return {descriptor->real_oneof_decl_count(), descriptor}; - } - - const Descriptor* descriptor; -}; - -inline OneOfRangeImpl OneOfRange(const Descriptor* desc) { return {desc}; } - -PROTOC_EXPORT TProtoStringType StripProto(const TProtoStringType& filename); - -bool EnableMessageOwnedArena(const Descriptor* desc, const Options& options); - -bool ShouldVerify(const Descriptor* descriptor, const Options& options, - MessageSCCAnalyzer* scc_analyzer); -bool ShouldVerify(const FileDescriptor* file, const Options& options, - MessageSCCAnalyzer* scc_analyzer); -} // namespace cpp -} // namespace compiler -} // namespace protobuf -} // namespace google - -#include <google/protobuf/port_undef.inc> - -#endif // GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ +#include "helpers.h"
\ No newline at end of file diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum.cc index 960dfcadf79..91d0b9442b7 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum.cc @@ -32,7 +32,7 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/cpp_enum.h> +#include <google/protobuf/compiler/cpp/enum.h> #include <cstdint> #include <limits> @@ -40,8 +40,8 @@ #include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/compiler/cpp/cpp_names.h> +#include <google/protobuf/compiler/cpp/helpers.h> +#include <google/protobuf/compiler/cpp/names.h> namespace google { namespace protobuf { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum.h index 652a26b6db8..550f43b1ed4 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum.h @@ -40,7 +40,7 @@ #include <string> #include <google/protobuf/descriptor.h> -#include <google/protobuf/compiler/cpp/cpp_options.h> +#include <google/protobuf/compiler/cpp/options.h> namespace google { namespace protobuf { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum_field.cc index f50fca4926a..dc8dc524815 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum_field.cc @@ -32,12 +32,13 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/cpp_enum_field.h> +#include <google/protobuf/compiler/cpp/enum_field.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/field.h> +#include <google/protobuf/compiler/cpp/helpers.h> namespace google { namespace protobuf { @@ -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" @@ -123,7 +126,7 @@ void EnumFieldGenerator::GenerateClearingCode(io::Printer* printer) const { void EnumFieldGenerator::GenerateMergingCode(io::Printer* printer) const { Formatter format(printer, variables_); - format("_internal_set_$name$(from._internal_$name$());\n"); + format("_this->_internal_set_$name$(from._internal_$name$());\n"); } void EnumFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { @@ -131,15 +134,10 @@ void EnumFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { format("swap($field$, other->$field$);\n"); } -void EnumFieldGenerator::GenerateConstructorCode(io::Printer* printer) const { - Formatter format(printer, variables_); - format("$field$ = $default$;\n"); -} - void EnumFieldGenerator::GenerateCopyConstructorCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$field$ = from.$field$;\n"); + format("_this->$field$ = from.$field$;\n"); } void EnumFieldGenerator::GenerateSerializeWithCachedSizesToArray( @@ -158,10 +156,26 @@ void EnumFieldGenerator::GenerateByteSize(io::Printer* printer) const { " ::_pbi::WireFormatLite::EnumSize(this->_internal_$name$());\n"); } -void EnumFieldGenerator::GenerateConstinitInitializer( +void EnumFieldGenerator::GenerateConstexprAggregateInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("/*decltype($field$)*/$default$"); +} + +void EnumFieldGenerator::GenerateAggregateInitializer( io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_($default$)\n"); + if (ShouldSplit(descriptor_, options_)) { + format("decltype(Impl_::Split::$name$_){$default$}"); + return; + } + format("decltype($field$){$default$}"); +} + +void EnumFieldGenerator::GenerateCopyAggregateInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("decltype($field$){}"); } // =================================================================== @@ -322,7 +336,7 @@ void RepeatedEnumFieldGenerator::GenerateClearingCode( void RepeatedEnumFieldGenerator::GenerateMergingCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$field$.MergeFrom(from.$field$);\n"); + format("_this->$field$.MergeFrom(from.$field$);\n"); } void RepeatedEnumFieldGenerator::GenerateSwappingCode( @@ -336,6 +350,12 @@ void RepeatedEnumFieldGenerator::GenerateConstructorCode( // Not needed for repeated fields. } +void RepeatedEnumFieldGenerator::GenerateDestructorCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$field$.~RepeatedField();\n"); +} + void RepeatedEnumFieldGenerator::GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const { Formatter format(printer, variables_); @@ -392,13 +412,36 @@ void RepeatedEnumFieldGenerator::GenerateByteSize(io::Printer* printer) const { format("}\n"); } -void RepeatedEnumFieldGenerator::GenerateConstinitInitializer( +void RepeatedEnumFieldGenerator::GenerateConstexprAggregateInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("/*decltype($field$)*/{}"); + if (descriptor_->is_packed() && + HasGeneratedMethods(descriptor_->file(), options_)) { + format("\n, /*decltype($cached_byte_size_field$)*/{0}"); + } +} + +void RepeatedEnumFieldGenerator::GenerateAggregateInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("decltype($field$){arena}"); + if (descriptor_->is_packed() && + HasGeneratedMethods(descriptor_->file(), options_)) { + // std::atomic has no copy constructor, which prevents explicit aggregate + // initialization pre-C++17. + format("\n, /*decltype($cached_byte_size_field$)*/{0}"); + } +} + +void RepeatedEnumFieldGenerator::GenerateCopyAggregateInitializer( io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_()"); + format("decltype($field$){from.$field$}"); if (descriptor_->is_packed() && HasGeneratedMethods(descriptor_->file(), options_)) { - format("\n, $cached_byte_size_name$(0)"); + // std::atomic has no copy constructor. + format("\n, /*decltype($cached_byte_size_field$)*/{0}"); } } diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum_field.h index 2a4ca5162bf..61bae855cd6 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_enum_field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/enum_field.h @@ -38,7 +38,7 @@ #include <map> #include <string> -#include <google/protobuf/compiler/cpp/cpp_field.h> +#include <google/protobuf/compiler/cpp/field.h> namespace google { namespace protobuf { @@ -57,12 +57,15 @@ class EnumFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const override; void GenerateMergingCode(io::Printer* printer) const override; void GenerateSwappingCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override {} void GenerateCopyConstructorCode(io::Printer* printer) const override; void GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const override; void GenerateByteSize(io::Printer* printer) const override; - void GenerateConstinitInitializer(io::Printer* printer) const override; + void GenerateConstexprAggregateInitializer( + io::Printer* printer) const override; + void GenerateAggregateInitializer(io::Printer* printer) const override; + void GenerateCopyAggregateInitializer(io::Printer* printer) const override; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); @@ -98,11 +101,17 @@ 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; void GenerateByteSize(io::Printer* printer) const override; - void GenerateConstinitInitializer(io::Printer* printer) const override; + void GenerateConstexprAggregateInitializer( + io::Printer* printer) const override; + void GenerateAggregateInitializer(io::Printer* printer) const override; + void GenerateCopyAggregateInitializer(io::Printer* printer) const override; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/extension.cc index ef6cc81241f..ed85f75960a 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/extension.cc @@ -32,13 +32,13 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/cpp_extension.h> +#include <google/protobuf/compiler/cpp/extension.h> #include <map> #include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/helpers.h> #include <google/protobuf/descriptor.pb.h> namespace google { @@ -78,7 +78,7 @@ ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor, break; } SetCommonVars(options, &variables_); - SetCommonMessageDataVariables(&variables_); + SetCommonMessageDataVariables(descriptor_->containing_type(), &variables_); variables_["extendee"] = QualifiedClassName(descriptor_->containing_type(), options_); variables_["type_traits"] = type_traits_; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/extension.h index 5a32e845540..b94b178868a 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_extension.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/extension.h @@ -39,7 +39,7 @@ #include <string> #include <google/protobuf/stubs/common.h> -#include <google/protobuf/compiler/cpp/cpp_options.h> +#include <google/protobuf/compiler/cpp/options.h> namespace google { namespace protobuf { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field.cc index 895f094c701..d5359b6d247 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field.cc @@ -32,7 +32,7 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/cpp_field.h> +#include <google/protobuf/compiler/cpp/field.h> #include <cstdint> #include <memory> @@ -40,16 +40,16 @@ #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/stubs/substitute.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/compiler/cpp/cpp_primitive_field.h> -#include <google/protobuf/compiler/cpp/cpp_string_field.h> +#include <google/protobuf/compiler/cpp/helpers.h> +#include <google/protobuf/compiler/cpp/primitive_field.h> +#include <google/protobuf/compiler/cpp/string_field.h> #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/wire_format.h> -#include <google/protobuf/compiler/cpp/cpp_enum_field.h> -#include <google/protobuf/compiler/cpp/cpp_map_field.h> -#include <google/protobuf/compiler/cpp/cpp_message_field.h> +#include <google/protobuf/compiler/cpp/enum_field.h> +#include <google/protobuf/compiler/cpp/map_field.h> +#include <google/protobuf/compiler/cpp/message_field.h> #include <google/protobuf/descriptor.pb.h> namespace google { @@ -236,7 +236,7 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, std::map<TProtoStringType, TProtoStringType>* variables, const Options& options) { SetCommonVars(options, variables); - SetCommonMessageDataVariables(variables); + SetCommonMessageDataVariables(descriptor->containing_type(), variables); (*variables)["ns"] = Namespace(descriptor, options); (*variables)["name"] = FieldName(descriptor); @@ -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,13 +253,8 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["set_hasbit"] = ""; (*variables)["clear_hasbit"] = ""; - if (HasHasbit(descriptor)) { - (*variables)["set_hasbit_io"] = - StrCat("_Internal::set_has_", FieldName(descriptor), "(&", - (*variables)["has_bits"], ");"); - } else { - (*variables)["set_hasbit_io"] = ""; - } + (*variables)["maybe_prepare_split_message"] = + split ? " PrepareSplitMessageForWrite();\n" : ""; AddAccessorAnnotations(descriptor, options, variables); @@ -304,6 +300,36 @@ void FieldGenerator::SetInlinedStringIndex(arc_i32 inlined_string_index) { "u"); } +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}"); +} + +void FieldGenerator::GenerateConstexprAggregateInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("/*decltype($field$)*/{}"); +} + +void FieldGenerator::GenerateCopyAggregateInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + 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<TProtoStringType, TProtoStringType>* variables) { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field.h index 9c3ec7fde4b..95eb96f499d 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/field.h @@ -41,8 +41,8 @@ #include <string> #include <google/protobuf/descriptor.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/compiler/cpp/cpp_options.h> +#include <google/protobuf/compiler/cpp/helpers.h> +#include <google/protobuf/compiler/cpp/options.h> namespace google { namespace protobuf { @@ -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. @@ -165,10 +168,32 @@ class FieldGenerator { } // Generate initialization code for private members declared by - // GeneratePrivateMembers(), specifically for the constexpr constructor. - // These go into the constructor's initializer list and must follow that - // syntax (eg `field_(args)`). Does not include `:` or `,` separators. - virtual void GenerateConstinitInitializer(io::Printer* printer) const {} + // GeneratePrivateMembers(). These go into the SharedCtor's + // aggregate initialization of the _impl_ struct and must follow the syntax + // (e.g. `decltype($field$){$default$}`). Does not include `:` or `,` + // separators. Default values should be specified here when possible. + // + // Note: We use `decltype($field$)` for both explicit construction and the + // fact that it's self-documenting. Pre-C++17, copy elision isn't guaranteed + // in aggregate initialization so a valid copy/move constructor must exist + // (even though it's not used). Because of this, we need to comment out the + // decltype and fallback to implicit construction. + virtual void GenerateAggregateInitializer(io::Printer* printer) const; + + // Generate constinit initialization code for private members declared by + // GeneratePrivateMembers(). These go into the constexpr constructor's + // aggregate initialization of the _impl_ struct and must follow the syntax + // (e.g. `/*decltype($field$)*/{}`, see above). Does not + // include `:` or `,` separators. + virtual void GenerateConstexprAggregateInitializer( + io::Printer* printer) const; + + // Generate copy initialization code for private members declared by + // GeneratePrivateMembers(). These go into the copy constructor's + // aggregate initialization of the _impl_ struct and must follow the syntax + // (e.g. `decltype($field$){from.$field$}`, see above). Does not + // include `:` or `,` separators. + virtual void GenerateCopyAggregateInitializer(io::Printer* printer) const; // Generate lines to serialize this field directly to the array "target", // which are placed within the message's SerializeWithCachedSizesToArray() diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/file.cc index f27d876e2ac..2d79ec11e59 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/file.cc @@ -32,7 +32,7 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/cpp_file.h> +#include <google/protobuf/compiler/cpp/file.h> #include <iostream> #include <map> @@ -46,12 +46,12 @@ #include <google/protobuf/compiler/scc.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/compiler/cpp/cpp_enum.h> -#include <google/protobuf/compiler/cpp/cpp_extension.h> -#include <google/protobuf/compiler/cpp/cpp_field.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/compiler/cpp/cpp_message.h> -#include <google/protobuf/compiler/cpp/cpp_service.h> +#include <google/protobuf/compiler/cpp/enum.h> +#include <google/protobuf/compiler/cpp/extension.h> +#include <google/protobuf/compiler/cpp/field.h> +#include <google/protobuf/compiler/cpp/helpers.h> +#include <google/protobuf/compiler/cpp/message.h> +#include <google/protobuf/compiler/cpp/service.h> #include <google/protobuf/descriptor.pb.h> // Must be last. @@ -496,10 +496,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" @@ -511,14 +541,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); @@ -526,11 +553,11 @@ void FileGenerator::GenerateSourceDefaultInstance(int idx, // Force the initialization of the inlined string in the default instance. format( "PROTOBUF_ATTRIBUTE_INIT_PRIORITY2 std::true_type " - "$1$::_init_inline_$2$_ = " + "$1$::Impl_::_init_inline_$2$_ = " "($3$._instance.$4$.Init(), std::true_type{});\n", ClassName(generator->descriptor_), FieldName(field), DefaultInstanceName(generator->descriptor_, options_), - FieldMemberName(field)); + FieldMemberName(field, ShouldSplit(field, options_))); } } @@ -963,6 +990,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_) { @@ -983,6 +1011,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, @@ -998,6 +1034,7 @@ class FileGenerator::ForwardDeclarations { private: std::map<TProtoStringType, const Descriptor*> classes_; std::map<TProtoStringType, const EnumDescriptor*> enums_; + std::map<TProtoStringType, const Descriptor*> splits_; }; static void PublicImportDFS(const FileDescriptor* fd, @@ -1071,6 +1108,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); diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/file.h index d8eff2feedb..805b4979bf5 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_file.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/file.h @@ -42,10 +42,10 @@ #include <vector> #include <google/protobuf/stubs/common.h> -#include <google/protobuf/compiler/cpp/cpp_field.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/field.h> +#include <google/protobuf/compiler/cpp/helpers.h> #include <google/protobuf/compiler/scc.h> -#include <google/protobuf/compiler/cpp/cpp_options.h> +#include <google/protobuf/compiler/cpp/options.h> namespace google { namespace protobuf { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/generator.cc index 69443f5bf2f..0da2027a1e6 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/generator.cc @@ -32,7 +32,7 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/cpp_generator.h> +#include <google/protobuf/compiler/cpp/generator.h> #include <memory> #include <string> @@ -42,8 +42,8 @@ #include <google/protobuf/stubs/strutil.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/io/zero_copy_stream.h> -#include <google/protobuf/compiler/cpp/cpp_file.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/file.h> +#include <google/protobuf/compiler/cpp/helpers.h> #include <google/protobuf/descriptor.pb.h> namespace google { @@ -135,12 +135,12 @@ bool CppGenerator::Generate(const FileDescriptor* file, .insert(options[i].second.substr(pos, next_pos - pos)); pos = next_pos + 1; } while (pos < options[i].second.size()); - } else if (options[i].first == "verified_lazy_message_sets") { - file_options.unverified_lazy_message_sets = false; + } else if (options[i].first == "verified_lazy") { + file_options.unverified_lazy = false; } else if (options[i].first == "unverified_lazy_message_sets") { file_options.unverified_lazy_message_sets = true; - } else if (options[i].first == "eagerly_verified_lazy") { - file_options.eagerly_verified_lazy = true; + } else if (options[i].first == "message_owned_arena_trial") { + file_options.message_owned_arena_trial = true; } else if (options[i].first == "force_eagerly_verified_lazy") { file_options.force_eagerly_verified_lazy = true; } else if (options[i].first == "experimental_tail_call_table_mode") { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/generator.h index aa63845d300..aa63845d300 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_generator.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/generator.h diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/helpers.cc index f726d0fc9b5..48879f29d57 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/helpers.cc @@ -32,12 +32,13 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/helpers.h> #include <cstdint> #include <functional> #include <limits> #include <map> +#include <memory> #include <queue> #include <unordered_set> #include <vector> @@ -45,8 +46,8 @@ #include <google/protobuf/stubs/common.h> #include <google/protobuf/stubs/logging.h> #include <google/protobuf/descriptor.h> -#include <google/protobuf/compiler/cpp/cpp_names.h> -#include <google/protobuf/compiler/cpp/cpp_options.h> +#include <google/protobuf/compiler/cpp/names.h> +#include <google/protobuf/compiler/cpp/options.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/compiler/scc.h> #include <google/protobuf/io/printer.h> @@ -182,18 +183,53 @@ void SetIntVar(const Options& options, const TProtoStringType& type, std::map<TProtoStringType, TProtoStringType>* variables) { (*variables)[type] = IntTypeName(options, type); } -bool IsEagerlyVerifiedLazyImpl(const FieldDescriptor* field, - const Options& options, - MessageSCCAnalyzer* scc_analyzer) { + +// Returns true if the message can potentially allocate memory for its field. +// This is used to determine if message-owned arena will be useful. +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<arc_i32>(t) - + static_cast<arc_i32>(VerifyInt32Type::kCustom)]; +} + } // namespace bool IsLazy(const FieldDescriptor* field, const Options& options, MessageSCCAnalyzer* scc_analyzer) { return IsLazilyVerifiedLazy(field, options) || - IsEagerlyVerifiedLazyImpl(field, options, scc_analyzer); + IsEagerlyVerifiedLazy(field, options, scc_analyzer); +} + +// Returns true if "field" is a message field that is backed by LazyField per +// profile (go/pdlazy). +inline bool IsEagerlyVerifiedLazyByProfile(const FieldDescriptor* field, + const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + return false; +} + +bool IsEagerlyVerifiedLazy(const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer) { + return false; +} + +bool IsLazilyVerifiedLazy(const FieldDescriptor* field, + const Options& options) { + return false; } void SetCommonVars(const Options& options, @@ -234,15 +270,20 @@ void SetCommonVars(const Options& options, } void SetCommonMessageDataVariables( + const Descriptor* descriptor, std::map<TProtoStringType, TProtoStringType>* variables) { - (*variables)["any_metadata"] = "_any_metadata_"; - (*variables)["cached_size"] = "_cached_size_"; - (*variables)["extensions"] = "_extensions_"; - (*variables)["has_bits"] = "_has_bits_"; - (*variables)["inlined_string_donated_array"] = "_inlined_string_donated_"; - (*variables)["oneof_case"] = "_oneof_case_"; - (*variables)["tracker"] = "_tracker_"; - (*variables)["weak_field_map"] = "_weak_field_map_"; + TProtoStringType prefix = IsMapEntryMessage(descriptor) ? "" : "_impl_."; + (*variables)["any_metadata"] = prefix + "_any_metadata_"; + (*variables)["cached_size"] = prefix + "_cached_size_"; + (*variables)["extensions"] = prefix + "_extensions_"; + (*variables)["has_bits"] = prefix + "_has_bits_"; + (*variables)["inlined_string_donated_array"] = + prefix + "_inlined_string_donated_"; + (*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, @@ -407,29 +448,32 @@ TProtoStringType Namespace(const EnumDescriptor* d, const Options& options) { } TProtoStringType DefaultInstanceType(const Descriptor* descriptor, - const Options& options) { - return ClassName(descriptor) + "DefaultTypeInternal"; + const Options& /*options*/, bool split) { + return ClassName(descriptor) + (split ? "__Impl_Split" : "") + + "DefaultTypeInternal"; } TProtoStringType 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_"; } TProtoStringType DefaultInstancePtr(const Descriptor* descriptor, - const Options& options) { - return DefaultInstanceName(descriptor, options) + "ptr_"; + const Options& options, bool split) { + return DefaultInstanceName(descriptor, options, split) + "ptr_"; } TProtoStringType 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); } TProtoStringType QualifiedDefaultInstancePtr(const Descriptor* descriptor, - const Options& options) { - return QualifiedDefaultInstanceName(descriptor, options) + "ptr_"; + const Options& options, bool split) { + return QualifiedDefaultInstanceName(descriptor, options, split) + "ptr_"; } TProtoStringType DescriptorTableName(const FileDescriptor* file, @@ -469,12 +513,17 @@ TProtoStringType FieldName(const FieldDescriptor* field) { return result; } -TProtoStringType FieldMemberName(const FieldDescriptor* field) { +TProtoStringType 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(FieldName(field), "_"); + return StrCat(prefix, split_prefix, FieldName(field), "_"); } - return StrCat(field->containing_oneof()->name(), "_.", FieldName(field), - "_"); + // Oneof fields are never split. + GOOGLE_CHECK(!split); + return StrCat(prefix, field->containing_oneof()->name(), "_.", + FieldName(field), "_"); } TProtoStringType OneofCaseConstantName(const FieldDescriptor* field) { @@ -855,6 +904,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) { @@ -991,6 +1043,16 @@ bool ShouldVerify(const FileDescriptor* file, const Options& options, return false; } +bool IsUtf8String(const FieldDescriptor* field) { + return IsProto3(field->file()) && + field->type() == FieldDescriptor::TYPE_STRING; +} + +VerifySimpleType ShouldVerifySimple(const Descriptor* descriptor) { + (void)descriptor; + return VerifySimpleType::kCustom; +} + bool IsStringOrMessage(const FieldDescriptor* field) { switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_INT32: @@ -1509,12 +1571,32 @@ FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file, return FileOptions::SPEED; } +inline bool IsMessageOwnedArenaEligible(const Descriptor* desc, + const Options& options) { + return GetOptimizeFor(desc->file(), options) != FileOptions::LITE_RUNTIME && + !options.bootstrap && !options.opensource_runtime && + AllocExpected(desc); +} + bool EnableMessageOwnedArena(const Descriptor* desc, const Options& options) { (void)desc; (void)options; return false; } +bool EnableMessageOwnedArenaTrial(const Descriptor* desc, + const Options& options) { + return false; +} + +bool HasMessageFieldOrExtension(const Descriptor* desc) { + if (desc->extension_range_count() > 0) return true; + for (const auto* f : FieldRange(desc)) { + if (f->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) return true; + } + return false; +} + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/helpers.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/helpers.h new file mode 100644 index 00000000000..690a577591e --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/helpers.h @@ -0,0 +1,1065 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: [email protected] (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ +#define GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ + +#include <algorithm> +#include <cstdint> +#include <iterator> +#include <map> +#include <string> + +#include <google/protobuf/compiler/scc.h> +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/compiler/cpp/names.h> +#include <google/protobuf/compiler/cpp/options.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/port.h> +#include <google/protobuf/stubs/strutil.h> + +// Must be included last. +#include <google/protobuf/port_def.inc> + +namespace google { +namespace protobuf { +namespace compiler { +namespace cpp { + +enum class ArenaDtorNeeds { kNone = 0, kOnDemand = 1, kRequired = 2 }; + +inline TProtoStringType ProtobufNamespace(const Options& /* options */) { + return "PROTOBUF_NAMESPACE_ID"; +} + +inline TProtoStringType MacroPrefix(const Options& /* options */) { + return "GOOGLE_PROTOBUF"; +} + +inline TProtoStringType DeprecatedAttribute(const Options& /* options */, + const FieldDescriptor* d) { + return d->options().deprecated() ? "PROTOBUF_DEPRECATED " : ""; +} + +inline TProtoStringType DeprecatedAttribute(const Options& /* options */, + const EnumValueDescriptor* d) { + return d->options().deprecated() ? "PROTOBUF_DEPRECATED_ENUM " : ""; +} + +// Commonly-used separator comments. Thick is a line of '=', thin is a line +// of '-'. +extern const char kThickSeparator[]; +extern const char kThinSeparator[]; + +void SetCommonVars(const Options& options, + std::map<TProtoStringType, TProtoStringType>* variables); + +// Variables to access message data from the message scope. +void SetCommonMessageDataVariables( + const Descriptor* descriptor, + std::map<TProtoStringType, TProtoStringType>* variables); + +void SetUnknownFieldsVariable(const Descriptor* descriptor, + const Options& options, + std::map<TProtoStringType, TProtoStringType>* variables); + +bool GetBootstrapBasename(const Options& options, const TProtoStringType& basename, + TProtoStringType* bootstrap_basename); +bool MaybeBootstrap(const Options& options, GeneratorContext* generator_context, + bool bootstrap_flag, TProtoStringType* basename); +bool IsBootstrapProto(const Options& options, const FileDescriptor* file); + +// Name space of the proto file. This namespace is such that the string +// "<namespace>::some_name" is the correct fully qualified namespace. +// This means if the package is empty the namespace is "", and otherwise +// the namespace is "::foo::bar::...::baz" without trailing semi-colons. +TProtoStringType Namespace(const FileDescriptor* d, const Options& options); +TProtoStringType Namespace(const Descriptor* d, const Options& options); +TProtoStringType Namespace(const FieldDescriptor* d, const Options& options); +TProtoStringType Namespace(const EnumDescriptor* d, const Options& options); + +// Returns true if it's safe to reset "field" to zero. +bool CanInitializeByZeroing(const FieldDescriptor* field); + +TProtoStringType ClassName(const Descriptor* descriptor); +TProtoStringType ClassName(const EnumDescriptor* enum_descriptor); + +TProtoStringType QualifiedClassName(const Descriptor* d, const Options& options); +TProtoStringType QualifiedClassName(const EnumDescriptor* d, const Options& options); + +TProtoStringType QualifiedClassName(const Descriptor* d); +TProtoStringType QualifiedClassName(const EnumDescriptor* d); + +// DEPRECATED just use ClassName or QualifiedClassName, a boolean is very +// unreadable at the callsite. +// Returns the non-nested type name for the given type. If "qualified" is +// true, prefix the type with the full namespace. For example, if you had: +// package foo.bar; +// message Baz { message Moo {} } +// Then the qualified ClassName for Moo would be: +// ::foo::bar::Baz_Moo +// While the non-qualified version would be: +// Baz_Moo +inline TProtoStringType ClassName(const Descriptor* descriptor, bool qualified) { + return qualified ? QualifiedClassName(descriptor, Options()) + : ClassName(descriptor); +} + +inline TProtoStringType ClassName(const EnumDescriptor* descriptor, bool qualified) { + return qualified ? QualifiedClassName(descriptor, Options()) + : ClassName(descriptor); +} + +// Returns the extension name prefixed with the class name if nested but without +// the package name. +TProtoStringType ExtensionName(const FieldDescriptor* d); + +TProtoStringType QualifiedExtensionName(const FieldDescriptor* d, + const Options& options); +TProtoStringType QualifiedExtensionName(const FieldDescriptor* d); + +// Type name of default instance. +TProtoStringType DefaultInstanceType(const Descriptor* descriptor, + const Options& options, bool split = false); + +// Non-qualified name of the default_instance of this message. +TProtoStringType DefaultInstanceName(const Descriptor* descriptor, + 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. +TProtoStringType DefaultInstancePtr(const Descriptor* descriptor, + const Options& options, bool split = false); + +// Fully qualified name of the default_instance of this message. +TProtoStringType QualifiedDefaultInstanceName(const Descriptor* descriptor, + const Options& options, + bool split = false); + +// Fully qualified name of the default instance pointer. +TProtoStringType QualifiedDefaultInstancePtr(const Descriptor* descriptor, + const Options& options, + bool split = false); + +// DescriptorTable variable name. +TProtoStringType DescriptorTableName(const FileDescriptor* file, + const Options& options); + +// When declaring symbol externs from another file, this macro will supply the +// dllexport needed for the target file, if any. +TProtoStringType FileDllExport(const FileDescriptor* file, const Options& options); + +// Name of the base class: google::protobuf::Message or google::protobuf::MessageLite. +TProtoStringType SuperClassName(const Descriptor* descriptor, + const Options& options); + +// Adds an underscore if necessary to prevent conflicting with a keyword. +TProtoStringType ResolveKeyword(const TProtoStringType& name); + +// Get the (unqualified) name that should be used for this field in C++ code. +// The name is coerced to lower-case to emulate proto1 behavior. People +// should be using lowercase-with-underscores style for proto field names +// anyway, so normally this just returns field->name(). +TProtoStringType FieldName(const FieldDescriptor* field); + +// Returns the (unqualified) private member name for this field in C++ code. +TProtoStringType 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 +// different systems with different alignment rules. The estimates below assume +// 64-bit pointers. +int EstimateAlignmentSize(const FieldDescriptor* field); + +// Get the unqualified name that should be used for a field's field +// number constant. +TProtoStringType FieldConstantName(const FieldDescriptor* field); + +// Returns the scope where the field was defined (for extensions, this is +// different from the message type to which the field applies). +inline const Descriptor* FieldScope(const FieldDescriptor* field) { + return field->is_extension() ? field->extension_scope() + : field->containing_type(); +} + +// Returns the fully-qualified type name field->message_type(). Usually this +// is just ClassName(field->message_type(), true); +TProtoStringType FieldMessageTypeName(const FieldDescriptor* field, + const Options& options); + +// Get the C++ type name for a primitive type (e.g. "double", "::google::protobuf::int32", etc.). +const char* PrimitiveTypeName(FieldDescriptor::CppType type); +TProtoStringType PrimitiveTypeName(const Options& options, + FieldDescriptor::CppType type); + +// Get the declared type name in CamelCase format, as is used e.g. for the +// methods of WireFormat. For example, TYPE_INT32 becomes "Int32". +const char* DeclaredTypeMethodName(FieldDescriptor::Type type); + +// Return the code that evaluates to the number when compiled. +TProtoStringType Int32ToString(int number); + +// Get code that evaluates to the field's default value. +TProtoStringType DefaultValue(const Options& options, const FieldDescriptor* field); + +// Compatibility function for callers outside proto2. +TProtoStringType DefaultValue(const FieldDescriptor* field); + +// Convert a file name into a valid identifier. +TProtoStringType FilenameIdentifier(const TProtoStringType& filename); + +// For each .proto file generates a unique name. To prevent collisions of +// symbols in the global namespace +TProtoStringType UniqueName(const TProtoStringType& name, const TProtoStringType& filename, + const Options& options); +inline TProtoStringType UniqueName(const TProtoStringType& name, const FileDescriptor* d, + const Options& options) { + return UniqueName(name, d->name(), options); +} +inline TProtoStringType UniqueName(const TProtoStringType& name, const Descriptor* d, + const Options& options) { + return UniqueName(name, d->file(), options); +} +inline TProtoStringType UniqueName(const TProtoStringType& name, const EnumDescriptor* d, + const Options& options) { + return UniqueName(name, d->file(), options); +} +inline TProtoStringType UniqueName(const TProtoStringType& name, + const ServiceDescriptor* d, + const Options& options) { + return UniqueName(name, d->file(), options); +} + +// Versions for call sites that only support the internal runtime (like proto1 +// support). +inline Options InternalRuntimeOptions() { + Options options; + options.opensource_runtime = false; + return options; +} +inline TProtoStringType UniqueName(const TProtoStringType& name, + const TProtoStringType& filename) { + return UniqueName(name, filename, InternalRuntimeOptions()); +} +inline TProtoStringType UniqueName(const TProtoStringType& name, + const FileDescriptor* d) { + return UniqueName(name, d->name(), InternalRuntimeOptions()); +} +inline TProtoStringType UniqueName(const TProtoStringType& name, const Descriptor* d) { + return UniqueName(name, d->file(), InternalRuntimeOptions()); +} +inline TProtoStringType UniqueName(const TProtoStringType& name, + const EnumDescriptor* d) { + return UniqueName(name, d->file(), InternalRuntimeOptions()); +} +inline TProtoStringType UniqueName(const TProtoStringType& name, + const ServiceDescriptor* d) { + return UniqueName(name, d->file(), InternalRuntimeOptions()); +} + +// Return the qualified C++ name for a file level symbol. +TProtoStringType QualifiedFileLevelSymbol(const FileDescriptor* file, + const TProtoStringType& name, + const Options& options); + +// Escape C++ trigraphs by escaping question marks to \? +TProtoStringType EscapeTrigraphs(const TProtoStringType& to_escape); + +// Escaped function name to eliminate naming conflict. +TProtoStringType SafeFunctionName(const Descriptor* descriptor, + const FieldDescriptor* field, + const TProtoStringType& prefix); + +// Returns true if generated messages have public unknown fields accessors +inline bool PublicUnknownFieldsAccessors(const Descriptor* message) { + return message->file()->syntax() != FileDescriptor::SYNTAX_PROTO3; +} + +// Returns the optimize mode for <file>, respecting <options.enforce_lite>. +FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file, + const Options& options); + +// Determines whether unknown fields will be stored in an UnknownFieldSet or +// a string. +inline bool UseUnknownFieldSet(const FileDescriptor* file, + const Options& options) { + return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME; +} + +inline bool IsWeak(const FieldDescriptor* field, const Options& options) { + if (field->options().weak()) { + GOOGLE_CHECK(!options.opensource_runtime); + return true; + } + return false; +} + +bool IsStringInlined(const FieldDescriptor* descriptor, const Options& options); + +// For a string field, returns the effective ctype. If the actual ctype is +// not supported, returns the default of STRING. +FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field, + const Options& options); + +inline bool IsCord(const FieldDescriptor* field, const Options& options) { + return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && + EffectiveStringCType(field, options) == FieldOptions::CORD; +} + +inline bool IsString(const FieldDescriptor* field, const Options& options) { + return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && + EffectiveStringCType(field, options) == FieldOptions::STRING; +} + +inline bool IsStringPiece(const FieldDescriptor* field, + const Options& options) { + return field->cpp_type() == FieldDescriptor::CPPTYPE_STRING && + EffectiveStringCType(field, options) == FieldOptions::STRING_PIECE; +} + +class MessageSCCAnalyzer; + +// Does the given FileDescriptor use lazy fields? +bool HasLazyFields(const FileDescriptor* file, const Options& options, + MessageSCCAnalyzer* scc_analyzer); + +// Is the given field a supported lazy field? +bool IsLazy(const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer); + +// Is this an explicit (non-profile driven) lazy field, as denoted by +// lazy/unverified_lazy in the descriptor? +inline bool IsExplicitLazy(const FieldDescriptor* field) { + return field->options().lazy() || field->options().unverified_lazy(); +} + +bool IsEagerlyVerifiedLazy(const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer); + +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; +} + +// Returns true if "field" is stripped. +inline bool IsFieldStripped(const FieldDescriptor* /*field*/, + const Options& /*options*/) { + return false; +} + +// Does the file contain any definitions that need extension_set.h? +bool HasExtensionsOrExtendableMessage(const FileDescriptor* file); + +// Does the file have any repeated fields, necessitating the file to include +// repeated_field.h? This does not include repeated extensions, since those are +// all stored internally in an ExtensionSet, not a separate RepeatedField*. +bool HasRepeatedFields(const FileDescriptor* file); + +// Does the file have any string/bytes fields with ctype=STRING_PIECE? This +// does not include extensions, since ctype is ignored for extensions. +bool HasStringPieceFields(const FileDescriptor* file, const Options& options); + +// Does the file have any string/bytes fields with ctype=CORD? This does not +// include extensions, since ctype is ignored for extensions. +bool HasCordFields(const FileDescriptor* file, const Options& options); + +// Does the file have any map fields, necessitating the file to include +// map_field_inl.h and map.h. +bool HasMapFields(const FileDescriptor* file); + +// Does this file have any enum type definitions? +bool HasEnumDefinitions(const FileDescriptor* file); + +// Does this file have generated parsing, serialization, and other +// standard methods for which reflection-based fallback implementations exist? +inline bool HasGeneratedMethods(const FileDescriptor* file, + const Options& options) { + return GetOptimizeFor(file, options) != FileOptions::CODE_SIZE; +} + +// Do message classes in this file have descriptor and reflection methods? +inline bool HasDescriptorMethods(const FileDescriptor* file, + const Options& options) { + return GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME; +} + +// Should we generate generic services for this file? +inline bool HasGenericServices(const FileDescriptor* file, + const Options& options) { + return file->service_count() > 0 && + GetOptimizeFor(file, options) != FileOptions::LITE_RUNTIME && + file->options().cc_generic_services(); +} + +inline bool IsProto2MessageSet(const Descriptor* descriptor, + const Options& options) { + return !options.opensource_runtime && + options.enforce_mode != EnforceOptimizeMode::kLiteRuntime && + !options.lite_implicit_weak_fields && + descriptor->options().message_set_wire_format() && + descriptor->full_name() == "google.protobuf.bridge.MessageSet"; +} + +inline bool IsMapEntryMessage(const Descriptor* descriptor) { + return descriptor->options().map_entry(); +} + +// Returns true if the field's CPPTYPE is string or message. +bool IsStringOrMessage(const FieldDescriptor* field); + +TProtoStringType UnderscoresToCamelCase(const TProtoStringType& input, + bool cap_next_letter); + +inline bool IsProto3(const FileDescriptor* file) { + return file->syntax() == FileDescriptor::SYNTAX_PROTO3; +} + +inline bool HasHasbit(const FieldDescriptor* field) { + // This predicate includes proto3 message fields only if they have "optional". + // Foo submsg1 = 1; // HasHasbit() == false + // optional Foo submsg2 = 2; // HasHasbit() == true + // This is slightly odd, as adding "optional" to a singular proto3 field does + // not change the semantics or API. However whenever any field in a message + // has a hasbit, it forces reflection to include hasbit offsets for *all* + // fields, even if almost all of them are set to -1 (no hasbit). So to avoid + // causing a sudden size regression for ~all proto3 messages, we give proto3 + // message fields a hasbit only if "optional" is present. If the user is + // explicitly writing "optional", it is likely they are writing it on + // primitive fields also. + return (field->has_optional_keyword() || field->is_required()) && + !field->options().weak(); +} + +// Returns true if 'enum' semantics are such that unknown values are preserved +// in the enum field itself, rather than going to the UnknownFieldSet. +inline bool HasPreservingUnknownEnumSemantics(const FieldDescriptor* field) { + return field->file()->syntax() == FileDescriptor::SYNTAX_PROTO3; +} + +inline bool IsCrossFileMessage(const FieldDescriptor* field) { + return field->type() == FieldDescriptor::TYPE_MESSAGE && + field->message_type()->file() != field->file(); +} + +inline TProtoStringType MakeDefaultName(const FieldDescriptor* field) { + return StrCat("_i_give_permission_to_break_this_code_default_", + FieldName(field), "_"); +} + +// Semantically distinct from MakeDefaultName in that it gives the C++ code +// referencing a default field from the message scope, rather than just the +// variable name. +// For example, declarations of default variables should always use just +// MakeDefaultName to produce code like: +// Type _i_give_permission_to_break_this_code_default_field_; +// +// Code that references these should use MakeDefaultFieldName, in case the field +// exists at some nested level like: +// internal_container_._i_give_permission_to_break_this_code_default_field_; +inline TProtoStringType MakeDefaultFieldName(const FieldDescriptor* field) { + return StrCat("Impl_::", MakeDefaultName(field)); +} + +inline TProtoStringType MakeVarintCachedSizeName(const FieldDescriptor* field) { + return StrCat("_", FieldName(field), "_cached_byte_size_"); +} + +// Semantically distinct from MakeVarintCachedSizeName in that it gives the C++ +// code referencing the object from the message scope, rather than just the +// variable name. +// For example, declarations of default variables should always use just +// MakeVarintCachedSizeName to produce code like: +// Type _field_cached_byte_size_; +// +// Code that references these variables should use +// MakeVarintCachedSizeFieldName, in case the field exists at some nested level +// like: +// internal_container_._field_cached_byte_size_; +inline TProtoStringType 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() +// while the two functions below use FileDescriptor::name(). In a sane world the +// two approaches should be equivalent. But if you are dealing with descriptors +// from untrusted sources, you might need to match semantics across libraries. +bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options); +bool IsAnyMessage(const Descriptor* descriptor, const Options& options); + +bool IsWellKnownMessage(const FileDescriptor* descriptor); + +inline TProtoStringType IncludeGuard(const FileDescriptor* file, bool pb_h, + bool deps, + const Options& options) { + // If we are generating a .pb.h file and the proto_h option is enabled, then + // the .pb.h gets an extra suffix. + TProtoStringType filename_identifier = FilenameIdentifier( + file->name() + (deps ? ".deps": "") + (pb_h && options.proto_h ? ".pb.h" : "")); + + if (IsWellKnownMessage(file)) { + // For well-known messages we need third_party/protobuf and net/proto2 to + // have distinct include guards, because some source files include both and + // both need to be defined (the third_party copies will be in the + // google::protobuf_opensource namespace). + return MacroPrefix(options) + "_INCLUDED_" + filename_identifier; + } else { + // Ideally this case would use distinct include guards for opensource and + // google3 protos also. (The behavior of "first #included wins" is not + // ideal). But unfortunately some legacy code includes both and depends on + // the identical include guards to avoid compile errors. + // + // We should clean this up so that this case can be removed. + return "GOOGLE_PROTOBUF_INCLUDED_" + filename_identifier; + } +} + +// Returns the OptimizeMode for this file, furthermore it updates a status +// bool if has_opt_codesize_extension is non-null. If this status bool is true +// it means this file contains an extension that itself is defined as +// optimized_for = CODE_SIZE. +FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file, + const Options& options, + bool* has_opt_codesize_extension); +inline FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor* file, + const Options& options) { + return GetOptimizeFor(file, options, nullptr); +} +inline bool NeedsEagerDescriptorAssignment(const FileDescriptor* file, + const Options& options) { + bool has_opt_codesize_extension; + if (GetOptimizeFor(file, options, &has_opt_codesize_extension) == + FileOptions::CODE_SIZE && + has_opt_codesize_extension) { + // If this filedescriptor contains an extension from another file which + // is optimized_for = CODE_SIZE. We need to be careful in the ordering so + // we eagerly build the descriptors in the dependencies before building + // the descriptors of this file. + return true; + } else { + // If we have a generated code based parser we never need eager + // initialization of descriptors of our deps. + return false; + } +} + +// This orders the messages in a .pb.cc as it's outputted by file.cc +void FlattenMessagesInFile(const FileDescriptor* file, + std::vector<const Descriptor*>* result); +inline std::vector<const Descriptor*> FlattenMessagesInFile( + const FileDescriptor* file) { + std::vector<const Descriptor*> result; + FlattenMessagesInFile(file, &result); + return result; +} + +template <typename F> +void ForEachMessage(const Descriptor* descriptor, F&& func) { + for (int i = 0; i < descriptor->nested_type_count(); i++) + ForEachMessage(descriptor->nested_type(i), std::forward<F&&>(func)); + func(descriptor); +} + +template <typename F> +void ForEachMessage(const FileDescriptor* descriptor, F&& func) { + for (int i = 0; i < descriptor->message_type_count(); i++) + ForEachMessage(descriptor->message_type(i), std::forward<F&&>(func)); +} + +bool HasWeakFields(const Descriptor* desc, const Options& options); +bool HasWeakFields(const FileDescriptor* desc, const Options& options); + +// Returns true if the "required" restriction check should be ignored for the +// given field. +inline static bool ShouldIgnoreRequiredFieldCheck(const FieldDescriptor* field, + const Options& options) { + // Do not check "required" for lazily verified lazy fields. + return IsLazilyVerifiedLazy(field, options); +} + +struct MessageAnalysis { + bool is_recursive = false; + bool contains_cord = false; + bool contains_extension = false; + bool contains_required = false; + bool contains_weak = false; // Implicit weak as well. +}; + +// This class is used in FileGenerator, to ensure linear instead of +// quadratic performance, if we do this per message we would get O(V*(V+E)). +// Logically this is just only used in message.cc, but in the header for +// FileGenerator to help share it. +class PROTOC_EXPORT MessageSCCAnalyzer { + public: + explicit MessageSCCAnalyzer(const Options& options) : options_(options) {} + + MessageAnalysis GetSCCAnalysis(const SCC* scc); + + bool HasRequiredFields(const Descriptor* descriptor) { + MessageAnalysis result = GetSCCAnalysis(GetSCC(descriptor)); + return result.contains_required || result.contains_extension; + } + bool HasWeakField(const Descriptor* descriptor) { + MessageAnalysis result = GetSCCAnalysis(GetSCC(descriptor)); + return result.contains_weak; + } + const SCC* GetSCC(const Descriptor* descriptor) { + return analyzer_.GetSCC(descriptor); + } + + private: + struct DepsGenerator { + std::vector<const Descriptor*> operator()(const Descriptor* desc) const { + std::vector<const Descriptor*> deps; + for (int i = 0; i < desc->field_count(); i++) { + if (desc->field(i)->message_type()) { + deps.push_back(desc->field(i)->message_type()); + } + } + return deps; + } + }; + SCCAnalyzer<DepsGenerator> analyzer_; + Options options_; + std::map<const SCC*, MessageAnalysis> analysis_cache_; +}; + +void ListAllFields(const Descriptor* d, + std::vector<const FieldDescriptor*>* fields); +void ListAllFields(const FileDescriptor* d, + std::vector<const FieldDescriptor*>* fields); + +template <class T> +void ForEachField(const Descriptor* d, T&& func) { + for (int i = 0; i < d->nested_type_count(); i++) { + ForEachField(d->nested_type(i), std::forward<T&&>(func)); + } + for (int i = 0; i < d->extension_count(); i++) { + func(d->extension(i)); + } + for (int i = 0; i < d->field_count(); i++) { + func(d->field(i)); + } +} + +template <class T> +void ForEachField(const FileDescriptor* d, T&& func) { + for (int i = 0; i < d->message_type_count(); i++) { + ForEachField(d->message_type(i), std::forward<T&&>(func)); + } + for (int i = 0; i < d->extension_count(); i++) { + func(d->extension(i)); + } +} + +void ListAllTypesForServices(const FileDescriptor* fd, + std::vector<const Descriptor*>* types); + +// Indicates whether we should use implicit weak fields for this file. +bool UsingImplicitWeakFields(const FileDescriptor* file, + const Options& options); + +// Indicates whether to treat this field as implicitly weak. +bool IsImplicitWeakField(const FieldDescriptor* field, const Options& options, + MessageSCCAnalyzer* scc_analyzer); + +inline bool HasSimpleBaseClass(const Descriptor* desc, const Options& options) { + if (!HasDescriptorMethods(desc->file(), options)) return false; + if (desc->extension_range_count() != 0) return false; + if (desc->field_count() == 0) return true; + // TODO(jorg): Support additional common message types with only one + // or two fields + return false; +} + +inline bool HasSimpleBaseClasses(const FileDescriptor* file, + const Options& options) { + bool v = false; + ForEachMessage(file, [&v, &options](const Descriptor* desc) { + v |= HasSimpleBaseClass(desc, options); + }); + return v; +} + +inline TProtoStringType SimpleBaseClass(const Descriptor* desc, + const Options& options) { + if (!HasDescriptorMethods(desc->file(), options)) return ""; + if (desc->extension_range_count() != 0) return ""; + if (desc->field_count() == 0) { + return "ZeroFieldsBase"; + } + // TODO(jorg): Support additional common message types with only one + // or two fields + return ""; +} + +// Returns true if this message has a _tracker_ field. +inline bool HasTracker(const Descriptor* desc, const Options& options) { + return options.field_listener_options.inject_field_listener_events && + desc->file()->options().optimize_for() != + google::protobuf::FileOptions::LITE_RUNTIME; +} + +// Returns true if this message needs an Impl_ struct for it's data. +inline bool HasImplData(const Descriptor* desc, const Options& options) { + return !HasSimpleBaseClass(desc, options); +} + +// Formatter is a functor class which acts as a closure around printer and +// the variable map. It's much like printer->Print except it supports both named +// variables that are substituted using a key value map and direct arguments. In +// the format string $1$, $2$, etc... are substituted for the first, second, ... +// direct argument respectively in the format call, it accepts both strings and +// integers. The implementation verifies all arguments are used and are "first" +// used in order of appearance in the argument list. For example, +// +// Format("return array[$1$];", 3) -> "return array[3];" +// Format("array[$2$] = $1$;", "Bla", 3) -> FATAL error (wrong order) +// Format("array[$1$] = $2$;", 3, "Bla") -> "array[3] = Bla;" +// +// The arguments can be used more than once like +// +// Format("array[$1$] = $2$; // Index = $1$", 3, "Bla") -> +// "array[3] = Bla; // Index = 3" +// +// If you use more arguments use the following style to help the reader, +// +// Format("int $1$() {\n" +// " array[$2$] = $3$;\n" +// " return $4$;" +// "}\n", +// funname, // 1 +// idx, // 2 +// varname, // 3 +// retval); // 4 +// +// but consider using named variables. Named variables like $foo$, with some +// identifier foo, are looked up in the map. One additional feature is that +// spaces are accepted between the '$' delimiters, $ foo$ will +// substitute to " bar" if foo stands for "bar", but in case it's empty +// will substitute to "". Hence, for example, +// +// Format(vars, "$dllexport $void fun();") -> "void fun();" +// "__declspec(export) void fun();" +// +// which is convenient to prevent double, leading or trailing spaces. +class PROTOC_EXPORT Formatter { + public: + explicit Formatter(io::Printer* printer) : printer_(printer) {} + Formatter(io::Printer* printer, + const std::map<TProtoStringType, TProtoStringType>& vars) + : printer_(printer), vars_(vars) {} + + template <typename T> + void Set(const TProtoStringType& key, const T& value) { + vars_[key] = ToString(value); + } + + void AddMap(const std::map<TProtoStringType, TProtoStringType>& vars) { + for (const auto& keyval : vars) vars_[keyval.first] = keyval.second; + } + + template <typename... Args> + void operator()(const char* format, const Args&... args) const { + printer_->FormatInternal({ToString(args)...}, vars_, format); + } + + void Indent() const { printer_->Indent(); } + void Outdent() const { printer_->Outdent(); } + io::Printer* printer() const { return printer_; } + + class PROTOC_EXPORT ScopedIndenter { + public: + explicit ScopedIndenter(Formatter* format) : format_(format) { + format_->Indent(); + } + ~ScopedIndenter() { format_->Outdent(); } + + private: + Formatter* format_; + }; + + PROTOBUF_NODISCARD ScopedIndenter ScopedIndent() { + return ScopedIndenter(this); + } + template <typename... Args> + PROTOBUF_NODISCARD ScopedIndenter ScopedIndent(const char* format, + const Args&&... args) { + (*this)(format, static_cast<Args&&>(args)...); + return ScopedIndenter(this); + } + + class PROTOC_EXPORT SaveState { + public: + explicit SaveState(Formatter* format) + : format_(format), vars_(format->vars_) {} + ~SaveState() { format_->vars_.swap(vars_); } + + private: + Formatter* format_; + std::map<TProtoStringType, TProtoStringType> vars_; + }; + + private: + io::Printer* printer_; + std::map<TProtoStringType, TProtoStringType> vars_; + + // Convenience overloads to accept different types as arguments. + static TProtoStringType ToString(const TProtoStringType& s) { return s; } + template <typename I, typename = typename std::enable_if< + std::is_integral<I>::value>::type> + static TProtoStringType ToString(I x) { + return StrCat(x); + } + static TProtoStringType ToString(strings::Hex x) { return StrCat(x); } + static TProtoStringType ToString(const FieldDescriptor* d) { return Payload(d); } + static TProtoStringType ToString(const Descriptor* d) { return Payload(d); } + static TProtoStringType ToString(const EnumDescriptor* d) { return Payload(d); } + static TProtoStringType ToString(const EnumValueDescriptor* d) { + return Payload(d); + } + static TProtoStringType ToString(const OneofDescriptor* d) { return Payload(d); } + + template <typename Descriptor> + static TProtoStringType Payload(const Descriptor* descriptor) { + std::vector<int> path; + descriptor->GetLocationPath(&path); + GeneratedCodeInfo::Annotation annotation; + for (int index : path) { + annotation.add_path(index); + } + annotation.set_source_file(descriptor->file()->name()); + return annotation.SerializeAsString(); + } +}; + +template <class T> +void PrintFieldComment(const Formatter& format, const T* field) { + // Print the field's (or oneof's) proto-syntax definition as a comment. + // We don't want to print group bodies so we cut off after the first + // line. + DebugStringOptions options; + options.elide_group_body = true; + options.elide_oneof_body = true; + TProtoStringType def = field->DebugStringWithOptions(options); + format("// $1$\n", def.substr(0, def.find_first_of('\n'))); +} + +class PROTOC_EXPORT NamespaceOpener { + public: + explicit NamespaceOpener(const Formatter& format) + : printer_(format.printer()) {} + NamespaceOpener(const TProtoStringType& name, const Formatter& format) + : NamespaceOpener(format) { + ChangeTo(name); + } + ~NamespaceOpener() { ChangeTo(""); } + + void ChangeTo(const TProtoStringType& name) { + std::vector<TProtoStringType> new_stack_ = + Split(name, "::", true); + size_t len = std::min(name_stack_.size(), new_stack_.size()); + size_t common_idx = 0; + while (common_idx < len) { + if (name_stack_[common_idx] != new_stack_[common_idx]) break; + common_idx++; + } + for (auto it = name_stack_.crbegin(); + it != name_stack_.crend() - common_idx; ++it) { + if (*it == "PROTOBUF_NAMESPACE_ID") { + printer_->Print("PROTOBUF_NAMESPACE_CLOSE\n"); + } else { + printer_->Print("} // namespace $ns$\n", "ns", *it); + } + } + name_stack_.swap(new_stack_); + for (size_t i = common_idx; i < name_stack_.size(); ++i) { + if (name_stack_[i] == "PROTOBUF_NAMESPACE_ID") { + printer_->Print("PROTOBUF_NAMESPACE_OPEN\n"); + } else { + printer_->Print("namespace $ns$ {\n", "ns", name_stack_[i]); + } + } + } + + private: + io::Printer* printer_; + std::vector<TProtoStringType> name_stack_; +}; + +enum class Utf8CheckMode { + kStrict = 0, // Parsing will fail if non UTF-8 data is in string fields. + kVerify = 1, // Only log an error but parsing will succeed. + kNone = 2, // No UTF-8 check. +}; + +Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor* field, + const Options& options); + +void GenerateUtf8CheckCodeForString(const FieldDescriptor* field, + const Options& options, bool for_parse, + const char* parameters, + const Formatter& format); + +void GenerateUtf8CheckCodeForCord(const FieldDescriptor* field, + const Options& options, bool for_parse, + const char* parameters, + const Formatter& format); + +template <typename T> +struct FieldRangeImpl { + struct Iterator { + using iterator_category = std::forward_iterator_tag; + using value_type = const FieldDescriptor*; + using difference_type = int; + + value_type operator*() { return descriptor->field(idx); } + + friend bool operator==(const Iterator& a, const Iterator& b) { + GOOGLE_DCHECK(a.descriptor == b.descriptor); + return a.idx == b.idx; + } + friend bool operator!=(const Iterator& a, const Iterator& b) { + return !(a == b); + } + + Iterator& operator++() { + idx++; + return *this; + } + + int idx; + const T* descriptor; + }; + + Iterator begin() const { return {0, descriptor}; } + Iterator end() const { return {descriptor->field_count(), descriptor}; } + + const T* descriptor; +}; + +template <typename T> +FieldRangeImpl<T> FieldRange(const T* desc) { + return {desc}; +} + +struct OneOfRangeImpl { + struct Iterator { + using iterator_category = std::forward_iterator_tag; + using value_type = const OneofDescriptor*; + using difference_type = int; + + value_type operator*() { return descriptor->oneof_decl(idx); } + + friend bool operator==(const Iterator& a, const Iterator& b) { + GOOGLE_DCHECK(a.descriptor == b.descriptor); + return a.idx == b.idx; + } + friend bool operator!=(const Iterator& a, const Iterator& b) { + return !(a == b); + } + + Iterator& operator++() { + idx++; + return *this; + } + + int idx; + const Descriptor* descriptor; + }; + + Iterator begin() const { return {0, descriptor}; } + Iterator end() const { + return {descriptor->real_oneof_decl_count(), descriptor}; + } + + const Descriptor* descriptor; +}; + +inline OneOfRangeImpl OneOfRange(const Descriptor* desc) { return {desc}; } + +PROTOC_EXPORT TProtoStringType StripProto(const TProtoStringType& filename); + +bool EnableMessageOwnedArena(const Descriptor* desc, const Options& options); + +bool EnableMessageOwnedArenaTrial(const Descriptor* desc, + const Options& options); + +bool ShouldVerify(const Descriptor* descriptor, const Options& options, + MessageSCCAnalyzer* scc_analyzer); +bool ShouldVerify(const FileDescriptor* file, const Options& options, + MessageSCCAnalyzer* scc_analyzer); + +// 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); + +bool HasMessageFieldOrExtension(const Descriptor* desc); + +} // namespace cpp +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <google/protobuf/port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_CPP_HELPERS_H__ diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/map_field.cc index 4d3e00ac89b..ba363f5267b 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_map_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/map_field.cc @@ -28,12 +28,12 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include <google/protobuf/compiler/cpp/cpp_map_field.h> +#include <google/protobuf/compiler/cpp/map_field.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/helpers.h> namespace google { @@ -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" @@ -153,7 +154,7 @@ void MapFieldGenerator::GenerateClearingCode(io::Printer* printer) const { void MapFieldGenerator::GenerateMergingCode(io::Printer* printer) const { Formatter format(printer, variables_); - format("$field$.MergeFrom(from.$field$);\n"); + format("_this->$field$.MergeFrom(from.$field$);\n"); } void MapFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { @@ -226,8 +227,7 @@ void MapFieldGenerator::GenerateSerializeWithCachedSizesToArray( format); } } - format( - "};\n"); + format("};\n"); } format( @@ -271,21 +271,48 @@ void MapFieldGenerator::GenerateIsInitialized(io::Printer* printer) const { "false;\n"); } -void MapFieldGenerator::GenerateConstinitInitializer( +void MapFieldGenerator::GenerateConstexprAggregateInitializer( io::Printer* printer) const { Formatter format(printer, variables_); if (HasDescriptorMethods(descriptor_->file(), options_)) { - format("$name$_(::$proto_ns$::internal::ConstantInitialized{})"); + format("/*decltype($field$)*/{::_pbi::ConstantInitialized()}"); } else { - format("$name$_()"); + format("/*decltype($field$)*/{}"); + } +} + +void MapFieldGenerator::GenerateCopyAggregateInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + // MapField has no move constructor, which prevents explicit aggregate + // initialization pre-C++17. + format("/*decltype($field$)*/{}"); +} + +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}"); } 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"); } void MapFieldGenerator::GenerateArenaDestructorCode( diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_map_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/map_field.h index 9e71267c0f1..678a128bd18 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_map_field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/map_field.h @@ -34,8 +34,8 @@ #include <map> #include <string> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/compiler/cpp/cpp_message_field.h> +#include <google/protobuf/compiler/cpp/helpers.h> +#include <google/protobuf/compiler/cpp/message_field.h> namespace google { namespace protobuf { @@ -61,7 +61,10 @@ class MapFieldGenerator : public FieldGenerator { io::Printer* printer) const override; void GenerateByteSize(io::Printer* printer) const override; void GenerateIsInitialized(io::Printer* printer) const override; - void GenerateConstinitInitializer(io::Printer* printer) const override; + void GenerateConstexprAggregateInitializer( + io::Printer* printer) const override; + void GenerateCopyAggregateInitializer(io::Printer* printer) const override; + void GenerateAggregateInitializer(io::Printer* printer) const override; void GenerateDestructorCode(io::Printer* printer) const override; void GenerateArenaDestructorCode(io::Printer* printer) const override; ArenaDtorNeeds NeedsArenaDestructor() const override; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message.cc index a56c6fbda1e..77702a68dfc 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message.cc @@ -32,7 +32,7 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/cpp_message.h> +#include <google/protobuf/compiler/cpp/message.h> #include <algorithm> #include <cstdint> @@ -51,13 +51,14 @@ #include <google/protobuf/map_entry_lite.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/stringprintf.h> #include <google/protobuf/stubs/substitute.h> -#include <google/protobuf/compiler/cpp/cpp_enum.h> -#include <google/protobuf/compiler/cpp/cpp_extension.h> -#include <google/protobuf/compiler/cpp/cpp_field.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/compiler/cpp/cpp_padding_optimizer.h> -#include <google/protobuf/compiler/cpp/cpp_parse_function_generator.h> +#include <google/protobuf/compiler/cpp/enum.h> +#include <google/protobuf/compiler/cpp/extension.h> +#include <google/protobuf/compiler/cpp/field.h> +#include <google/protobuf/compiler/cpp/helpers.h> +#include <google/protobuf/compiler/cpp/padding_optimizer.h> +#include <google/protobuf/compiler/cpp/parse_function_generator.h> #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/stubs/hash.h> @@ -83,7 +84,7 @@ static constexpr int kNoHasbit = -1; // masks must be non-zero. TProtoStringType ConditionalToCheckBitmasks( const std::vector<arc_ui32>& masks, bool return_success = true, - StringPiece has_bits_var = "_has_bits_") { + StringPiece has_bits_var = "_impl_._has_bits_") { std::vector<TProtoStringType> parts; for (int i = 0; i < masks.size(); i++) { if (masks[i] == 0) continue; @@ -345,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; } } @@ -403,7 +404,7 @@ static int popcnt(arc_ui32 n) { class ColdChunkSkipper { public: ColdChunkSkipper( - const Options& options, + const Descriptor* descriptor, const Options& options, const std::vector<std::vector<const FieldDescriptor*>>& chunks, const std::vector<int>& has_bit_indices, const double cold_threshold) : chunks_(chunks), @@ -411,7 +412,7 @@ class ColdChunkSkipper { access_info_map_(options.access_info_map), cold_threshold_(cold_threshold) { SetCommonVars(options, &variables_); - SetCommonMessageDataVariables(&variables_); + SetCommonMessageDataVariables(descriptor, &variables_); } // May open an external if check for a batch of cold fields. "from" is the @@ -495,7 +496,7 @@ void ColdChunkSkipper::OnStartChunk(int chunk, int cached_has_word_index, if (this_word == cached_has_word_index) { format("(cached_has_bits & 0x$mask$u) != 0"); } else { - format("($1$_has_bits_[$2$] & 0x$mask$u) != 0", from, this_word); + format("($1$_impl_._has_bits_[$2$] & 0x$mask$u) != 0", from, this_word); } } format(")) {\n"); @@ -547,9 +548,7 @@ void GenerateExtensionAnnotations( for (const auto& annotation : accessor_annotations_to_hooks) { (*variables)[annotation.first] = ""; } - if (!options.field_listener_options.inject_field_listener_events || - descriptor->file()->options().optimize_for() == - google::protobuf::FileOptions::LITE_RUNTIME) { + if (!HasTracker(descriptor, options)) { return; } StringPiece tracker = (*variables)["tracker"]; @@ -617,7 +616,7 @@ MessageGenerator::MessageGenerator( if (!message_layout_helper_) { message_layout_helper_.reset(new PaddingOptimizer()); } - SetCommonMessageDataVariables(&variables_); + SetCommonMessageDataVariables(descriptor, &variables_); // Variables that apply to this class variables_["classname"] = classname_; @@ -630,9 +629,7 @@ MessageGenerator::MessageGenerator( variables_["annotate_bytesize"] = ""; variables_["annotate_mergefrom"] = ""; - if (options.field_listener_options.inject_field_listener_events && - descriptor->file()->options().optimize_for() != - google::protobuf::FileOptions::LITE_RUNTIME) { + if (HasTracker(descriptor_, options_)) { const TProtoStringType injector_template = StrCat(" ", variables_["tracker"], "."); @@ -649,7 +646,7 @@ MessageGenerator::MessageGenerator( MaySetAnnotationVariable(options, "bytesize", injector_template, "OnByteSize(this);\n", &variables_); MaySetAnnotationVariable(options, "mergefrom", injector_template, - "OnMergeFrom(this, &from);\n", &variables_); + "OnMergeFrom(_this, &from);\n", &variables_); } GenerateExtensionAnnotations(descriptor_, options_, &variables_); @@ -1205,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); @@ -1245,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" @@ -1398,6 +1397,11 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { format( "inline $classname$() : $classname$(" "::$proto_ns$::Arena::InternalCreateMessageOwnedArena(), true) {}\n"); + } else if (EnableMessageOwnedArenaTrial(descriptor_, options_)) { + format( + "inline $classname$() : $classname$(InMoaTrial() ? " + "::$proto_ns$::Arena::InternalCreateMessageOwnedArena() : nullptr, " + "InMoaTrial()) {}\n"); } else { format("inline $classname$() : $classname$(nullptr) {}\n"); } @@ -1510,11 +1514,13 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { if (HasDescriptorMethods(descriptor_->file(), options_)) { format( "bool PackFrom(const ::$proto_ns$::Message& message) {\n" + " $DCHK$_NE(&message, this);\n" " return $any_metadata$.PackFrom(GetArena(), message);\n" "}\n" "bool PackFrom(const ::$proto_ns$::Message& message,\n" " ::PROTOBUF_NAMESPACE_ID::ConstStringParam " "type_url_prefix) {\n" + " $DCHK$_NE(&message, this);\n" " return $any_metadata$.PackFrom(GetArena(), message, " "type_url_prefix);\n" "}\n" @@ -1618,27 +1624,28 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { // argument is a generic Message instance, and only define the // custom MergeFrom and CopyFrom instances when the source of the // merge/copy is known to be the same class as the destination. - // TODO(jorg): Define MergeFrom in terms of MergeImpl, rather than - // the other way around, to save even more code size. "using $superclass$::CopyFrom;\n" "void CopyFrom(const $classname$& from);\n" "" "using $superclass$::MergeFrom;\n" - "void MergeFrom(const $classname$& from);\n" + "void MergeFrom(" + " const $classname$& from) {\n" + " $classname$::MergeImpl(*this, from);\n" + "}\n" "private:\n" - "static void MergeImpl(::$proto_ns$::Message* to, const " - "::$proto_ns$::Message& from);\n" + "static void MergeImpl(::$proto_ns$::Message& to_msg, const " + "::$proto_ns$::Message& from_msg);\n" "public:\n"); } else { format( "using $superclass$::CopyFrom;\n" "inline void CopyFrom(const $classname$& from) {\n" - " $superclass$::CopyImpl(this, from);\n" + " $superclass$::CopyImpl(*this, from);\n" "}\n" "" "using $superclass$::MergeFrom;\n" "void MergeFrom(const $classname$& from) {\n" - " $superclass$::MergeImpl(this, from);\n" + " $superclass$::MergeImpl(*this, from);\n" "}\n" "public:\n"); } @@ -1676,7 +1683,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "int GetCachedSize() const final { return " "$cached_size$.Get(); }" "\n\nprivate:\n" - "void SharedCtor();\n" + "void SharedCtor(::$proto_ns$::Arena* arena, bool is_message_owned);\n" "void SharedDtor();\n" "void SetCachedSize(int size) const$ full_final$;\n" "void InternalSwap($classname$* other);\n"); @@ -1747,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"); @@ -1837,12 +1855,21 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { : StrCat("::$proto_ns$::internal::HasBits<", sizeof_has_bits, "> _has_bits_;\n"); + format( + "template <typename T> friend class " + "::$proto_ns$::Arena::InternalHelper;\n" + "typedef void InternalArenaConstructable_;\n" + "typedef void DestructorSkippable_;\n"); + // To minimize padding, data members are divided into three sections: // (1) members assumed to align to 8 bytes // (2) members corresponding to message fields, re-ordered to optimize // alignment. // (3) members assumed to align to 4 bytes. + format("struct Impl_ {\n"); + format.Indent(); + // Members assumed to align to 8 bytes: if (descriptor_->extension_range_count() > 0) { @@ -1851,9 +1878,7 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { "\n"); } - if (options_.field_listener_options.inject_field_listener_events && - descriptor_->file()->options().optimize_for() != - google::protobuf::FileOptions::LITE_RUNTIME) { + if (HasTracker(descriptor_, options_)) { format("static ::$proto_ns$::AccessListener<$1$> _tracker_;\n", ClassName(descriptor_)); } @@ -1866,12 +1891,6 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { InlinedStringDonatedSize()); } - format( - "template <typename T> friend class " - "::$proto_ns$::Arena::InternalHelper;\n" - "typedef void InternalArenaConstructable_;\n" - "typedef void DestructorSkippable_;\n"); - if (!has_bit_indices_.empty()) { // _has_bits_ is frequently accessed, so to reduce code size and improve // speed, it should be close to the start of the object. Placing @@ -1890,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 @@ -1941,6 +1977,22 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* printer) { format("::$proto_ns$::internal::AnyMetadata _any_metadata_;\n"); } + format.Outdent(); + format("};\n"); + + // Only create the _impl_ field if it contains data. + if (HasImplData(descriptor_, options_)) { + 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"); @@ -2080,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); } } @@ -2130,7 +2183,7 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { GenerateMergeFrom(printer); format("\n"); - GenerateClassSpecificMergeFrom(printer); + GenerateClassSpecificMergeImpl(printer); format("\n"); GenerateCopyFrom(printer); @@ -2140,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); @@ -2172,9 +2234,7 @@ void MessageGenerator::GenerateClassMethods(io::Printer* printer) { "\n"); } - if (options_.field_listener_options.inject_field_listener_events && - descriptor_->file()->options().optimize_for() != - google::protobuf::FileOptions::LITE_RUNTIME) { + if (HasTracker(descriptor_, options_)) { format( "::$proto_ns$::AccessListener<$classtype$> " "$1$::$tracker$(&FullMessageName);\n", @@ -2230,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 @@ -2250,7 +2314,7 @@ std::pair<size_t, size_t> MessageGenerator::GenerateOffsets( int count = 0; for (auto oneof : OneOfRange(descriptor_)) { - format("PROTOBUF_FIELD_OFFSET($classtype$, $1$_),\n", oneof->name()); + format("PROTOBUF_FIELD_OFFSET($classtype$, _impl_.$1$_),\n", oneof->name()); count++; } GOOGLE_CHECK_EQ(count, descriptor_->real_oneof_decl_count()); @@ -2286,18 +2350,181 @@ void MessageGenerator::GenerateSharedConstructorCode(io::Printer* printer) { if (HasSimpleBaseClass(descriptor_, options_)) return; Formatter format(printer, variables_); - format("inline void $classname$::SharedCtor() {\n"); + format( + "inline void $classname$::SharedCtor(\n" + " ::_pb::Arena* arena, bool is_message_owned) {\n" + " (void)arena;\n" + " (void)is_message_owned;\n"); - std::vector<bool> processed(optimized_order_.size(), false); - GenerateConstructorBody(printer, processed, false); + format.Indent(); + // Impl_ _impl_. + format("new (&_impl_) Impl_{"); + format.Indent(); + const char* field_sep = " "; + const auto put_sep = [&] { + format("\n$1$ ", field_sep); + field_sep = ","; + }; + + // Note: any fields without move/copy constructors can't be explicitly + // aggregate initialized pre-C++17. + if (descriptor_->extension_range_count() > 0) { + put_sep(); + format("/*decltype($extensions$)*/{::_pbi::ArenaInitialized(), arena}"); + } + if (!inlined_string_indices_.empty()) { + put_sep(); + format("decltype($inlined_string_donated_array$){}"); + } + bool need_to_emit_cached_size = !HasSimpleBaseClass(descriptor_, options_); + if (!has_bit_indices_.empty()) { + put_sep(); + format("decltype($has_bits$){}"); + if (need_to_emit_cached_size) { + put_sep(); + format("/*decltype($cached_size$)*/{}"); + need_to_emit_cached_size = false; + } + } + + // 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()); + } + + if (need_to_emit_cached_size) { + put_sep(); + format("/*decltype($cached_size$)*/{}"); + } + + if (descriptor_->real_oneof_decl_count() != 0) { + put_sep(); + format("/*decltype($oneof_case$)*/{}"); + } + if (num_weak_fields_ > 0) { + put_sep(); + format("decltype($weak_field_map$){arena}"); + } + if (IsAnyMessage(descriptor_, options_)) { + put_sep(); + // AnyMetadata has no move constructor. + format("/*decltype($any_metadata$)*/{&_impl_.type_url_, &_impl_.value_}"); + } + + format.Outdent(); + format("\n};\n"); + + if (!inlined_string_indices_.empty()) { + // Donate inline string fields. + format.Indent(); + // The last bit is the tracking bit for registering ArenaDtor. The bit is 1 + // means ArenaDtor is not registered on construction, and on demand register + // is needed. + format("if (arena != nullptr) {\n"); + if (NeedsArenaDestructor() == ArenaDtorNeeds::kOnDemand) { + format( + " if (!is_message_owned) {\n" + " $inlined_string_donated_array$[0] = ~0u;\n" + " } else {\n" + // We should not register ArenaDtor for MOA. + " $inlined_string_donated_array$[0] = 0xFFFFFFFEu;\n" + " }\n"); + } else { + format(" $inlined_string_donated_array$[0] = 0xFFFFFFFEu;\n"); + } + for (size_t i = 1; i < InlinedStringDonatedSize(); ++i) { + format(" $inlined_string_donated_array$[$1$] = ~0u;\n", i); + } + format("}\n"); + format.Outdent(); + } + + for (const FieldDescriptor* field : optimized_order_) { + if (ShouldSplit(field, options_)) { + continue; + } + field_generators_.get(field).GenerateConstructorCode(printer); + } for (auto oneof : OneOfRange(descriptor_)) { format("clear_has_$1$();\n", oneof->name()); } + format.Outdent(); 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_); @@ -2305,11 +2532,32 @@ void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) { format("inline void $classname$::SharedDtor() {\n"); format.Indent(); format("$DCHK$(GetArenaForAllocation() == nullptr);\n"); + + if (descriptor_->extension_range_count() > 0) { + format("$extensions$.~ExtensionSet();\n"); + } + // 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_)) { @@ -2323,6 +2571,11 @@ void MessageGenerator::GenerateSharedDestructorCode(io::Printer* printer) { if (num_weak_fields_) { format("$weak_field_map$.ClearAll();\n"); } + + if (IsAnyMessage(descriptor_, options_)) { + format("$any_metadata$.~AnyMetadata();\n"); + } + format.Outdent(); format( "}\n" @@ -2358,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_)) { @@ -2378,72 +2644,118 @@ void MessageGenerator::GenerateArenaDestructorCode(io::Printer* printer) { void MessageGenerator::GenerateConstexprConstructor(io::Printer* printer) { Formatter format(printer, variables_); + if (IsMapEntryMessage(descriptor_) || !HasImplData(descriptor_, options_)) { + format( + "PROTOBUF_CONSTEXPR $classname$::$classname$(\n" + " ::_pbi::ConstantInitialized) {}\n"); + return; + } + format( "PROTOBUF_CONSTEXPR $classname$::$classname$(\n" " ::_pbi::ConstantInitialized)"); + + bool need_to_emit_cached_size = !HasSimpleBaseClass(descriptor_, options_); + format(": _impl_{"); format.Indent(); - const char* field_sep = ":"; + const char* field_sep = " "; const auto put_sep = [&] { format("\n$1$ ", field_sep); field_sep = ","; }; - - if (!IsMapEntryMessage(descriptor_)) { - // Process non-oneof fields first. - for (auto field : optimized_order_) { - auto& gen = field_generators_.get(field); + if (descriptor_->extension_range_count() > 0) { + put_sep(); + format("/*decltype($extensions$)*/{}"); + } + if (!inlined_string_indices_.empty()) { + put_sep(); + format("/*decltype($inlined_string_donated_array$)*/{}"); + } + if (!has_bit_indices_.empty()) { + put_sep(); + format("/*decltype($has_bits$)*/{}"); + if (need_to_emit_cached_size) { put_sep(); - gen.GenerateConstinitInitializer(printer); + format("/*decltype($cached_size$)*/{}"); + need_to_emit_cached_size = false; } - - if (IsAnyMessage(descriptor_, options_)) { - put_sep(); - format("_any_metadata_(&type_url_, &value_)"); + } + for (auto field : optimized_order_) { + if (ShouldSplit(field, options_)) { + continue; } + put_sep(); + field_generators_.get(field).GenerateConstexprAggregateInitializer( + printer); + } + if (ShouldSplit(descriptor_, options_)) { + put_sep(); + format("/*decltype($split$)*/&$1$._instance", + DefaultInstanceName(descriptor_, options_, /*split=*/true)); + } - if (descriptor_->real_oneof_decl_count() != 0) { - put_sep(); - format("_oneof_case_{}"); - } + for (auto oneof : OneOfRange(descriptor_)) { + put_sep(); + format("/*decltype(_impl_.$1$_)*/{}", oneof->name()); + } + + if (need_to_emit_cached_size) { + put_sep(); + format("/*decltype($cached_size$)*/{}"); + } + + if (descriptor_->real_oneof_decl_count() != 0) { + put_sep(); + format("/*decltype($oneof_case$)*/{}"); + } + + if (num_weak_fields_) { + put_sep(); + format("/*decltype($weak_field_map$)*/{}"); + } + + if (IsAnyMessage(descriptor_, options_)) { + put_sep(); + format( + "/*decltype($any_metadata$)*/{&_impl_.type_url_, " + "&_impl_.value_}"); } format.Outdent(); - format("{}\n"); + format("} {}\n"); } -void MessageGenerator::GenerateConstructorBody(io::Printer* printer, - std::vector<bool> processed, - bool copy_constructor) const { +void MessageGenerator::GenerateCopyConstructorBody(io::Printer* printer) const { Formatter format(printer, variables_); - const RunMap runs = FindRuns( - optimized_order_, [copy_constructor, this](const FieldDescriptor* field) { - return (copy_constructor && IsPOD(field)) || - (!copy_constructor && - CanBeManipulatedAsRawBytes(field, options_, scc_analyzer_)); + const RunMap runs = + FindRuns(optimized_order_, [this](const FieldDescriptor* field) { + return IsPOD(field) && !ShouldSplit(field, options_); }); - TProtoStringType pod_template; - if (copy_constructor) { - pod_template = - "::memcpy(&$first$, &from.$first$,\n" - " static_cast<size_t>(reinterpret_cast<char*>(&$last$) -\n" - " reinterpret_cast<char*>(&$first$)) + sizeof($last$));\n"; - } else { - pod_template = - "::memset(reinterpret_cast<char*>(this) + static_cast<size_t>(\n" - " reinterpret_cast<char*>(&$first$) - " - "reinterpret_cast<char*>(this)),\n" - " 0, static_cast<size_t>(reinterpret_cast<char*>(&$last$) -\n" - " reinterpret_cast<char*>(&$first$)) + sizeof($last$));\n"; - } + TProtoStringType pod_template = + "::memcpy(&$first$, &from.$first$,\n" + " static_cast<size_t>(reinterpret_cast<char*>(&$last$) -\n" + " reinterpret_cast<char*>(&$first$)) + sizeof($last$));\n"; - for (int i = 0; i < optimized_order_.size(); ++i) { - if (processed[i]) { - continue; + 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 @@ -2451,9 +2763,10 @@ void MessageGenerator::GenerateConstructorBody(io::Printer* printer, if (it != runs.end() && it->second > 1) { // Use a memset, then skip run_length fields. const size_t run_length = it->second; - const TProtoStringType first_field_name = FieldMemberName(field); + const TProtoStringType first_field_name = + FieldMemberName(field, /*cold=*/false); const TProtoStringType 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); @@ -2463,11 +2776,7 @@ void MessageGenerator::GenerateConstructorBody(io::Printer* printer, i += run_length - 1; // ++i at the top of the loop. } else { - if (copy_constructor) { - field_generators_.get(field).GenerateCopyConstructorCode(printer); - } else { - field_generators_.get(field).GenerateConstructorCode(printer); - } + field_generators_.get(field).GenerateCopyConstructorCode(printer); } } } @@ -2475,78 +2784,14 @@ void MessageGenerator::GenerateConstructorBody(io::Printer* printer, void MessageGenerator::GenerateStructors(io::Printer* printer) { Formatter format(printer, variables_); - TProtoStringType superclass; - superclass = SuperClassName(descriptor_, options_); - TProtoStringType initializer_with_arena = superclass + "(arena, is_message_owned)"; - - if (descriptor_->extension_range_count() > 0) { - initializer_with_arena += ",\n _extensions_(arena)"; - } - - // Initialize member variables with arena constructor. - for (auto field : optimized_order_) { - GOOGLE_DCHECK(!IsFieldStripped(field, options_)); - bool has_arena_constructor = field->is_repeated(); - if (!field->real_containing_oneof() && - (IsLazy(field, options_, scc_analyzer_) || - IsStringPiece(field, options_) || - (IsString(field, options_) && IsStringInlined(field, options_)))) { - has_arena_constructor = true; - } - if (has_arena_constructor) { - initializer_with_arena += - TProtoStringType(",\n ") + FieldName(field) + TProtoStringType("_(arena)"); - } - } - - if (IsAnyMessage(descriptor_, options_)) { - initializer_with_arena += ",\n _any_metadata_(&type_url_, &value_)"; - } - if (num_weak_fields_ > 0) { - initializer_with_arena += ", _weak_field_map_(arena)"; - } - - TProtoStringType initializer_null = superclass + "()"; - if (IsAnyMessage(descriptor_, options_)) { - initializer_null += ", _any_metadata_(&type_url_, &value_)"; - } - if (num_weak_fields_ > 0) { - initializer_null += ", _weak_field_map_(nullptr)"; - } - format( "$classname$::$classname$(::$proto_ns$::Arena* arena,\n" " bool is_message_owned)\n" - " : $1$ {\n", - initializer_with_arena); - - if (!inlined_string_indices_.empty()) { - // Donate inline string fields. - format.Indent(); - // The last bit is the tracking bit for registering ArenaDtor. The bit is 1 - // means ArenaDtor is not registered on construction, and on demand register - // is needed. - format("if (arena != nullptr) {\n"); - if (NeedsArenaDestructor() == ArenaDtorNeeds::kOnDemand) { - format( - " if (!is_message_owned) {\n" - " $inlined_string_donated_array$[0] = ~0u;\n" - " } else {\n" - // We should not register ArenaDtor for MOA. - " $inlined_string_donated_array$[0] = 0xFFFFFFFEu;\n" - " }\n"); - } else { - format(" $inlined_string_donated_array$[0] = 0xFFFFFFFEu;\n"); - } - for (size_t i = 1; i < InlinedStringDonatedSize(); ++i) { - format(" $inlined_string_donated_array$[$1$] = ~0u;\n", i); - } - format("}\n"); - format.Outdent(); - } + " : $1$(arena, is_message_owned) {\n", + SuperClassName(descriptor_, options_)); if (!HasSimpleBaseClass(descriptor_, options_)) { - format(" SharedCtor();\n"); + format(" SharedCtor(arena, is_message_owned);\n"); if (NeedsArenaDestructor() == ArenaDtorNeeds::kRequired) { format( " if (arena != nullptr && !is_message_owned) {\n" @@ -2576,40 +2821,81 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { } else { format( "$classname$::$classname$(const $classname$& from)\n" - " : $superclass$()"); - format.Indent(); - format.Indent(); + " : $superclass$() {\n"); format.Indent(); + format("$classname$* const _this = this; (void)_this;\n"); - // Do not copy inlined_string_donated_, because this is not an arena - // constructor. + if (HasImplData(descriptor_, options_)) { + const char* field_sep = " "; + const auto put_sep = [&] { + format("\n$1$ ", field_sep); + field_sep = ","; + }; - if (!has_bit_indices_.empty()) { - format(",\n_has_bits_(from._has_bits_)"); - } + format("new (&_impl_) Impl_{"); + format.Indent(); - std::vector<bool> processed(optimized_order_.size(), false); - for (int i = 0; i < optimized_order_.size(); i++) { - auto field = optimized_order_[i]; - if (!(field->is_repeated() && !(field->is_map())) && - !IsCord(field, options_)) { - continue; + if (descriptor_->extension_range_count() > 0) { + put_sep(); + format("/*decltype($extensions$)*/{}"); + } + if (!inlined_string_indices_.empty()) { + // Do not copy inlined_string_donated_, because this is not an arena + // constructor. + put_sep(); + format("decltype($inlined_string_donated_array$){}"); + } + bool need_to_emit_cached_size = + !HasSimpleBaseClass(descriptor_, options_); + if (!has_bit_indices_.empty()) { + put_sep(); + format("decltype($has_bits$){from.$has_bits$}"); + if (need_to_emit_cached_size) { + put_sep(); + format("/*decltype($cached_size$)*/{}"); + need_to_emit_cached_size = false; + } } - processed[i] = true; - format(",\n$1$_(from.$1$_)", FieldName(field)); - } + // 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()); + } - if (IsAnyMessage(descriptor_, options_)) { - format(",\n_any_metadata_(&type_url_, &value_)"); - } - if (num_weak_fields_ > 0) { - format(",\n_weak_field_map_(from._weak_field_map_)"); - } + if (need_to_emit_cached_size) { + put_sep(); + format("/*decltype($cached_size$)*/{}"); + } - format.Outdent(); - format.Outdent(); - format(" {\n"); + if (descriptor_->real_oneof_decl_count() != 0) { + put_sep(); + format("/*decltype($oneof_case$)*/{}"); + } + if (num_weak_fields_ > 0) { + put_sep(); + format("decltype($weak_field_map$){from.$weak_field_map$}"); + } + if (IsAnyMessage(descriptor_, options_)) { + put_sep(); + format( + "/*decltype($any_metadata$)*/{&_impl_.type_url_, &_impl_.value_}"); + } + format.Outdent(); + format("};\n\n"); + } format( "_internal_metadata_.MergeFrom<$unknown_fields_type$>(from._internal_" @@ -2621,7 +2907,7 @@ void MessageGenerator::GenerateStructors(io::Printer* printer) { "from.$extensions$);\n"); } - GenerateConstructorBody(printer, processed, true); + GenerateCopyConstructorBody(printer); // Copy oneof fields. Oneof field requires oneof case check. for (auto oneof : OneOfRange(descriptor_)) { @@ -2659,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( @@ -2756,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))); @@ -2763,7 +3054,8 @@ void MessageGenerator::GenerateClear(io::Printer* printer) { return same; }); - ColdChunkSkipper cold_skipper(options_, chunks, has_bit_indices_, kColdRatio); + ColdChunkSkipper cold_skipper(descriptor_, options_, chunks, has_bit_indices_, + kColdRatio); int cached_has_word_index = -1; for (int chunk_index = 0; chunk_index < chunks.size(); chunk_index++) { @@ -2773,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); @@ -2813,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)); } } @@ -2852,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"); @@ -2950,7 +3255,7 @@ void MessageGenerator::GenerateSwap(io::Printer* printer) { std::map<TProtoStringType, TProtoStringType> 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"); @@ -2966,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 @@ -2979,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 TProtoStringType first_field_name = FieldMemberName(field); - const TProtoStringType last_field_name = - FieldMemberName(optimized_order_[i + run_length - 1]); + const TProtoStringType first_field_name = + FieldMemberName(field, /*cold=*/false); + const TProtoStringType last_field_name = FieldMemberName( + optimized_order_[i + run_length - 1], /*cold=*/false); format.Set("first", first_field_name); format.Set("last", last_field_name); @@ -3000,16 +3310,16 @@ 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($1$_, other->$1$_);\n", oneof->name()); + format("swap(_impl_.$1$_, other->_impl_.$1$_);\n", oneof->name()); } for (int i = 0; i < descriptor_->real_oneof_decl_count(); i++) { - format( - "swap($oneof_case$[$1$], " - "other->$oneof_case$[$1$]);\n", - i); + format("swap($oneof_case$[$1$], other->$oneof_case$[$1$]);\n", i); } if (num_weak_fields_) { @@ -3050,17 +3360,11 @@ void MessageGenerator::GenerateMergeFrom(io::Printer* printer) { format( "const ::$proto_ns$::Message::ClassData " "$classname$::_class_data_ = {\n" - " ::$proto_ns$::Message::CopyWithSizeCheck,\n" + " ::$proto_ns$::Message::CopyWithSourceCheck,\n" " $classname$::MergeImpl\n" "};\n" "const ::$proto_ns$::Message::ClassData*" "$classname$::GetClassData() const { return &_class_data_; }\n" - "\n" - "void $classname$::MergeImpl(::$proto_ns$::Message* to,\n" - " const ::$proto_ns$::Message& from) {\n" - " static_cast<$classname$ *>(to)->MergeFrom(\n" - " static_cast<const $classname$ &>(from));\n" - "}\n" "\n"); } else { // Generate CheckTypeAndMergeFrom(). @@ -3087,29 +3391,50 @@ void MessageGenerator::GenerateMergeFrom(io::Printer* printer) { } } -void MessageGenerator::GenerateClassSpecificMergeFrom(io::Printer* printer) { +void MessageGenerator::GenerateClassSpecificMergeImpl(io::Printer* printer) { if (HasSimpleBaseClass(descriptor_, options_)) return; // Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast. Formatter format(printer, variables_); + if (!HasDescriptorMethods(descriptor_->file(), options_)) { + // For messages that don't inherit from Message, just implement MergeFrom + // directly. + format( + "void $classname$::MergeFrom(const $classname$& from) {\n" + " $classname$* const _this = this;\n"); + } else { + format( + "void $classname$::MergeImpl(::$proto_ns$::Message& to_msg, const " + "::$proto_ns$::Message& from_msg) {\n" + " auto* const _this = static_cast<$classname$*>(&to_msg);\n" + " auto& from = static_cast<const $classname$&>(from_msg);\n"); + } + format.Indent(); format( - "void $classname$::MergeFrom(const $classname$& from) {\n" "$annotate_mergefrom$" "// @@protoc_insertion_point(class_specific_merge_from_start:" - "$full_name$)\n" - " $DCHK$_NE(&from, this);\n"); - format.Indent(); + "$full_name$)\n"); + format("$DCHK$_NE(&from, _this);\n"); format( "$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(options_, chunks, has_bit_indices_, kColdRatio); + ColdChunkSkipper cold_skipper(descriptor_, options_, chunks, has_bit_indices_, + kColdRatio); // cached_has_word_index maintains that: // cached_has_bits = from._has_bits_[cached_has_word_index] @@ -3198,7 +3523,8 @@ void MessageGenerator::GenerateClassSpecificMergeFrom(io::Printer* printer) { if (deferred_has_bit_changes) { // Flush the has bits for the primitives we deferred. GOOGLE_CHECK_LE(0, cached_has_word_index); - format("$has_bits$[$1$] |= cached_has_bits;\n", cached_has_word_index); + format("_this->$has_bits$[$1$] |= cached_has_bits;\n", + cached_has_word_index); } format.Outdent(); @@ -3235,7 +3561,7 @@ void MessageGenerator::GenerateClassSpecificMergeFrom(io::Printer* printer) { } if (num_weak_fields_) { format( - "$weak_field_map$.MergeFrom(from.$weak_field_map$);" + "_this->$weak_field_map$.MergeFrom(from.$weak_field_map$);" "\n"); } @@ -3243,12 +3569,13 @@ void MessageGenerator::GenerateClassSpecificMergeFrom(io::Printer* printer) { // the opportunity for tail calls. if (descriptor_->extension_range_count() > 0) { format( - "$extensions$.MergeFrom(internal_default_instance(), " + "_this->$extensions$.MergeFrom(internal_default_instance(), " "from.$extensions$);\n"); } format( - "_internal_metadata_.MergeFrom<$unknown_fields_type$>(from._internal_" + "_this->_internal_metadata_.MergeFrom<$unknown_fields_type$>(from._" + "internal_" "metadata_);\n"); format.Outdent(); @@ -3263,12 +3590,12 @@ void MessageGenerator::GenerateCopyFrom(io::Printer* printer) { // takes in the Message base class as a parameter); instead we just // let the base Message::CopyFrom take care of it. The base MergeFrom // knows how to quickly confirm the types exactly match, and if so, will - // use GetClassData() to get the address of Message::CopyWithSizeCheck, + // use GetClassData() to get the address of Message::CopyWithSourceCheck, // which calls Clear() and then MergeFrom(), as well as making sure that - // clearing the destination message doesn't alter the size of the source, - // when in debug builds. - // Most callers avoid this by passing a "from" message that is the same - // type as the message being merged into, rather than a generic Message. + // clearing the destination message doesn't alter the source, when in debug + // builds. Most callers avoid this by passing a "from" message that is the + // same type as the message being merged into, rather than a generic + // Message. } // Generate the class-specific CopyFrom. @@ -3280,20 +3607,33 @@ void MessageGenerator::GenerateCopyFrom(io::Printer* printer) { format("if (&from == this) return;\n"); - if (!options_.opensource_runtime) { + if (!options_.opensource_runtime && HasMessageFieldOrExtension(descriptor_)) { // This check is disabled in the opensource release because we're // concerned that many users do not define NDEBUG in their release builds. + // It is also disabled if a message has neither message fields nor + // extensions, as it's impossible to copy from its descendant. + // + // Note that FailIfCopyFromDescendant is implemented by reflection and not + // available for lite runtime. In that case, check if the size of the source + // has changed after Clear. + format("#ifndef NDEBUG\n"); + if (HasDescriptorMethods(descriptor_->file(), options_)) { + format("FailIfCopyFromDescendant(*this, from);\n"); + } else { + format("size_t from_size = from.ByteSizeLong();\n"); + } format( - "#ifndef NDEBUG\n" - "size_t from_size = from.ByteSizeLong();\n" "#endif\n" - "Clear();\n" - "#ifndef NDEBUG\n" - "$CHK$_EQ(from_size, from.ByteSizeLong())\n" - " << \"Source of CopyFrom changed when clearing target. Either \"\n" - " \"source is a nested message in target (not allowed), or \"\n" - " \"another thread is modifying the source.\";\n" - "#endif\n"); + "Clear();\n"); + if (!HasDescriptorMethods(descriptor_->file(), options_)) { + format( + "#ifndef NDEBUG\n" + "$CHK$_EQ(from_size, from.ByteSizeLong())\n" + " << \"Source of CopyFrom changed when clearing target. Either \"\n" + " \"source is a nested message in target (not allowed), or \"\n" + " \"another thread is modifying the source.\";\n" + "#endif\n"); + } } else { format("Clear();\n"); } @@ -3485,7 +3825,7 @@ void MessageGenerator::GenerateSerializeWithCachedSizesBody( // Reload. int new_index = has_bit_index / 32; - format_("cached_has_bits = _has_bits_[$1$];\n", new_index); + format_("cached_has_bits = _impl_._has_bits_[$1$];\n", new_index); cached_has_bit_index_ = new_index; } @@ -3878,14 +4218,16 @@ 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. chunks.erase(std::remove_if(chunks.begin(), chunks.end(), IsRequired), chunks.end()); - ColdChunkSkipper cold_skipper(options_, chunks, has_bit_indices_, kColdRatio); + ColdChunkSkipper cold_skipper(descriptor_, options_, chunks, has_bit_indices_, + kColdRatio); int cached_has_word_index = -1; format( diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message.h index 5e4bbe84b83..960bea8e5af 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message.h @@ -40,11 +40,11 @@ #include <set> #include <string> -#include <google/protobuf/compiler/cpp/cpp_field.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/compiler/cpp/cpp_message_layout_helper.h> -#include <google/protobuf/compiler/cpp/cpp_options.h> -#include <google/protobuf/compiler/cpp/cpp_parse_function_generator.h> +#include <google/protobuf/compiler/cpp/field.h> +#include <google/protobuf/compiler/cpp/helpers.h> +#include <google/protobuf/compiler/cpp/message_layout_helper.h> +#include <google/protobuf/compiler/cpp/options.h> +#include <google/protobuf/compiler/cpp/parse_function_generator.h> namespace google { namespace protobuf { @@ -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); @@ -129,7 +132,7 @@ class MessageGenerator { void GenerateSerializeWithCachedSizesBodyShuffled(io::Printer* printer); void GenerateByteSize(io::Printer* printer); void GenerateMergeFrom(io::Printer* printer); - void GenerateClassSpecificMergeFrom(io::Printer* printer); + void GenerateClassSpecificMergeImpl(io::Printer* printer); void GenerateCopyFrom(io::Printer* printer); void GenerateSwap(io::Printer* printer); void GenerateIsInitialized(io::Printer* printer); @@ -161,9 +164,8 @@ class MessageGenerator { void GenerateFieldClear(const FieldDescriptor* field, bool is_inline, Formatter format); - void GenerateConstructorBody(io::Printer* printer, - std::vector<bool> already_processed, - bool copy_constructor) const; + // Generates the body of the message's copy constructor. + void GenerateCopyConstructorBody(io::Printer* printer) const; // Returns the level that this message needs ArenaDtor. If the message has // a field that is not arena-exclusive, it needs an ArenaDtor diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_field.cc index 3b9f09c8c8b..9a91fd91720 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_field.cc @@ -32,10 +32,11 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/cpp_message_field.h> +#include <google/protobuf/compiler/cpp/message_field.h> #include <google/protobuf/io/printer.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/field.h> +#include <google/protobuf/compiler/cpp/helpers.h> #include <google/protobuf/stubs/strutil.h> @@ -157,8 +158,7 @@ void MessageFieldGenerator::GenerateAccessorDeclarations( } void MessageFieldGenerator::GenerateNonInlineAccessorDefinitions( - io::Printer* printer) const { -} + io::Printer* printer) const {} void MessageFieldGenerator::GenerateInlineAccessorDefinitions( io::Printer* printer) const { @@ -179,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" @@ -204,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" @@ -222,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" @@ -244,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" @@ -255,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"); @@ -407,12 +415,12 @@ void MessageFieldGenerator::GenerateMergingCode(io::Printer* printer) const { Formatter format(printer, variables_); if (implicit_weak_field_) { format( - "_Internal::mutable_$name$(this)->CheckTypeAndMergeFrom(\n" + "_Internal::mutable_$name$(_this)->CheckTypeAndMergeFrom(\n" " _Internal::$name$(&from));\n"); } else { format( - "_internal_mutable_$name$()->$type$::MergeFrom(from._internal_$name$())" - ";\n"); + "_this->_internal_mutable_$name$()->$type$::MergeFrom(\n" + " from._internal_$name$());\n"); } } @@ -435,17 +443,13 @@ 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"); } -void MessageFieldGenerator::GenerateConstructorCode( - io::Printer* printer) const { - GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); - - Formatter format(printer, variables_); - format("$field$ = nullptr;\n"); -} - void MessageFieldGenerator::GenerateCopyConstructorCode( io::Printer* printer) const { GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); @@ -453,9 +457,7 @@ void MessageFieldGenerator::GenerateCopyConstructorCode( Formatter format(printer, variables_); format( "if (from._internal_has_$name$()) {\n" - " $field$ = new $type$(*from.$field$);\n" - "} else {\n" - " $field$ = nullptr;\n" + " _this->$field$ = new $type$(*from.$field$);\n" "}\n"); } @@ -500,10 +502,26 @@ void MessageFieldGenerator::GenerateIsInitialized(io::Printer* printer) const { "}\n"); } -void MessageFieldGenerator::GenerateConstinitInitializer( +void MessageFieldGenerator::GenerateConstexprAggregateInitializer( io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_(nullptr)"); + format("/*decltype($field$)*/nullptr"); +} + +void MessageFieldGenerator::GenerateCopyAggregateInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("decltype($field$){nullptr}"); +} + +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}"); } // =================================================================== @@ -830,7 +848,7 @@ void RepeatedMessageFieldGenerator::GenerateMergingCode( GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); Formatter format(printer, variables_); - format("$field$.MergeFrom(from.$field$);\n"); + format("_this->$field$.MergeFrom(from.$field$);\n"); } void RepeatedMessageFieldGenerator::GenerateSwappingCode( @@ -846,6 +864,18 @@ void RepeatedMessageFieldGenerator::GenerateConstructorCode( // Not needed for repeated fields. } +void RepeatedMessageFieldGenerator::GenerateDestructorCode( + io::Printer* printer) const { + GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); + + Formatter format(printer, variables_); + if (implicit_weak_field_) { + format("$field$.~WeakRepeatedPtrField();\n"); + } else { + format("$field$.~RepeatedPtrField();\n"); + } +} + void RepeatedMessageFieldGenerator::GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const { GOOGLE_CHECK(!IsFieldStripped(descriptor_, options_)); @@ -922,12 +952,6 @@ void RepeatedMessageFieldGenerator::GenerateIsInitialized( } } -void RepeatedMessageFieldGenerator::GenerateConstinitInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$name$_()"); -} - } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_field.h index 528b4197048..70c42c0eacc 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_field.h @@ -38,8 +38,8 @@ #include <map> #include <string> -#include <google/protobuf/compiler/cpp/cpp_field.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/field.h> +#include <google/protobuf/compiler/cpp/helpers.h> namespace google { namespace protobuf { @@ -67,13 +67,16 @@ class MessageFieldGenerator : public FieldGenerator { void GenerateMergingCode(io::Printer* printer) const override; void GenerateSwappingCode(io::Printer* printer) const override; void GenerateDestructorCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override {} void GenerateCopyConstructorCode(io::Printer* printer) const override; void GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const override; void GenerateByteSize(io::Printer* printer) const override; void GenerateIsInitialized(io::Printer* printer) const override; - void GenerateConstinitInitializer(io::Printer* printer) const override; + void GenerateConstexprAggregateInitializer( + io::Printer* printer) const override; + void GenerateAggregateInitializer(io::Printer* printer) const override; + void GenerateCopyAggregateInitializer(io::Printer* printer) const override; protected: const bool implicit_weak_field_; @@ -124,11 +127,11 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { void GenerateSwappingCode(io::Printer* printer) const override; void GenerateConstructorCode(io::Printer* printer) const override; void GenerateCopyConstructorCode(io::Printer* printer) const override {} + void GenerateDestructorCode(io::Printer* printer) const override; void GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const override; void GenerateByteSize(io::Printer* printer) const override; void GenerateIsInitialized(io::Printer* printer) const override; - void GenerateConstinitInitializer(io::Printer* printer) const override; private: const bool implicit_weak_field_; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_layout_helper.h index 80860053f17..a8813a1f225 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/message_layout_helper.h @@ -36,7 +36,7 @@ #define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_LAYOUT_HELPER_H__ #include <google/protobuf/descriptor.h> -#include <google/protobuf/compiler/cpp/cpp_options.h> +#include <google/protobuf/compiler/cpp/options.h> namespace google { namespace protobuf { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_names.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/names.h index 39563cd0cdf..8220f7dde8c 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_names.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/names.h @@ -51,9 +51,9 @@ namespace cpp { // // For example, if you had: // package foo.bar; -// message Baz { message Qux {} } +// message Baz { message Moo {} } // Then the non-qualified version would be: -// Baz_Qux +// Baz_Moo TProtoStringType ClassName(const Descriptor* descriptor); TProtoStringType ClassName(const EnumDescriptor* enum_descriptor); @@ -61,9 +61,9 @@ TProtoStringType ClassName(const EnumDescriptor* enum_descriptor); // // For example, if you had: // package foo.bar; -// message Baz { message Qux {} } -// Then the qualified ClassName for Qux would be: -// ::foo::bar::Baz_Qux +// message Baz { message Moo {} } +// Then the qualified ClassName for Moo would be: +// ::foo::bar::Baz_Moo TProtoStringType QualifiedClassName(const Descriptor* d); TProtoStringType QualifiedClassName(const EnumDescriptor* d); TProtoStringType QualifiedExtensionName(const FieldDescriptor* d); diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_options.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/options.h index 48512a64c87..14546ca6187 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_options.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/options.h @@ -80,9 +80,10 @@ struct Options { bool opensource_runtime = false; bool annotate_accessor = false; bool unused_field_stripping = false; - bool unverified_lazy_message_sets = true; - bool eagerly_verified_lazy = true; + bool unverified_lazy_message_sets = false; + bool unverified_lazy = false; bool profile_driven_inline_string = true; + bool message_owned_arena_trial = false; bool force_split = false; #ifdef PROTOBUF_STABLE_EXPERIMENTS bool force_eagerly_verified_lazy = true; diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/padding_optimizer.cc index f48ba718a54..20910520d63 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/padding_optimizer.cc @@ -28,9 +28,9 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include <google/protobuf/compiler/cpp/cpp_padding_optimizer.h> +#include <google/protobuf/compiler/cpp/padding_optimizer.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/helpers.h> namespace google { namespace protobuf { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/padding_optimizer.h index ebdb17de61f..9c76f38c471 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/padding_optimizer.h @@ -35,7 +35,7 @@ #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_PADDING_OPTIMIZER_H__ -#include <google/protobuf/compiler/cpp/cpp_message_layout_helper.h> +#include <google/protobuf/compiler/cpp/message_layout_helper.h> namespace google { namespace protobuf { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/parse_function_generator.cc index e033856f0c7..1b97182acd6 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/parse_function_generator.cc @@ -28,7 +28,7 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include <google/protobuf/compiler/cpp/cpp_parse_function_generator.h> +#include <google/protobuf/compiler/cpp/parse_function_generator.h> #include <algorithm> #include <limits> @@ -36,7 +36,7 @@ #include <utility> #include <google/protobuf/wire_format.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/helpers.h> namespace google { namespace protobuf { @@ -231,8 +231,7 @@ std::vector<const FieldDescriptor*> FilterMiniParsedFields( break; case FieldDescriptor::TYPE_ENUM: - if (field->is_repeated() && - !HasPreservingUnknownEnumSemantics(field)) { + if (field->is_repeated() && !HasPreservingUnknownEnumSemantics(field)) { // TODO(b/206890171): handle packed repeated closed enums // Non-packed repeated can be handled using tables, but we still // need to generate fallback code for all repeated enums in order to @@ -244,15 +243,15 @@ std::vector<const FieldDescriptor*> FilterMiniParsedFields( } break; - case FieldDescriptor::TYPE_BYTES: - case FieldDescriptor::TYPE_STRING: - if (IsStringInlined(field, options)) { - // TODO(b/198211897): support InilnedStringField. - handled = false; - } else { - handled = true; - } - break; + case FieldDescriptor::TYPE_BYTES: + case FieldDescriptor::TYPE_STRING: + if (IsStringInlined(field, options)) { + // TODO(b/198211897): support InilnedStringField. + handled = false; + } else { + handled = true; + } + break; case FieldDescriptor::TYPE_MESSAGE: case FieldDescriptor::TYPE_GROUP: @@ -291,8 +290,9 @@ TailCallTableInfo::TailCallTableInfo( GOOGLE_LOG_IF(DFATAL, ordered_fields.empty()) << "Invalid message: " << descriptor->full_name() << " has " << oneof_count << " oneof declarations, but no fields"; - aux_entries.push_back(StrCat( - "_fl::Offset{offsetof(", ClassName(descriptor), ", _oneof_case_)}")); + aux_entries.push_back(StrCat("_fl::Offset{offsetof(", + ClassName(descriptor), + ", _impl_._oneof_case_)}")); } // If this message has any inlined string fields, store the donation state @@ -301,7 +301,7 @@ TailCallTableInfo::TailCallTableInfo( aux_entries.resize(2); // pad if necessary aux_entries[1] = StrCat("_fl::Offset{offsetof(", ClassName(descriptor), - ", _inlined_string_donated_)}"); + ", _impl_._inlined_string_donated_)}"); } // Fill in mini table entries. @@ -444,7 +444,7 @@ ParseFunctionGenerator::ParseFunctionGenerator( inlined_string_indices, scc_analyzer)); } SetCommonVars(options_, &variables_); - SetCommonMessageDataVariables(&variables_); + SetCommonMessageDataVariables(descriptor_, &variables_); SetUnknownFieldsVariable(descriptor_, options_, &variables_); variables_["classname"] = ClassName(descriptor, false); } @@ -547,13 +547,13 @@ void ParseFunctionGenerator::GenerateTailcallFallbackFunction( if (num_hasbits_ > 0) { // Sync hasbits - format("typed_msg->_has_bits_[0] = hasbits;\n"); + format("typed_msg->_impl_._has_bits_[0] = hasbits;\n"); } format("arc_ui32 tag = data.tag();\n"); format.Set("msg", "typed_msg->"); format.Set("this", "typed_msg"); - format.Set("has_bits", "typed_msg->_has_bits_"); + format.Set("has_bits", "typed_msg->_impl_._has_bits_"); format.Set("next_tag", "goto next_tag"); GenerateParseIterationBody(format, descriptor_, tc_table_info_->fallback_fields); @@ -649,7 +649,7 @@ void ParseFunctionGenerator::GenerateLoopingParseFunction(Formatter& format) { format("_Internal::HasBits has_bits{};\n"); format.Set("has_bits", "has_bits"); } else { - format.Set("has_bits", "_has_bits_"); + format.Set("has_bits", "_impl_._has_bits_"); } format.Set("next_tag", "continue"); format("while (!ctx->Done(&ptr)) {\n"); @@ -665,7 +665,7 @@ void ParseFunctionGenerator::GenerateLoopingParseFunction(Formatter& format) { format.Outdent(); format("message_done:\n"); - if (hasbits_size) format(" _has_bits_.Or(has_bits);\n"); + if (hasbits_size) format(" _impl_._has_bits_.Or(has_bits);\n"); format( " return ptr;\n" @@ -774,7 +774,7 @@ void ParseFunctionGenerator::GenerateTailCallTable(Formatter& format) { { auto header_scope = format.ScopedIndent(); if (num_hasbits_ > 0 || IsMapEntryMessage(descriptor_)) { - format("PROTOBUF_FIELD_OFFSET($classname$, _has_bits_),\n"); + format("PROTOBUF_FIELD_OFFSET($classname$, _impl_._has_bits_),\n"); } else { format("0, // no _has_bits_\n"); } @@ -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); arc_ui32 tag = WireFormatLite::MakeTag(field->number(), wiretype); int tag_size = io::CodedOutputStream::VarintSize32(tag); diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/parse_function_generator.h index 3c8209534a4..7e2b674852f 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_parse_function_generator.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/parse_function_generator.h @@ -38,8 +38,8 @@ #include <google/protobuf/io/printer.h> #include <google/protobuf/descriptor.h> #include <google/protobuf/wire_format_lite.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> -#include <google/protobuf/compiler/cpp/cpp_options.h> +#include <google/protobuf/compiler/cpp/helpers.h> +#include <google/protobuf/compiler/cpp/options.h> namespace google { namespace protobuf { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/primitive_field.cc index 910b59a21a7..9dbf16ae7eb 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/primitive_field.cc @@ -32,12 +32,12 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/cpp_primitive_field.h> +#include <google/protobuf/compiler/cpp/primitive_field.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/wire_format.h> #include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/helpers.h> namespace google { namespace protobuf { @@ -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" @@ -178,7 +180,7 @@ void PrimitiveFieldGenerator::GenerateClearingCode(io::Printer* printer) const { void PrimitiveFieldGenerator::GenerateMergingCode(io::Printer* printer) const { Formatter format(printer, variables_); - format("_internal_set_$name$(from._internal_$name$());\n"); + format("_this->_internal_set_$name$(from._internal_$name$());\n"); } void PrimitiveFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { @@ -186,16 +188,10 @@ void PrimitiveFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { format("swap($field$, other->$field$);\n"); } -void PrimitiveFieldGenerator::GenerateConstructorCode( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$field$ = $default$;\n"); -} - void PrimitiveFieldGenerator::GenerateCopyConstructorCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$field$ = from.$field$;\n"); + format("_this->$field$ = from.$field$;\n"); } void PrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray( @@ -230,10 +226,26 @@ void PrimitiveFieldGenerator::GenerateByteSize(io::Printer* printer) const { } } -void PrimitiveFieldGenerator::GenerateConstinitInitializer( +void PrimitiveFieldGenerator::GenerateConstexprAggregateInitializer( io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_($default$)"); + format("/*decltype($field$)*/$default$"); +} + +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$}"); +} + +void PrimitiveFieldGenerator::GenerateCopyAggregateInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("decltype($field$){}"); } // =================================================================== @@ -398,7 +410,7 @@ void RepeatedPrimitiveFieldGenerator::GenerateClearingCode( void RepeatedPrimitiveFieldGenerator::GenerateMergingCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$field$.MergeFrom(from.$field$);\n"); + format("_this->$field$.MergeFrom(from.$field$);\n"); } void RepeatedPrimitiveFieldGenerator::GenerateSwappingCode( @@ -407,6 +419,12 @@ void RepeatedPrimitiveFieldGenerator::GenerateSwappingCode( format("$field$.InternalSwap(&other->$field$);\n"); } +void RepeatedPrimitiveFieldGenerator::GenerateDestructorCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$field$.~RepeatedField();\n"); +} + void RepeatedPrimitiveFieldGenerator::GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const { Formatter format(printer, variables_); @@ -460,7 +478,8 @@ void RepeatedPrimitiveFieldGenerator::GenerateByteSize( format( "if (data_size > 0) {\n" " total_size += $tag_size$ +\n" - " ::_pbi::WireFormatLite::Int32Size(static_cast<$int32$>(data_size));\n" + " " + "::_pbi::WireFormatLite::Int32Size(static_cast<$int32$>(data_size));\n" "}\n"); if (FixedSize(descriptor_->type()) == -1) { format( @@ -480,13 +499,37 @@ void RepeatedPrimitiveFieldGenerator::GenerateByteSize( format("}\n"); } -void RepeatedPrimitiveFieldGenerator::GenerateConstinitInitializer( +void RepeatedPrimitiveFieldGenerator::GenerateConstexprAggregateInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("/*decltype($field$)*/{}"); + if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 && + HasGeneratedMethods(descriptor_->file(), options_)) { + format("\n, /*decltype($cached_byte_size_field$)*/{0}"); + } +} + +void RepeatedPrimitiveFieldGenerator::GenerateAggregateInitializer( io::Printer* printer) const { Formatter format(printer, variables_); - format("$name$_()"); + format("decltype($field$){arena}"); + if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 && + HasGeneratedMethods(descriptor_->file(), options_)) { + // std::atomic has no move constructor, which prevents explicit aggregate + // initialization pre-C++17. + format("\n, /*decltype($cached_byte_size_field$)*/{0}"); + } +} + +void RepeatedPrimitiveFieldGenerator::GenerateCopyAggregateInitializer( + io::Printer* printer) const { + + Formatter format(printer, variables_); + format("decltype($field$){from.$field$}"); if (descriptor_->is_packed() && FixedSize(descriptor_->type()) == -1 && HasGeneratedMethods(descriptor_->file(), options_)) { - format("\n, $cached_byte_size_name$(0)"); + // std::atomic has no move constructor. + format("\n, /*decltype($cached_byte_size_field$)*/{0}"); } } diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/primitive_field.h index 77ac598e905..bb8a08aa141 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_primitive_field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/primitive_field.h @@ -38,7 +38,7 @@ #include <map> #include <string> -#include <google/protobuf/compiler/cpp/cpp_field.h> +#include <google/protobuf/compiler/cpp/field.h> namespace google { namespace protobuf { @@ -58,12 +58,15 @@ class PrimitiveFieldGenerator : public FieldGenerator { void GenerateClearingCode(io::Printer* printer) const override; void GenerateMergingCode(io::Printer* printer) const override; void GenerateSwappingCode(io::Printer* printer) const override; - void GenerateConstructorCode(io::Printer* printer) const override; + void GenerateConstructorCode(io::Printer* printer) const override {} void GenerateCopyConstructorCode(io::Printer* printer) const override; void GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const override; void GenerateByteSize(io::Printer* printer) const override; - void GenerateConstinitInitializer(io::Printer* printer) const override; + void GenerateConstexprAggregateInitializer( + io::Printer* printer) const override; + void GenerateAggregateInitializer(io::Printer* printer) const override; + void GenerateCopyAggregateInitializer(io::Printer* printer) const override; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); @@ -99,11 +102,17 @@ 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; void GenerateByteSize(io::Printer* printer) const override; - void GenerateConstinitInitializer(io::Printer* printer) const override; + void GenerateConstexprAggregateInitializer( + io::Printer* printer) const override; + void GenerateAggregateInitializer(io::Printer* printer) const override; + void GenerateCopyAggregateInitializer(io::Printer* printer) const override; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_service.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/service.cc index 7bf589fa388..fae7128a097 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_service.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/service.cc @@ -32,11 +32,11 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/cpp_service.h> +#include <google/protobuf/compiler/cpp/service.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/helpers.h> namespace google { namespace protobuf { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_service.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/service.h index d237f9d732e..56982cf566b 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_service.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/service.h @@ -39,7 +39,7 @@ #include <string> #include <google/protobuf/descriptor.h> -#include <google/protobuf/compiler/cpp/cpp_options.h> +#include <google/protobuf/compiler/cpp/options.h> namespace google { namespace protobuf { diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/string_field.cc index 4d8744976ba..5f30d3b511e 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/string_field.cc @@ -32,11 +32,11 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. -#include <google/protobuf/compiler/cpp/cpp_string_field.h> +#include <google/protobuf/compiler/cpp/string_field.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/stubs/strutil.h> -#include <google/protobuf/compiler/cpp/cpp_helpers.h> +#include <google/protobuf/compiler/cpp/helpers.h> #include <google/protobuf/descriptor.pb.h> @@ -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( - "union { ::$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 TProtoStringType* $classname$::mutable_$name$() {\n" + "$maybe_prepare_split_message$" " TProtoStringType* _s = _internal_mutable_$name$();\n" "$annotate_mutable$" " // @@protoc_insertion_point(field_mutable:$full_name$)\n" @@ -280,6 +283,7 @@ void StringFieldGenerator::GenerateInlineAccessorDefinitions( format( "inline TProtoStringType* $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$(TProtoStringType* $name$) {\n" + "$maybe_prepare_split_message$" " if ($name$ != nullptr) {\n" " $set_hasbit$\n" " } else {\n" @@ -403,7 +408,7 @@ void StringFieldGenerator::GenerateMessageClearingCode( void StringFieldGenerator::GenerateMergingCode(io::Printer* printer) const { Formatter format(printer, variables_); // TODO(gpike): improve this - format("_internal_set_$name$(from._internal_$name$());\n"); + format("_this->_internal_set_$name$(from._internal_$name$());\n"); } void StringFieldGenerator::GenerateSwappingCode(io::Printer* printer) const { @@ -440,12 +445,27 @@ 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_); GenerateConstructorCode(printer); if (inlined_) { - format("new (&$field$) ::_pbi::InlinedStringField();\n"); + format("new (&_this->$field$) ::_pbi::InlinedStringField();\n"); } if (HasHasbit(descriptor_)) { @@ -458,13 +478,13 @@ void StringFieldGenerator::GenerateCopyConstructorCode( if (!inlined_) { format( - "$field$.Set(from._internal_$name$(), \n" - " GetArenaForAllocation());\n"); + "_this->$field$.Set(from._internal_$name$(), \n" + " _this->GetArenaForAllocation());\n"); } else { format( - "$field$.Set(from._internal_$name$(),\n" - " GetArenaForAllocation(), _internal_$name$_donated(), " - "&$donating_states_word$, $mask_for_undonate$, this);\n"); + "_this->$field$.Set(from._internal_$name$(),\n" + " _this->GetArenaForAllocation(), _this->_internal_$name$_donated(), " + "&_this->$donating_states_word$, $mask_for_undonate$, _this);\n"); } format.Outdent(); @@ -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"); } @@ -522,22 +547,43 @@ void StringFieldGenerator::GenerateByteSize(io::Printer* printer) const { " this->_internal_$name$());\n"); } -void StringFieldGenerator::GenerateConstinitInitializer( +void StringFieldGenerator::GenerateConstexprAggregateInitializer( io::Printer* printer) const { Formatter format(printer, variables_); if (inlined_) { - format("$name$_(nullptr, false)"); + format("/*decltype($field$)*/{nullptr, false}"); return; } if (descriptor_->default_value_string().empty()) { format( - "$name$_(&::_pbi::fixed_address_empty_string, " - "::_pbi::ConstantInitialized{})"); + "/*decltype($field$)*/{&::_pbi::fixed_address_empty_string, " + "::_pbi::ConstantInitialized{}}"); + } else { + format("/*decltype($field$)*/{nullptr, ::_pbi::ConstantInitialized{}}"); + } +} + +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 { - format("$name$_(nullptr, ::_pbi::ConstantInitialized{})"); + format("decltype($field$)(arena)"); } } +void StringFieldGenerator::GenerateCopyAggregateInitializer( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("decltype($field$){}"); +} + // =================================================================== StringOneofFieldGenerator::StringOneofFieldGenerator( @@ -858,7 +904,7 @@ void RepeatedStringFieldGenerator::GenerateClearingCode( void RepeatedStringFieldGenerator::GenerateMergingCode( io::Printer* printer) const { Formatter format(printer, variables_); - format("$field$.MergeFrom(from.$field$);\n"); + format("_this->$field$.MergeFrom(from.$field$);\n"); } void RepeatedStringFieldGenerator::GenerateSwappingCode( @@ -867,6 +913,12 @@ void RepeatedStringFieldGenerator::GenerateSwappingCode( format("$field$.InternalSwap(&other->$field$);\n"); } +void RepeatedStringFieldGenerator::GenerateDestructorCode( + io::Printer* printer) const { + Formatter format(printer, variables_); + format("$field$.~RepeatedPtrField();\n"); +} + void RepeatedStringFieldGenerator::GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const { Formatter format(printer, variables_); @@ -899,12 +951,6 @@ void RepeatedStringFieldGenerator::GenerateByteSize( "}\n"); } -void RepeatedStringFieldGenerator::GenerateConstinitInitializer( - io::Printer* printer) const { - Formatter format(printer, variables_); - format("$name$_()"); -} - } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.h b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/string_field.h index 845bf073a93..db5f18bfb7d 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/cpp/cpp_string_field.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/cpp/string_field.h @@ -38,7 +38,7 @@ #include <map> #include <string> -#include <google/protobuf/compiler/cpp/cpp_field.h> +#include <google/protobuf/compiler/cpp/field.h> namespace google { namespace protobuf { @@ -63,13 +63,17 @@ 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; void GenerateSerializeWithCachedSizesToArray( io::Printer* printer) const override; void GenerateByteSize(io::Printer* printer) const override; - void GenerateConstinitInitializer(io::Printer* printer) const override; + void GenerateConstexprAggregateInitializer( + io::Printer* printer) const override; + void GenerateAggregateInitializer(io::Printer* printer) const override; + void GenerateCopyAggregateInitializer(io::Printer* printer) const override; bool IsInlined() const override { return inlined_; } ArenaDtorNeeds NeedsArenaDestructor() const override; @@ -112,11 +116,13 @@ 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; void GenerateByteSize(io::Printer* printer) const override; - void GenerateConstinitInitializer(io::Printer* printer) const override; private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedStringFieldGenerator); |