// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file or at // https://developers.google.com/open-source/licenses/bsd // Author: kenton@google.com (Kenton Varda) // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. #ifndef GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__ #define GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__ #include #include #include #include #include #include "absl/container/flat_hash_map.h" #include "absl/log/absl_check.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" #include "absl/types/span.h" #include "google/protobuf/compiler/cpp/helpers.h" #include "google/protobuf/compiler/cpp/options.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/io/printer.h" namespace google { namespace protobuf { namespace compiler { namespace cpp { // Customization points for each field codegen type. See FieldGenerator to // see how each of these functions is used. // // TODO: Make every function except the dtor in this generator // non-pure-virtual. A generator with no implementation should be able to // automatically not contribute any code to the message it is part of, as a // matter of clean composability. class FieldGeneratorBase { public: // `GeneratorFunction` defines a subset of generator functions that may have // additional optimizations or requirements such as 'uses a local `arena` // variable instead of calling GetArena()' enum class GeneratorFunction { kMergeFrom }; FieldGeneratorBase(const FieldDescriptor* field, const Options& options, MessageSCCAnalyzer* scc_analyzer); FieldGeneratorBase(const FieldGeneratorBase&) = delete; FieldGeneratorBase& operator=(const FieldGeneratorBase&) = delete; virtual ~FieldGeneratorBase() = 0; // Returns true if this field should be placed in the cold 'Split' section. bool should_split() const { return should_split_; } // Returns true if this field is trivial. (int, float, double, enum, bool) bool is_trivial() const { return is_trivial_; } // Returns true if the field value itself is trivial, i.e., the field is // trivial, or a (raw) pointer value to a singular, non lazy message. bool has_trivial_value() const { return has_trivial_value_; } // Returns true if the provided field has a trivial zero default. // I.e., the field can be initialized with `memset(&field, 0, sizeof(field))` bool has_trivial_zero_default() const { return has_trivial_zero_default_; } // Returns true if the provided field can be initialized with `= {}`. bool has_brace_default_assign() const { return has_brace_default_assign_; } // Returns true if the field is a singular or repeated message. // This includes group message types. To explicitly check if a message // type is a group type, use the `is_group()` function, bool is_message() const { return is_message_; } // Returns true if the field is a group message field (TYPE_GROUP). bool is_group() const { return is_group_; } // Returns true if the field is a weak message bool is_weak() const { return is_weak_; } // Returns true if the field is a lazy message. bool is_lazy() const { return is_lazy_; } // Returns true if the field is a foreign message field. bool is_foreign() const { return is_foreign_; } // Returns true if the field is a string field. bool is_string() const { return is_string_; } // Returns true if the field API uses bytes (void) instead of chars. bool is_bytes() const { return is_bytes_; } // Returns true if this field is part of a oneof field. bool is_oneof() const { return is_oneof_; } // Returns true if the field should be inlined instead of dynamically // allocated. Applies to string and message value. bool is_inlined() const { return is_inlined_; } // Returns true if this field has an appropriate default constexpr // constructor. i.e., there is no need for an explicit initializer. bool has_default_constexpr_constructor() const { return has_default_constexpr_constructor_; } // Returns true if this generator requires an 'arena' parameter on the // given generator function. virtual bool RequiresArena(GeneratorFunction) const { return false; } virtual std::vector MakeVars() const { return {}; } virtual void GeneratePrivateMembers(io::Printer* p) const = 0; virtual void GenerateStaticMembers(io::Printer* p) const {} virtual void GenerateAccessorDeclarations(io::Printer* p) const = 0; virtual void GenerateInlineAccessorDefinitions(io::Printer* p) const = 0; virtual void GenerateNonInlineAccessorDefinitions(io::Printer* p) const {} virtual void GenerateClearingCode(io::Printer* p) const = 0; virtual void GenerateMessageClearingCode(io::Printer* p) const { GenerateClearingCode(p); } virtual void GenerateMergingCode(io::Printer* p) const = 0; virtual void GenerateCopyConstructorCode(io::Printer* p) const; virtual void GenerateSwappingCode(io::Printer* p) const = 0; virtual void GenerateConstructorCode(io::Printer* p) const = 0; virtual void GenerateDestructorCode(io::Printer* p) const {} virtual void GenerateArenaDestructorCode(io::Printer* p) const { ABSL_CHECK(NeedsArenaDestructor() == ArenaDtorNeeds::kNone) << field_->cpp_type_name(); } // Generates constexpr member initialization code, e.g.: `foo_{5}`. // The default implementation generates the following code: // - repeated fields and maps: `field_{}` // - all other fields: `field_{}` virtual void GenerateMemberConstexprConstructor(io::Printer* p) const; // Generates member initialization code, e.g.: `foo_(5)`. // The default implementation generates the following code: // - repeated fields and maps: `field_{visibility, arena}` // - split repeated fields (RawPtr): `field_{}` // - all other fields: `field_{}` virtual void GenerateMemberConstructor(io::Printer* p) const; // Generates member copy initialization code, e.g.: `foo_(5)`. // The default implementation generates the following code: // - repeated fields and maps: `field_{visibility, arena, from.field_}` // - all other fields: `field_{from.field_}` virtual void GenerateMemberCopyConstructor(io::Printer* p) const; // Generates 'placement new' copy construction code used to // explicitly copy initialize oneof field values. // The default implementation checks the current field to not be repeated, // an extension or a map, and generates the following code: // - `field_ = from.field_` virtual void GenerateOneofCopyConstruct(io::Printer* p) const; virtual void GenerateAggregateInitializer(io::Printer* p) const; virtual void GenerateConstexprAggregateInitializer(io::Printer* p) const; virtual void GenerateCopyAggregateInitializer(io::Printer* p) const; virtual void GenerateSerializeWithCachedSizesToArray( io::Printer* p) const = 0; virtual void GenerateByteSize(io::Printer* p) const = 0; virtual void GenerateIsInitialized(io::Printer* p) const { ABSL_CHECK(!NeedsIsInitialized()); } virtual bool NeedsIsInitialized() const { return false; } virtual bool IsInlined() const { return false; } virtual ArenaDtorNeeds NeedsArenaDestructor() const { return ArenaDtorNeeds::kNone; } protected: const FieldDescriptor* field_; const Options& options_; MessageSCCAnalyzer* scc_; absl::flat_hash_map variables_; private: bool should_split_ = false; bool is_trivial_ = false; bool has_trivial_value_ = false; bool has_trivial_zero_default_ = false; bool has_brace_default_assign_ = false; bool is_message_ = false; bool is_group_ = false; bool is_string_ = false; bool is_bytes_ = false; bool is_inlined_ = false; bool is_foreign_ = false; bool is_lazy_ = false; bool is_weak_ = false; bool is_oneof_ = false; bool has_default_constexpr_constructor_ = false; }; inline FieldGeneratorBase::~FieldGeneratorBase() = default; class FieldGenerator { private: // This function must be defined here so that the inline definitions below // can see it, which is required because it has deduced return type. auto PushVarsForCall(io::Printer* p) const { // NOTE: we use a struct here because: // * We want to ensure that order of evaluation below is well-defined, // which {...} guarantees but (...) does not. // * We do not require C++17 as of writing and therefore cannot use // std::tuple with CTAD. // * std::make_tuple uses (...), not {...}. struct Vars { decltype(p->WithVars(field_vars_)) cleanup1; decltype(p->WithVars(tracker_vars_)) cleanup2; decltype(p->WithVars(per_generator_vars_)) cleanup3; }; return Vars{p->WithVars(field_vars_), p->WithVars(tracker_vars_), p->WithVars(per_generator_vars_)}; } public: using GeneratorFunction = FieldGeneratorBase::GeneratorFunction; FieldGenerator(const FieldGenerator&) = delete; FieldGenerator& operator=(const FieldGenerator&) = delete; FieldGenerator(FieldGenerator&&) = default; FieldGenerator& operator=(FieldGenerator&&) = default; // Properties: see FieldGeneratorBase for documentation bool should_split() const { return impl_->should_split(); } bool is_trivial() const { return impl_->is_trivial(); } bool has_trivial_value() const { return impl_->has_trivial_value(); } bool has_trivial_zero_default() const { return impl_->has_trivial_zero_default(); } bool has_brace_default_assign() const { return impl_->has_brace_default_assign(); } bool is_message() const { return impl_->is_message(); } bool is_group() const { return impl_->is_group(); } bool is_weak() const { return impl_->is_weak(); } bool is_lazy() const { return impl_->is_lazy(); } bool is_foreign() const { return impl_->is_foreign(); } bool is_string() const { return impl_->is_string(); } bool is_bytes() const { return impl_->is_bytes(); } bool is_oneof() const { return impl_->is_oneof(); } bool is_inlined() const { return impl_->is_inlined(); } bool has_default_constexpr_constructor() const { return impl_->has_default_constexpr_constructor(); } // Requirements: see FieldGeneratorBase for documentation bool RequiresArena(GeneratorFunction function) const { return impl_->RequiresArena(function); } // Prints private members needed to represent this field. // // These are placed inside the class definition. void GeneratePrivateMembers(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GeneratePrivateMembers(p); } // Prints static members needed to represent this field. // // These are placed inside the class definition. void GenerateStaticMembers(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateStaticMembers(p); } void GenerateMemberConstructor(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateMemberConstructor(p); } void GenerateMemberCopyConstructor(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateMemberCopyConstructor(p); } void GenerateOneofCopyConstruct(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateOneofCopyConstruct(p); } void GenerateMemberConstexprConstructor(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateMemberConstexprConstructor(p); } // Generates declarations for all of the accessor functions related to this // field. // // These are placed inside the class definition. void GenerateAccessorDeclarations(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateAccessorDeclarations(p); } // Generates inline definitions of accessor functions for this field. // // These are placed in namespace scope in the header after all class // definitions. void GenerateInlineAccessorDefinitions(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateInlineAccessorDefinitions(p); } // Generates definitions of accessors that aren't inlined. // // These are placed in namespace scope in the .cc file. void GenerateNonInlineAccessorDefinitions(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateNonInlineAccessorDefinitions(p); } // Generates statements which clear the field. // // This is used to define the clear_$name$() method. void GenerateClearingCode(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateClearingCode(p); } // Generates statements which clear the field as part of the Clear() method // for the whole message. // // For message types which have field presence bits, // MessageGenerator::GenerateClear will have already checked the presence // bits. void GenerateMessageClearingCode(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateMessageClearingCode(p); } // Generates statements which merge the contents of the field from the current // message to the target message, which is stored in the generated code // variable `from`. // // This is used to fill in the MergeFrom method for the whole message. // // Details of this usage can be found in message.cc under the // GenerateMergeFrom method. void GenerateMergingCode(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateMergingCode(p); } // Generates a copy constructor // // TODO: Document this properly. void GenerateCopyConstructorCode(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateCopyConstructorCode(p); } // Generates statements which swap this field and the corresponding field of // another message, which is stored in the generated code variable `other`. // // This is used to define the Swap method. Details of usage can be found in // message.cc under the GenerateSwap method. void GenerateSwappingCode(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateSwappingCode(p); } // Generates initialization code for private members declared by // GeneratePrivateMembers(). // // These go into the message class's SharedCtor() method, invoked by each of // the generated constructors. void GenerateConstructorCode(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateConstructorCode(p); } // Generates any code that needs to go in the class's SharedDtor() method, // invoked by the destructor. void GenerateDestructorCode(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateDestructorCode(p); } // Generates a manual destructor invocation for use when the message is on an // arena. // // The code that this method generates will be executed inside a // shared-for-the-whole-message-class method registered with OwnDestructor(). void GenerateArenaDestructorCode(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateArenaDestructorCode(p); } // Generates initialization code for private members declared by // GeneratePrivateMembers(). // // These go into the SharedCtor's aggregate initialization of the _impl_ // struct and must follow the syntax `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. void GenerateAggregateInitializer(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateAggregateInitializer(p); } // Generates 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 `/*decltype($field$)*/{}` (see // above). Does not include `:` or `,` separators. void GenerateConstexprAggregateInitializer(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateConstexprAggregateInitializer(p); } // Generates 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 `decltype($field$){from.$field$}` (see // above). Does not include `:` or `,` separators. void GenerateCopyAggregateInitializer(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateCopyAggregateInitializer(p); } // Generates statements to serialize this field directly to the array // `target`, which are placed within the message's // SerializeWithCachedSizesToArray() method. // // This must also advance `target` past the written bytes. void GenerateSerializeWithCachedSizesToArray(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateSerializeWithCachedSizesToArray(p); } // Generates statements to compute the serialized size of this field, which // are placed in the message's ByteSize() method. void GenerateByteSize(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateByteSize(p); } // Generates lines to call IsInitialized() for eligible message fields. Non // message fields won't need to override this function. void GenerateIsInitialized(io::Printer* p) const { auto vars = PushVarsForCall(p); impl_->GenerateIsInitialized(p); } bool NeedsIsInitialized() const { return impl_->NeedsIsInitialized(); } // TODO: Document this properly. bool IsInlined() const { return impl_->IsInlined(); } // TODO: Document this properly. ArenaDtorNeeds NeedsArenaDestructor() const { return impl_->NeedsArenaDestructor(); } private: friend class FieldGeneratorTable; FieldGenerator(const FieldDescriptor* field, const Options& options, MessageSCCAnalyzer* scc_analyzer, absl::optional hasbit_index, absl::optional inlined_string_index); std::unique_ptr impl_; std::vector field_vars_; std::vector tracker_vars_; std::vector per_generator_vars_; }; // Convenience class which constructs FieldGeneratorBases for a Descriptor. class FieldGeneratorTable { public: explicit FieldGeneratorTable(const Descriptor* descriptor) : descriptor_(descriptor) {} FieldGeneratorTable(const FieldGeneratorTable&) = delete; FieldGeneratorTable& operator=(const FieldGeneratorTable&) = delete; void Build(const Options& options, MessageSCCAnalyzer* scc_analyzer, absl::Span has_bit_indices, absl::Span inlined_string_indices); const FieldGenerator& get(const FieldDescriptor* field) const { ABSL_CHECK_EQ(field->containing_type(), descriptor_); ABSL_DCHECK_GE(field->index(), 0); return fields_[static_cast(field->index())]; } private: const Descriptor* descriptor_; std::vector fields_; }; // Returns variables common to all fields. // // TODO: Make this function .cc-private. std::vector FieldVars(const FieldDescriptor* field, const Options& opts); } // namespace cpp } // namespace compiler } // namespace protobuf } // namespace google #endif // GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__