| // 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 <cstddef> |
| #include <cstdint> |
| #include <memory> |
| #include <string> |
| #include <vector> |
| |
| #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 the public API string type for string fields. |
| FieldOptions::CType string_type() const { return string_type_; } |
| |
| // 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<io::Printer::Sub> 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_{<default value>}` |
| 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_{<default value>}` |
| 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<absl::string_view, std::string> 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; |
| FieldOptions::CType string_type_ = FieldOptions::STRING; |
| 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(); } |
| FieldOptions::CType string_type() const { return impl_->string_type(); } |
| 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<uint32_t> hasbit_index, |
| absl::optional<uint32_t> inlined_string_index); |
| |
| std::unique_ptr<FieldGeneratorBase> impl_; |
| std::vector<io::Printer::Sub> field_vars_; |
| std::vector<io::Printer::Sub> tracker_vars_; |
| std::vector<io::Printer::Sub> 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<const int32_t> has_bit_indices, |
| absl::Span<const int32_t> 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<size_t>(field->index())]; |
| } |
| |
| private: |
| const Descriptor* descriptor_; |
| std::vector<FieldGenerator> fields_; |
| }; |
| |
| // Returns variables common to all fields. |
| // |
| // TODO: Make this function .cc-private. |
| std::vector<io::Printer::Sub> FieldVars(const FieldDescriptor* field, |
| const Options& opts); |
| } // namespace cpp |
| } // namespace compiler |
| } // namespace protobuf |
| } // namespace google |
| |
| #endif // GOOGLE_PROTOBUF_COMPILER_CPP_FIELD_H__ |