aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/compiler/cpp
diff options
context:
space:
mode:
authorGravatar Feng Xiao <xfxyjwf@gmail.com>2014-11-10 17:34:54 -0800
committerGravatar Feng Xiao <xfxyjwf@gmail.com>2014-11-10 17:34:54 -0800
commit6ef984af4b0c63c1c33127a12dcfc8e6359f0c9e (patch)
treed17c61ff9f3ae28224fbddac6d26bfc59e2cf755 /src/google/protobuf/compiler/cpp
parentbaca1a8a1aa180c42de6278d3b8286c4496c6a10 (diff)
Down-integrate from internal code base.
Diffstat (limited to 'src/google/protobuf/compiler/cpp')
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum.cc9
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.cc118
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.cc17
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.h13
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.cc17
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.h3
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_generator.cc3
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.cc21
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.h33
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc1014
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.h9
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.cc369
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc128
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.cc8
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.cc538
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.h1
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto20
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.cc3
18 files changed, 1813 insertions, 511 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc
index c31cb5b3..32d5516e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc
@@ -101,6 +101,15 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) {
}
}
+ if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+ // For new enum semantics: generate min and max sentinel values equal to
+ // INT32_MIN and INT32_MAX
+ if (descriptor_->value_count() > 0) printer->Print(",\n");
+ printer->Print(vars,
+ "$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = INT32_MIN,\n"
+ "$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = INT32_MAX");
+ }
+
printer->Outdent();
printer->Print("\n};\n");
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
index 20b18ade..17926135 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -87,9 +87,13 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return static_cast< $type$ >($name$_);\n"
"}\n"
- "inline void $classname$::set_$name$($type$ value) {\n"
- " assert($type$_IsValid(value));\n"
- " set_has_$name$();\n"
+ "inline void $classname$::set_$name$($type$ value) {\n");
+ if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+ printer->Print(variables_,
+ " assert($type$_IsValid(value));\n");
+ }
+ printer->Print(variables_,
+ " $set_hasbit$\n"
" $name$_ = value;\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n");
@@ -121,21 +125,27 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
"int value;\n"
"DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
" int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
- " input, &value)));\n"
- "if ($type$_IsValid(value)) {\n"
- " set_$name$(static_cast< $type$ >(value));\n");
- if (UseUnknownFieldSet(descriptor_->file())) {
+ " input, &value)));\n");
+ if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
printer->Print(variables_,
- "} else {\n"
- " mutable_unknown_fields()->AddVarint($number$, value);\n");
+ "set_$name$(static_cast< $type$ >(value));\n");
} else {
- printer->Print(
- "} else {\n"
- " unknown_fields_stream.WriteVarint32(tag);\n"
- " unknown_fields_stream.WriteVarint32(value);\n");
+ printer->Print(variables_,
+ "if ($type$_IsValid(value)) {\n"
+ " set_$name$(static_cast< $type$ >(value));\n");
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(variables_,
+ "} else {\n"
+ " mutable_unknown_fields()->AddVarint($number$, value);\n");
+ } else {
+ printer->Print(
+ "} else {\n"
+ " unknown_fields_stream.WriteVarint32(tag);\n"
+ " unknown_fields_stream.WriteVarint32(value);\n");
+ }
+ printer->Print(variables_,
+ "}\n");
}
- printer->Print(variables_,
- "}\n");
}
void EnumFieldGenerator::
@@ -174,18 +184,24 @@ void EnumOneofFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
printer->Print(variables_,
"inline $type$ $classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
" if (has_$name$()) {\n"
" return static_cast< $type$ >($oneof_prefix$$name$_);\n"
" }\n"
" return static_cast< $type$ >($default$);\n"
"}\n"
- "inline void $classname$::set_$name$($type$ value) {\n"
- " assert($type$_IsValid(value));\n"
+ "inline void $classname$::set_$name$($type$ value) {\n");
+ if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+ printer->Print(variables_,
+ " assert($type$_IsValid(value));\n");
+ }
+ printer->Print(variables_,
" if (!has_$name$()) {\n"
" clear_$oneof_name$();\n"
" set_has_$name$();\n"
" }\n"
" $oneof_prefix$$name$_ = value;\n"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n");
}
@@ -245,13 +261,21 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" // @@protoc_insertion_point(field_get:$full_name$)\n"
" return static_cast< $type$ >($name$_.Get(index));\n"
"}\n"
- "inline void $classname$::set_$name$(int index, $type$ value) {\n"
- " assert($type$_IsValid(value));\n"
+ "inline void $classname$::set_$name$(int index, $type$ value) {\n");
+ if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+ printer->Print(variables_,
+ " assert($type$_IsValid(value));\n");
+ }
+ printer->Print(variables_,
" $name$_.Set(index, value);\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n"
- "inline void $classname$::add_$name$($type$ value) {\n"
- " assert($type$_IsValid(value));\n"
+ "inline void $classname$::add_$name$($type$ value) {\n");
+ if (!HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+ printer->Print(variables_,
+ " assert($type$_IsValid(value));\n");
+ }
+ printer->Print(variables_,
" $name$_.Add(value);\n"
" // @@protoc_insertion_point(field_add:$full_name$)\n"
"}\n");
@@ -280,7 +304,7 @@ GenerateMergingCode(io::Printer* printer) const {
void RepeatedEnumFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
- printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
+ printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n");
}
void RepeatedEnumFieldGenerator::
@@ -295,20 +319,26 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
"int value;\n"
"DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
" int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
- " input, &value)));\n"
- "if ($type$_IsValid(value)) {\n"
- " add_$name$(static_cast< $type$ >(value));\n");
- if (UseUnknownFieldSet(descriptor_->file())) {
+ " input, &value)));\n");
+ if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
printer->Print(variables_,
- "} else {\n"
- " mutable_unknown_fields()->AddVarint($number$, value);\n");
+ "add_$name$(static_cast< $type$ >(value));\n");
} else {
- printer->Print(
- "} else {\n"
- " unknown_fields_stream.WriteVarint32(tag);\n"
- " unknown_fields_stream.WriteVarint32(value);\n");
+ printer->Print(variables_,
+ "if ($type$_IsValid(value)) {\n"
+ " add_$name$(static_cast< $type$ >(value));\n");
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(variables_,
+ "} else {\n"
+ " mutable_unknown_fields()->AddVarint($number$, value);\n");
+ } else {
+ printer->Print(
+ "} else {\n"
+ " unknown_fields_stream.WriteVarint32(tag);\n"
+ " unknown_fields_stream.WriteVarint32(value);\n");
+ }
+ printer->Print("}\n");
}
- printer->Print("}\n");
}
void RepeatedEnumFieldGenerator::
@@ -318,8 +348,15 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
// rarely be executed.
printer->Print(variables_,
"DO_((::google::protobuf::internal::WireFormatLite::ReadPackedEnumNoInline(\n"
- " input,\n"
- " &$type$_IsValid,\n"
+ " input,\n");
+ if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+ printer->Print(variables_,
+ " NULL,\n");
+ } else {
+ printer->Print(variables_,
+ " &$type$_IsValid,\n");
+ }
+ printer->Print(variables_,
" this->mutable_$name$())));\n");
} else {
printer->Print(variables_,
@@ -331,10 +368,17 @@ GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const {
" int value;\n"
" DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
" int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>(\n"
- " input, &value)));\n"
+ " input, &value)));\n");
+ if (HasPreservingUnknownEnumSemantics(descriptor_->file())) {
+ printer->Print(variables_,
+ " add_$name$(static_cast< $type$ >(value));\n");
+ } else {
+ printer->Print(variables_,
" if ($type$_IsValid(value)) {\n"
" add_$name$(static_cast< $type$ >(value));\n"
- " }\n"
+ " }\n");
+ }
+ printer->Print(variables_,
"}\n"
"input->PopLimit(limit);\n");
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc
index 1e9a40ac..85838ac3 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_field.cc
@@ -34,6 +34,9 @@
#include <google/protobuf/compiler/cpp/cpp_field.h>
#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
@@ -68,6 +71,20 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
? " PROTOBUF_DEPRECATED" : "";
(*variables)["cppget"] = "Get";
+
+ if (HasFieldPresence(descriptor->file())) {
+ (*variables)["set_hasbit"] =
+ "set_has_" + FieldName(descriptor) + "();";
+ (*variables)["clear_hasbit"] =
+ "clear_has_" + FieldName(descriptor) + "();";
+ } else {
+ (*variables)["set_hasbit"] = "";
+ (*variables)["clear_hasbit"] = "";
+ }
+
+ // By default, empty string, so that generic code used for both oneofs and
+ // singular fields can be written.
+ (*variables)["oneof_prefix"] = "";
}
void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor,
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h
index 0342c35e..088e5063 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_field.h
@@ -37,6 +37,9 @@
#include <map>
#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <string>
#include <google/protobuf/descriptor.h>
@@ -124,6 +127,16 @@ class FieldGenerator {
// Most field types don't need this, so the default implementation is empty.
virtual void GenerateDestructorCode(io::Printer* /*printer*/) const {}
+ // Generate 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().
+ // The method should return |true| if it generated any code that requires a
+ // call; this allows the message generator to eliminate the OwnDestructor()
+ // registration if no fields require it.
+ virtual bool GenerateArenaDestructorCode(io::Printer* printer) const {
+ return false;
+ }
+
// Generate code that allocates the fields's default instance.
virtual void GenerateDefaultInstanceAllocator(io::Printer* /*printer*/)
const {}
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index fa194273..dc8bf613 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -34,6 +34,9 @@
#include <google/protobuf/compiler/cpp/cpp_file.h>
#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <set>
#include <google/protobuf/compiler/cpp/cpp_enum.h>
@@ -102,6 +105,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
"#define PROTOBUF_$filename_identifier$__INCLUDED\n"
"\n"
"#include <string>\n"
+ "#include <stdint.h>\n" // INT32_MIN, INT32_MAX
"\n",
"filename", file_->name(),
"filename_identifier", filename_identifier);
@@ -131,7 +135,10 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
// OK, it's now safe to #include other files.
printer->Print(
- "#include <google/protobuf/generated_message_util.h>\n");
+ "#include <google/protobuf/arena.h>\n"
+ "#include <google/protobuf/arenastring.h>\n"
+ "#include <google/protobuf/generated_message_util.h>\n"
+ "#include <google/protobuf/metadata.h>\n");
if (file_->message_type_count() > 0) {
if (HasDescriptorMethods(file_)) {
printer->Print(
@@ -181,6 +188,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
"// @@protoc_insertion_point(includes)\n");
+
// Open namespace.
GenerateNamespaceOpeners(printer);
@@ -189,9 +197,10 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
printer->Print(
"\n"
"// Internal implementation detail -- do not call these.\n"
- "void $dllexport_decl$ $adddescriptorsname$();\n",
+ "void $dllexport_decl$$adddescriptorsname$();\n",
"adddescriptorsname", GlobalAddDescriptorsName(file_->name()),
- "dllexport_decl", options_.dllexport_decl);
+ "dllexport_decl",
+ options_.dllexport_decl.empty() ? "" : options_.dllexport_decl + " ");
printer->Print(
// Note that we don't put dllexport_decl on these because they are only
@@ -295,7 +304,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
}
printer->Print(
"\n"
- "} // namespace google\n} // namespace protobuf\n"
+ "} // namespace protobuf\n} // namespace google\n"
"#endif // SWIG\n");
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h
index 4e4d8b6a..13d06f98 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.h
+++ b/src/google/protobuf/compiler/cpp/cpp_file.h
@@ -36,6 +36,9 @@
#define GOOGLE_PROTOBUF_COMPILER_CPP_FILE_H__
#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <string>
#include <vector>
#include <google/protobuf/stubs/common.h>
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index 75d558ea..a2fb7162 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -36,6 +36,9 @@
#include <vector>
#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <utility>
#include <google/protobuf/compiler/cpp/cpp_file.h>
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index b7a47acb..63b0265e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -60,16 +60,17 @@ string DotsToColons(const string& name) {
}
const char* const kKeywordList[] = {
- "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case",
- "catch", "char", "class", "compl", "const", "const_cast", "continue",
- "default", "delete", "do", "double", "dynamic_cast", "else", "enum",
- "explicit", "extern", "false", "float", "for", "friend", "goto", "if",
- "inline", "int", "long", "mutable", "namespace", "new", "not", "not_eq",
- "operator", "or", "or_eq", "private", "protected", "public", "register",
- "reinterpret_cast", "return", "short", "signed", "sizeof", "static",
- "static_cast", "struct", "switch", "template", "this", "throw", "true", "try",
- "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual",
- "void", "volatile", "wchar_t", "while", "xor", "xor_eq"
+ "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor",
+ "bool", "break", "case", "catch", "char", "class", "compl", "const",
+ "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do",
+ "double", "dynamic_cast", "else", "enum", "explicit", "extern", "false",
+ "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable",
+ "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or",
+ "or_eq", "private", "protected", "public", "register", "reinterpret_cast",
+ "return", "short", "signed", "sizeof", "static", "static_assert",
+ "static_cast", "struct", "switch", "template", "this", "thread_local",
+ "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned",
+ "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq"
};
hash_set<string> MakeKeywordsMap() {
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index 5d30240c..1cff17c8 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -135,8 +135,15 @@ string SafeFunctionName(const Descriptor* descriptor,
const FieldDescriptor* field,
const string& prefix);
-// Do message classes in this file use UnknownFieldSet?
-// Otherwise, messages will store unknown fields in a string
+// Returns true if unknown fields are preseved after parsing.
+inline bool PreserveUnknownFields(const Descriptor* message) {
+ return message->file()->syntax() != FileDescriptor::SYNTAX_PROTO3;
+}
+
+// If PreserveUnknownFields() is true, determines whether unknown
+// fields will be stored in an UnknownFieldSet or a string.
+// If PreserveUnknownFields() is false, this method will not be
+// used.
inline bool UseUnknownFieldSet(const FileDescriptor* file) {
return file->options().optimize_for() != FileOptions::LITE_RUNTIME;
}
@@ -198,6 +205,28 @@ bool IsStringOrMessage(const FieldDescriptor* field);
string UnderscoresToCamelCase(const string& input, bool cap_next_letter);
+inline bool HasFieldPresence(const FileDescriptor* file) {
+ return file->syntax() != FileDescriptor::SYNTAX_PROTO3;
+}
+
+// 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 FileDescriptor* file) {
+ return file->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
+inline bool SupportsArenas(const FileDescriptor* file) {
+ return true;
+}
+
+inline bool SupportsArenas(const Descriptor* desc) {
+ return SupportsArenas(desc->file());
+}
+
+inline bool SupportsArenas(const FieldDescriptor* field) {
+ return SupportsArenas(field->file());
+}
+
} // namespace cpp
} // namespace compiler
} // namespace protobuf
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index 3a9d2639..54a92ae4 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -36,6 +36,9 @@
#include <google/protobuf/stubs/hash.h>
#include <map>
#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <set>
#include <utility>
#include <vector>
@@ -281,8 +284,67 @@ string MessageTypeProtoName(const FieldDescriptor* field) {
return field->message_type()->full_name();
}
+// Emits an if-statement with a condition that evaluates to true if |field| is
+// considered non-default (will be sent over the wire), for message types
+// without true field presence. Should only be called if
+// !HasFieldPresence(message_descriptor).
+bool EmitFieldNonDefaultCondition(io::Printer* printer,
+ const string& prefix,
+ const FieldDescriptor* field) {
+ // Merge and serialize semantics: primitive fields are merged/serialized only
+ // if non-zero (numeric) or non-empty (string).
+ if (!field->is_repeated() && !field->containing_oneof()) {
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) {
+ printer->Print(
+ "if ($prefix$$name$().size() > 0) {\n",
+ "prefix", prefix,
+ "name", FieldName(field));
+ } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ // Message fields still have has_$name$() methods.
+ printer->Print(
+ "if ($prefix$has_$name$()) {\n",
+ "prefix", prefix,
+ "name", FieldName(field));
+ } else {
+ printer->Print(
+ "if ($prefix$$name$() != 0) {\n",
+ "prefix", prefix,
+ "name", FieldName(field));
+ }
+ printer->Indent();
+ return true;
+ } else if (field->containing_oneof()) {
+ printer->Print(
+ "if (has_$name$()) {\n",
+ "name", FieldName(field));
+ printer->Indent();
+ return true;
+ }
+ return false;
+}
+
+// Does the given field have a has_$name$() method?
+bool HasHasMethod(const FieldDescriptor* field) {
+ if (HasFieldPresence(field->file())) {
+ // In proto1/proto2, every field has a has_$name$() method.
+ return true;
+ }
+ // For message types without true field presence, only fields with a message
+ // type have a has_$name$() method.
+ return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE;
}
+// Does the given field have a private (internal helper only) has_$name$()
+// method?
+bool HasPrivateHasMethod(const FieldDescriptor* field) {
+ // Only for oneofs in message types with no field presence. has_$name$(),
+ // based on the oneof case, is still useful internally for generated code.
+ return (!HasFieldPresence(field->file()) &&
+ field->containing_oneof() != NULL);
+}
+
+} // anonymous namespace
+
// ===================================================================
MessageGenerator::MessageGenerator(const Descriptor* descriptor,
@@ -312,6 +374,13 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
extension_generators_[i].reset(
new ExtensionGenerator(descriptor->extension(i), options));
}
+
+ num_required_fields_ = 0;
+ for (int i = 0; i < descriptor->field_count(); i++) {
+ if (descriptor->field(i)->is_required()) {
+ ++num_required_fields_;
+ }
+ }
}
MessageGenerator::~MessageGenerator() {}
@@ -360,8 +429,13 @@ GenerateFieldAccessorDeclarations(io::Printer* printer) {
if (field->is_repeated()) {
printer->Print(vars, "inline int $name$_size() const$deprecation$;\n");
- } else {
+ } else if (HasHasMethod(field)) {
printer->Print(vars, "inline bool has_$name$() const$deprecation$;\n");
+ } else if (HasPrivateHasMethod(field)) {
+ printer->Print(vars,
+ "private:\n"
+ "inline bool has_$name$() const$deprecation$;\n"
+ "public:\n");
}
printer->Print(vars, "inline void clear_$name$()$deprecation$;\n");
@@ -410,32 +484,59 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) {
"}\n");
} else if (field->containing_oneof()) {
// Singular field in a oneof
+ // N.B.: Without field presence, we do not use has-bits or generate
+ // has_$name$() methods, but oneofs still have set_has_$name$().
+ // Oneofs also have has_$name$() but only as a private helper
+ // method, so that generated code is slightly cleaner (vs. comparing
+ // _oneof_case_[index] against a constant everywhere).
vars["field_name"] = UnderscoresToCamelCase(field->name(), true);
vars["oneof_name"] = field->containing_oneof()->name();
vars["oneof_index"] = SimpleItoa(field->containing_oneof()->index());
printer->Print(vars,
"inline bool $classname$::has_$name$() const {\n"
" return $oneof_name$_case() == k$field_name$;\n"
- "}\n"
+ "}\n");
+ printer->Print(vars,
"inline void $classname$::set_has_$name$() {\n"
" _oneof_case_[$oneof_index$] = k$field_name$;\n"
"}\n");
} else {
// Singular field.
- char buffer[kFastToBufferSize];
- vars["has_array_index"] = SimpleItoa(field->index() / 32);
- vars["has_mask"] = FastHex32ToBuffer(1u << (field->index() % 32), buffer);
- printer->Print(vars,
- "inline bool $classname$::has_$name$() const {\n"
- " return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"
- "}\n"
- "inline void $classname$::set_has_$name$() {\n"
- " _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n"
- "}\n"
- "inline void $classname$::clear_has_$name$() {\n"
- " _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n"
- "}\n"
- );
+ if (HasFieldPresence(descriptor_->file())) {
+ // N.B.: without field presence, we do not use has-bits or generate
+ // has_$name$() methods.
+ char buffer[kFastToBufferSize];
+ vars["has_array_index"] = SimpleItoa(field->index() / 32);
+ vars["has_mask"] = FastHex32ToBuffer(1u << (field->index() % 32),
+ buffer);
+ printer->Print(vars,
+ "inline bool $classname$::has_$name$() const {\n"
+ " return (_has_bits_[$has_array_index$] & 0x$has_mask$u) != 0;\n"
+ "}\n"
+ "inline void $classname$::set_has_$name$() {\n"
+ " _has_bits_[$has_array_index$] |= 0x$has_mask$u;\n"
+ "}\n"
+ "inline void $classname$::clear_has_$name$() {\n"
+ " _has_bits_[$has_array_index$] &= ~0x$has_mask$u;\n"
+ "}\n"
+ );
+ } else {
+ // Message fields have a has_$name$() method.
+ if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) {
+ bool is_lazy = false;
+ if (is_lazy) {
+ printer->Print(vars,
+ "inline bool $classname$::has_$name$() const {\n"
+ " return !$name$_.IsCleared();\n"
+ "}\n");
+ } else {
+ printer->Print(vars,
+ "inline bool $classname$::has_$name$() const {\n"
+ " return $name$_ != NULL;\n"
+ "}\n");
+ }
+ }
+ }
}
// Generate clear_$name$()
@@ -457,9 +558,11 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) {
printer->Print("}\n");
} else {
field_generators_.get(field).GenerateClearingCode(printer);
- if (!field->is_repeated()) {
- printer->Print(vars,
- "clear_has_$name$();\n");
+ if (HasFieldPresence(descriptor_->file())) {
+ if (!field->is_repeated()) {
+ printer->Print(vars,
+ "clear_has_$name$();\n");
+ }
}
}
@@ -553,26 +656,41 @@ GenerateClassDefinition(io::Printer* printer) {
"}\n"
"\n");
- if (UseUnknownFieldSet(descriptor_->file())) {
- printer->Print(
- "inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {\n"
- " return _unknown_fields_;\n"
- "}\n"
- "\n"
- "inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {\n"
- " return &_unknown_fields_;\n"
- "}\n"
- "\n");
- } else {
+ if (PreserveUnknownFields(descriptor_)) {
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(
+ "inline const ::google::protobuf::UnknownFieldSet& unknown_fields() const {\n"
+ " return _internal_metadata_.unknown_fields();\n"
+ "}\n"
+ "\n"
+ "inline ::google::protobuf::UnknownFieldSet* mutable_unknown_fields() {\n"
+ " return _internal_metadata_.mutable_unknown_fields();\n"
+ "}\n"
+ "\n");
+ } else {
+ printer->Print(
+ "inline const ::std::string& unknown_fields() const {\n"
+ " return _unknown_fields_;\n"
+ "}\n"
+ "\n"
+ "inline ::std::string* mutable_unknown_fields() {\n"
+ " return &_unknown_fields_;\n"
+ "}\n"
+ "\n");
+ }
+ }
+
+ // N.B.: We exclude GetArena() when arena support is disabled, falling back on
+ // MessageLite's implementation which returns NULL rather than generating our
+ // own method which returns NULL, in order to reduce code size.
+ if (SupportsArenas(descriptor_)) {
+ // virtual method version of GetArenaNoVirtual(), required for generic dispatch given a
+ // MessageLite* (e.g., in RepeatedField::AddAllocated()).
printer->Print(
- "inline const ::std::string& unknown_fields() const {\n"
- " return _unknown_fields_;\n"
- "}\n"
- "\n"
- "inline ::std::string* mutable_unknown_fields() {\n"
- " return &_unknown_fields_;\n"
- "}\n"
- "\n");
+ "inline ::google::protobuf::Arena* GetArena() const { return GetArenaNoVirtual(); }\n"
+ "inline void* GetMaybeArenaPointer() const {\n"
+ " return MaybeArenaPtr();\n"
+ "}\n");
}
// Only generate this member if it's not disabled.
@@ -628,12 +746,18 @@ GenerateClassDefinition(io::Printer* printer) {
}
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(vars,
+ "void UnsafeArenaSwap($classname$* other);\n");
+ }
printer->Print(vars,
"void Swap($classname$* other);\n"
"\n"
"// implements Message ----------------------------------------------\n"
"\n"
- "$classname$* New() const;\n");
+ "inline $classname$* New() const { return New(NULL); }\n"
+ "\n"
+ "$classname$* New(::google::protobuf::Arena* arena) const;\n");
if (HasGeneratedMethods(descriptor_->file())) {
if (HasDescriptorMethods(descriptor_->file())) {
@@ -699,7 +823,41 @@ GenerateClassDefinition(io::Printer* printer) {
"void SharedCtor();\n"
"void SharedDtor();\n"
"void SetCachedSize(int size) const;\n"
- "public:\n");
+ "void InternalSwap($classname$* other);\n",
+ "classname", classname_);
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(
+ "protected:\n"
+ "explicit $classname$(::google::protobuf::Arena* arena);\n"
+ "private:\n"
+ "static void ArenaDtor(void* object);\n"
+ "inline void RegisterArenaDtor(::google::protobuf::Arena* arena);\n",
+ "classname", classname_);
+ }
+
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(
+ "private:\n"
+ "inline ::google::protobuf::Arena* GetArenaNoVirtual() const {\n"
+ " return _internal_metadata_.arena();\n"
+ "}\n"
+ "inline void* MaybeArenaPtr() const {\n"
+ " return _internal_metadata_.raw_arena_ptr();\n"
+ "}\n"
+ "public:\n"
+ "\n");
+ } else {
+ printer->Print(
+ "private:\n"
+ "inline ::google::protobuf::Arena* GetArenaNoVirtual() const {\n"
+ " return _arena_ptr_;\n"
+ "}\n"
+ "inline ::google::protobuf::Arena* MaybeArenaPtr() const {\n"
+ " return _arena_ptr_;\n"
+ "}\n"
+ "public:\n"
+ "\n");
+ }
if (HasDescriptorMethods(descriptor_->file())) {
printer->Print(
@@ -759,10 +917,18 @@ GenerateClassDefinition(io::Printer* printer) {
for (int i = 0; i < descriptor_->field_count(); i++) {
if (!descriptor_->field(i)->is_repeated()) {
- printer->Print(
- "inline void set_has_$name$();\n",
- "name", FieldName(descriptor_->field(i)));
- if (!descriptor_->field(i)->containing_oneof()) {
+ // set_has_***() generated in all proto1/2 code and in oneofs (only) for
+ // messages without true field presence.
+ if (HasFieldPresence(descriptor_->file()) ||
+ descriptor_->field(i)->containing_oneof()) {
+ printer->Print(
+ "inline void set_has_$name$();\n",
+ "name", FieldName(descriptor_->field(i)));
+ }
+ // clear_has_***() generated only for non-oneof fields
+ // in proto1/2.
+ if (!descriptor_->field(i)->containing_oneof() &&
+ HasFieldPresence(descriptor_->file())) {
printer->Print(
"inline void clear_has_$name$();\n",
"name", FieldName(descriptor_->field(i)));
@@ -780,6 +946,14 @@ GenerateClassDefinition(io::Printer* printer) {
"oneof_name", descriptor_->oneof_decl(i)->name());
}
+ if (HasGeneratedMethods(descriptor_->file()) &&
+ !descriptor_->options().message_set_wire_format() &&
+ num_required_fields_ > 1) {
+ printer->Print(
+ "// helper for ByteSize()\n"
+ "int RequiredFieldsByteSizeFallback() const;\n\n");
+ }
+
// Prepare decls for _cached_size_ and _has_bits_. Their position in the
// output will be determined later.
@@ -816,23 +990,32 @@ GenerateClassDefinition(io::Printer* printer) {
if (UseUnknownFieldSet(descriptor_->file())) {
printer->Print(
- "::google::protobuf::UnknownFieldSet _unknown_fields_;\n"
- "\n");
+ "::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_;\n");
} else {
printer->Print(
"::std::string _unknown_fields_;\n"
+ "::google::protobuf::Arena* _arena_ptr_;\n"
"\n");
}
- // _has_bits_ is frequently accessed, so to reduce code size and improve
- // speed, it should be close to the start of the object. But, try not to
- // waste space:_has_bits_ by itself always makes sense if its size is a
- // multiple of 8, but, otherwise, maybe _has_bits_ and cached_size_ together
- // will work well.
- printer->Print(has_bits_decl.c_str());
- if ((sizeof_has_bits % 8) != 0) {
- printer->Print(cached_size_decl.c_str());
- need_to_emit_cached_size = false;
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(
+ "friend class ::google::protobuf::Arena;\n"
+ "typedef void InternalArenaConstructable_;\n"
+ "typedef void DestructorSkippable_;\n");
+ }
+
+ if (HasFieldPresence(descriptor_->file())) {
+ // _has_bits_ is frequently accessed, so to reduce code size and improve
+ // speed, it should be close to the start of the object. But, try not to
+ // waste space:_has_bits_ by itself always makes sense if its size is a
+ // multiple of 8, but, otherwise, maybe _has_bits_ and cached_size_ together
+ // will work well.
+ printer->Print(has_bits_decl.c_str());
+ if ((sizeof_has_bits % 8) != 0) {
+ printer->Print(cached_size_decl.c_str());
+ need_to_emit_cached_size = false;
+ }
}
// Field members:
@@ -871,7 +1054,10 @@ GenerateClassDefinition(io::Printer* printer) {
// For each oneof generate a union
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
printer->Print(
- "union $camel_oneof_name$Union {\n",
+ "union $camel_oneof_name$Union {\n"
+ // explicit empty constructor is needed when union contains
+ // ArenaStringPtr members for string fields.
+ " $camel_oneof_name$Union() {}\n",
"camel_oneof_name",
UnderscoresToCamelCase(descriptor_->oneof_decl(i)->name(), true));
printer->Indent();
@@ -1029,10 +1215,28 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) {
" new ::google::protobuf::internal::GeneratedMessageReflection(\n"
" $classname$_descriptor_,\n"
" $classname$::default_instance_,\n"
- " $classname$_offsets_,\n"
- " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, _has_bits_[0]),\n"
+ " $classname$_offsets_,\n");
+ if (!HasFieldPresence(descriptor_->file())) {
+ // If we don't have field presence, then _has_bits_ does not exist.
+ printer->Print(vars,
+ " -1,\n");
+ } else {
+ printer->Print(vars,
+ " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET($classname$, _has_bits_[0]),\n");
+ }
+
+ // Unknown field offset: either points to the unknown field set if embedded
+ // directly, or indicates that the unknown field set is stored as part of the
+ // internal metadata if not.
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(vars,
+ " -1,\n");
+ } else {
+ printer->Print(vars,
" GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
"$classname$, _unknown_fields_),\n");
+ }
+
if (descriptor_->extension_range_count() > 0) {
printer->Print(vars,
" GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
@@ -1054,8 +1258,23 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) {
" ::google::protobuf::DescriptorPool::generated_pool(),\n");
printer->Print(vars,
" ::google::protobuf::MessageFactory::generated_factory(),\n");
+
printer->Print(vars,
- " sizeof($classname$));\n");
+ " sizeof($classname$),\n");
+
+ // Arena offset: either an offset to the metadata struct that contains the
+ // arena pointer and unknown field set (in a space-efficient way) if we use
+ // that implementation strategy, or an offset directly to the arena pointer if
+ // not (because e.g. we don't have an unknown field set).
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(vars,
+ " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
+ "$classname$, _internal_metadata_));\n");
+ } else {
+ printer->Print(vars,
+ " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET("
+ "$classname$, _arena_));\n");
+ }
// Handle nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
@@ -1100,7 +1319,7 @@ GenerateDefaultInstanceAllocator(io::Printer* printer) {
if ((descriptor_->oneof_decl_count() > 0) &&
HasDescriptorMethods(descriptor_->file())) {
printer->Print(
- "$classname$_default_oneof_instance_ = new $classname$OneofInstance;\n",
+ "$classname$_default_oneof_instance_ = new $classname$OneofInstance();\n",
"classname", classname_);
}
@@ -1312,8 +1531,10 @@ GenerateSharedConstructorCode(io::Printer* printer) {
}
}
- printer->Print(
- "::memset(_has_bits_, 0, sizeof(_has_bits_));\n");
+ if (HasFieldPresence(descriptor_->file())) {
+ printer->Print(
+ "::memset(_has_bits_, 0, sizeof(_has_bits_));\n");
+ }
for (int i = 0; i < descriptor_->oneof_decl_count(); i++) {
printer->Print(
@@ -1331,6 +1552,14 @@ GenerateSharedDestructorCode(io::Printer* printer) {
"void $classname$::SharedDtor() {\n",
"classname", classname_);
printer->Indent();
+ if (SupportsArenas(descriptor_)) {
+ // Do nothing when the message is allocated in an arena.
+ printer->Print(
+ "if (GetArenaNoVirtual() != NULL) {\n"
+ " return;\n"
+ "}\n"
+ "\n");
+ }
// Write the destructors for each field except oneof members.
for (int i = 0; i < descriptor_->field_count(); i++) {
if (!descriptor_->field(i)->containing_oneof()) {
@@ -1381,19 +1610,107 @@ GenerateSharedDestructorCode(io::Printer* printer) {
}
void MessageGenerator::
+GenerateArenaDestructorCode(io::Printer* printer) {
+ // Generate the ArenaDtor() method. Track whether any fields actually produced
+ // code that needs to be called.
+ printer->Print(
+ "void $classname$::ArenaDtor(void* object) {\n",
+ "classname", classname_);
+ printer->Indent();
+
+ // This code is placed inside a static method, rather than an ordinary one,
+ // since that simplifies Arena's destructor list (ordinary function pointers
+ // rather than member function pointers). _this is the object being
+ // destructed.
+ printer->Print(
+ "$classname$* _this = reinterpret_cast< $classname$* >(object);\n"
+ // avoid an "unused variable" warning in case no fields have dtor code.
+ "(void)_this;\n",
+ "classname", classname_);
+
+ bool need_registration = false;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ if (field_generators_.get(descriptor_->field(i))
+ .GenerateArenaDestructorCode(printer)) {
+ need_registration = true;
+ }
+ }
+ printer->Outdent();
+ printer->Print(
+ "}\n");
+
+ if (need_registration) {
+ printer->Print(
+ "inline void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n"
+ " if (arena != NULL) {"
+ " arena->OwnCustomDestructor(this, &$classname$::ArenaDtor);\n"
+ " }\n"
+ "}\n",
+ "classname", classname_);
+ } else {
+ printer->Print(
+ "void $classname$::RegisterArenaDtor(::google::protobuf::Arena* arena) {\n"
+ "}\n",
+ "classname", classname_);
+ }
+}
+
+void MessageGenerator::
GenerateStructors(io::Printer* printer) {
string superclass = SuperClassName(descriptor_);
+ string initializer_with_arena;
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ initializer_with_arena = "_internal_metadata_(arena)";
+ } else {
+ initializer_with_arena = "_arena_ptr_(arena)";
+ }
+ if (descriptor_->extension_range_count() > 0) {
+ initializer_with_arena = string("\n _extensions_(arena)") +
+ (!initializer_with_arena.empty() ? ", " : "") + initializer_with_arena;
+ } else {
+ initializer_with_arena = "\n " + initializer_with_arena;
+ }
+
+ // Initialize member variables with arena constructor.
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ bool has_arena_constructor = descriptor_->field(i)->is_repeated();
+ if (has_arena_constructor) {
+ initializer_with_arena += string(",\n ") +
+ FieldName(descriptor_->field(i)) + string("_(arena)");
+ }
+ }
+ initializer_with_arena = superclass + "()" +
+ (!initializer_with_arena.empty() ? "," : " ") + initializer_with_arena;
+
+ string initializer_null;
+ initializer_null = (UseUnknownFieldSet(descriptor_->file()) ?
+ ", _internal_metadata_(NULL) " : ", _arena_ptr_(NULL)");
- // Generate the default constructor.
printer->Print(
- "$classname$::$classname$()\n"
- " : $superclass$() {\n"
- " SharedCtor();\n"
- " // @@protoc_insertion_point(constructor:$full_name$)\n"
- "}\n",
- "classname", classname_,
- "superclass", superclass,
- "full_name", descriptor_->full_name());
+ "$classname$::$classname$()\n"
+ " : $superclass$() $initializer$ {\n"
+ " SharedCtor();\n"
+ " // @@protoc_insertion_point(constructor:$full_name$)\n"
+ "}\n",
+ "classname", classname_,
+ "superclass", superclass,
+ "full_name", descriptor_->full_name(),
+ "initializer", initializer_null);
+
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(
+ "\n"
+ "$classname$::$classname$(::google::protobuf::Arena* arena)\n"
+ " : $initializer$ {\n"
+ " SharedCtor();\n"
+ " RegisterArenaDtor(arena);\n"
+ " // @@protoc_insertion_point(arena_constructor:$full_name$)\n"
+ "}\n",
+ "initializer", initializer_with_arena,
+ "classname", classname_,
+ "superclass", superclass,
+ "full_name", descriptor_->full_name());
+ }
printer->Print(
"\n"
@@ -1441,7 +1758,17 @@ GenerateStructors(io::Printer* printer) {
// Generate the copy constructor.
printer->Print(
"$classname$::$classname$(const $classname$& from)\n"
- " : $superclass$() {\n"
+ " : $superclass$()",
+ "classname", classname_,
+ "superclass", superclass,
+ "full_name", descriptor_->full_name());
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(
+ ",\n _internal_metadata_(NULL) {\n");
+ } else if (!UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(",\n _arena_ptr_(NULL) {\n");
+ }
+ printer->Print(
" SharedCtor();\n"
" MergeFrom(from);\n"
" // @@protoc_insertion_point(copy_constructor:$full_name$)\n"
@@ -1467,6 +1794,11 @@ GenerateStructors(io::Printer* printer) {
// Generate the shared destructor code.
GenerateSharedDestructorCode(printer);
+ // Generate the arena-specific destructor code.
+ if (SupportsArenas(descriptor_)) {
+ GenerateArenaDestructorCode(printer);
+ }
+
// Generate SetCachedSize.
printer->Print(
"void $classname$::SetCachedSize(int size) const {\n"
@@ -1512,11 +1844,23 @@ GenerateStructors(io::Printer* printer) {
"\n",
"classname", classname_);
- printer->Print(
- "$classname$* $classname$::New() const {\n"
- " return new $classname$;\n"
- "}\n",
- "classname", classname_);
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(
+ "$classname$* $classname$::New(::google::protobuf::Arena* arena) const {\n"
+ " return ::google::protobuf::Arena::CreateMessage<$classname$>(arena);\n"
+ "}\n",
+ "classname", classname_);
+ } else {
+ printer->Print(
+ "$classname$* $classname$::New(::google::protobuf::Arena* arena) const {\n"
+ " $classname$* n = new $classname$;\n"
+ " if (arena != NULL) {\n"
+ " arena->Own(n);\n"
+ " }\n"
+ " return n;\n"
+ "}\n",
+ "classname", classname_);
+ }
}
@@ -1616,16 +1960,19 @@ GenerateClear(io::Printer* printer) {
const string& memsets = memsets_for_chunk[i / 8];
uint32 mask = fields_mask_for_chunk[i / 8];
int count = popcnt(mask);
+ GOOGLE_DCHECK_GE(count, 1);
if (count == 1 ||
(count <= 4 && count == memset_field_count_for_chunk[i / 8])) {
// No "if" here because the chunk is trivial.
} else {
- printer->Print(
- "if (_has_bits_[$index$ / 32] & $mask$) {\n",
- "index", SimpleItoa(i / 8 * 8),
- "mask", SimpleItoa(mask));
- printer->Indent();
- chunk_block_in_progress = true;
+ if (HasFieldPresence(descriptor_->file())) {
+ printer->Print(
+ "if (_has_bits_[$index$ / 32] & $mask$) {\n",
+ "index", SimpleItoa(i / 8 * 8),
+ "mask", SimpleItoa(mask));
+ printer->Indent();
+ chunk_block_in_progress = true;
+ }
}
printer->Print(memsets.c_str());
}
@@ -1639,14 +1986,18 @@ GenerateClear(io::Printer* printer) {
field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE ||
field->cpp_type() == FieldDescriptor::CPPTYPE_STRING;
- if (should_check_bit) {
+ bool have_enclosing_if = false;
+ if (should_check_bit &&
+ // If no field presence, then always clear strings/messages as well.
+ HasFieldPresence(descriptor_->file())) {
printer->Print("if (has_$name$()) {\n", "name", fieldname);
printer->Indent();
+ have_enclosing_if = true;
}
field_generators_.get(field).GenerateClearingCode(printer);
- if (should_check_bit) {
+ if (have_enclosing_if) {
printer->Outdent();
printer->Print("}\n");
}
@@ -1678,16 +2029,22 @@ GenerateClear(io::Printer* printer) {
"oneof_name", descriptor_->oneof_decl(i)->name());
}
- // Step 5: Everything else.
- printer->Print(
- "::memset(_has_bits_, 0, sizeof(_has_bits_));\n");
-
- if (UseUnknownFieldSet(descriptor_->file())) {
+ if (HasFieldPresence(descriptor_->file())) {
+ // Step 5: Everything else.
printer->Print(
- "mutable_unknown_fields()->Clear();\n");
- } else {
- printer->Print(
- "mutable_unknown_fields()->clear();\n");
+ "::memset(_has_bits_, 0, sizeof(_has_bits_));\n");
+ }
+
+ if (PreserveUnknownFields(descriptor_)) {
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(
+ "if (_internal_metadata_.have_unknown_fields()) {\n"
+ " mutable_unknown_fields()->Clear();\n"
+ "}\n");
+ } else {
+ printer->Print(
+ "mutable_unknown_fields()->clear();\n");
+ }
}
printer->Outdent();
@@ -1748,12 +2105,42 @@ GenerateOneofClear(io::Printer* printer) {
void MessageGenerator::
GenerateSwap(io::Printer* printer) {
- // Generate the Swap member function.
- printer->Print("void $classname$::Swap($classname$* other) {\n",
+ if (SupportsArenas(descriptor_)) {
+ // Generate the Swap member function. This is a lightweight wrapper around
+ // UnsafeArenaSwap() / MergeFrom() with temporaries, depending on the memory
+ // ownership situation: swapping across arenas or between an arena and a
+ // heap requires copying.
+ printer->Print(
+ "void $classname$::Swap($classname$* other) {\n"
+ " if (other == this) return;\n"
+ " if (GetArenaNoVirtual() == other->GetArenaNoVirtual()) {\n"
+ " InternalSwap(other);\n"
+ " } else {\n"
+ " $classname$ temp;\n"
+ " temp.MergeFrom(*this);\n"
+ " CopyFrom(*other);\n"
+ " other->CopyFrom(temp);\n"
+ " }\n"
+ "}\n"
+ "void $classname$::UnsafeArenaSwap($classname$* other) {\n"
+ " if (other == this) return;\n"
+ " GOOGLE_DCHECK(GetArenaNoVirtual() == other->GetArenaNoVirtual());\n"
+ " InternalSwap(other);\n"
+ "}\n",
+ "classname", classname_);
+ } else {
+ printer->Print(
+ "void $classname$::Swap($classname$* other) {\n"
+ " if (other == this) return;\n"
+ " InternalSwap(other);\n"
+ "}\n",
+ "classname", classname_);
+ }
+
+ // Generate the UnsafeArenaSwap member function.
+ printer->Print("void $classname$::InternalSwap($classname$* other) {\n",
"classname", classname_);
printer->Indent();
- printer->Print("if (other != this) {\n");
- printer->Indent();
if (HasGeneratedMethods(descriptor_->file())) {
for (int i = 0; i < descriptor_->field_count(); i++) {
@@ -1769,15 +2156,25 @@ GenerateSwap(io::Printer* printer) {
"i", SimpleItoa(i));
}
- for (int i = 0; i < (descriptor_->field_count() + 31) / 32; ++i) {
- printer->Print("std::swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n",
- "i", SimpleItoa(i));
+ if (HasFieldPresence(descriptor_->file())) {
+ for (int i = 0; i < (descriptor_->field_count() + 31) / 32; ++i) {
+ printer->Print("std::swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n",
+ "i", SimpleItoa(i));
+ }
}
- if (UseUnknownFieldSet(descriptor_->file())) {
- printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n");
+ if (PreserveUnknownFields(descriptor_)) {
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(
+ "_internal_metadata_.Swap(&other->_internal_metadata_);\n");
+ } else {
+ printer->Print("_unknown_fields_.swap(other->_unknown_fields_);\n");
+ }
} else {
- printer->Print("_unknown_fields_.swap(other->_unknown_fields_);\n");
+ // Still swap internal_metadata as it may contain more than just
+ // unknown fields.
+ printer->Print(
+ "_internal_metadata_.Swap(&other->_internal_metadata_);\n");
}
printer->Print("std::swap(_cached_size_, other->_cached_size_);\n");
if (descriptor_->extension_range_count() > 0) {
@@ -1789,8 +2186,6 @@ GenerateSwap(io::Printer* printer) {
printer->Outdent();
printer->Print("}\n");
- printer->Outdent();
- printer->Print("}\n");
}
void MessageGenerator::
@@ -1886,33 +2281,48 @@ GenerateMergeFrom(io::Printer* printer) {
const FieldDescriptor* field = descriptor_->field(i);
if (!field->is_repeated() && !field->containing_oneof()) {
- // See above in GenerateClear for an explanation of this.
- if (i / 8 != last_index / 8 || last_index < 0) {
- if (last_index >= 0) {
- printer->Outdent();
- printer->Print("}\n");
+ if (HasFieldPresence(descriptor_->file())) {
+ // See above in GenerateClear for an explanation of this.
+ if (i / 8 != last_index / 8 || last_index < 0) {
+ if (last_index >= 0) {
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ printer->Print(
+ "if (from._has_bits_[$index$ / 32] & "
+ "(0xffu << ($index$ % 32))) {\n",
+ "index", SimpleItoa(field->index()));
+ printer->Indent();
}
- printer->Print(
- "if (from._has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n",
- "index", SimpleItoa(field->index()));
- printer->Indent();
}
last_index = i;
- printer->Print(
- "if (from.has_$name$()) {\n",
- "name", FieldName(field));
- printer->Indent();
+ bool have_enclosing_if = false;
+ if (HasFieldPresence(descriptor_->file())) {
+ printer->Print(
+ "if (from.has_$name$()) {\n",
+ "name", FieldName(field));
+ printer->Indent();
+ have_enclosing_if = true;
+ } else {
+ // Merge semantics without true field presence: primitive fields are
+ // merged only if non-zero (numeric) or non-empty (string).
+ have_enclosing_if = EmitFieldNonDefaultCondition(
+ printer, "from.", field);
+ }
field_generators_.get(field).GenerateMergingCode(printer);
- printer->Outdent();
- printer->Print("}\n");
+ if (have_enclosing_if) {
+ printer->Outdent();
+ printer->Print("}\n");
+ }
}
}
- if (last_index >= 0) {
+ if (HasFieldPresence(descriptor_->file()) &&
+ last_index >= 0) {
printer->Outdent();
printer->Print("}\n");
}
@@ -1921,12 +2331,16 @@ GenerateMergeFrom(io::Printer* printer) {
printer->Print("_extensions_.MergeFrom(from._extensions_);\n");
}
- if (UseUnknownFieldSet(descriptor_->file())) {
- printer->Print(
- "mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n");
- } else {
- printer->Print(
- "mutable_unknown_fields()->append(from.unknown_fields());\n");
+ if (PreserveUnknownFields(descriptor_)) {
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(
+ "if (from._internal_metadata_.have_unknown_fields()) {\n"
+ " mutable_unknown_fields()->MergeFrom(from.unknown_fields());\n"
+ "}\n");
+ } else {
+ printer->Print(
+ "mutable_unknown_fields()->append(from.unknown_fields());\n");
+ }
}
printer->Outdent();
@@ -2171,24 +2585,33 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
}
}
printer->Print(") {\n");
- if (UseUnknownFieldSet(descriptor_->file())) {
- PrintHandlingOptionalStaticInitializers(
- descriptor_->file(), printer,
- // With static initializers.
- " DO_(_extensions_.ParseField(tag, input, default_instance_,\n"
- " mutable_unknown_fields()));\n",
- // Without.
- " DO_(_extensions_.ParseField(tag, input, &default_instance(),\n"
- " mutable_unknown_fields()));\n");
+ if (PreserveUnknownFields(descriptor_)) {
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ PrintHandlingOptionalStaticInitializers(
+ descriptor_->file(), printer,
+ // With static initializers.
+ " DO_(_extensions_.ParseField(tag, input, default_instance_,\n"
+ " mutable_unknown_fields()));\n",
+ // Without.
+ " DO_(_extensions_.ParseField(tag, input, &default_instance(),\n"
+ " mutable_unknown_fields()));\n");
+ } else {
+ PrintHandlingOptionalStaticInitializers(
+ descriptor_->file(), printer,
+ // With static initializers.
+ " DO_(_extensions_.ParseField(tag, input, default_instance_,\n"
+ " &unknown_fields_stream));\n",
+ // Without.
+ " DO_(_extensions_.ParseField(tag, input, &default_instance(),\n"
+ " &unknown_fields_stream));\n");
+ }
} else {
PrintHandlingOptionalStaticInitializers(
descriptor_->file(), printer,
// With static initializers.
- " DO_(_extensions_.ParseField(tag, input, default_instance_,\n"
- " &unknown_fields_stream));\n",
+ " DO_(_extensions_.ParseField(tag, input, default_instance_);\n",
// Without.
- " DO_(_extensions_.ParseField(tag, input, &default_instance(),\n"
- " &unknown_fields_stream));\n");
+ " DO_(_extensions_.ParseField(tag, input, &default_instance());\n");
}
printer->Print(
" continue;\n"
@@ -2196,14 +2619,19 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
}
// We really don't recognize this tag. Skip it.
- if (UseUnknownFieldSet(descriptor_->file())) {
- printer->Print(
- "DO_(::google::protobuf::internal::WireFormat::SkipField(\n"
- " input, tag, mutable_unknown_fields()));\n");
+ if (PreserveUnknownFields(descriptor_)) {
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(
+ "DO_(::google::protobuf::internal::WireFormat::SkipField(\n"
+ " input, tag, mutable_unknown_fields()));\n");
+ } else {
+ printer->Print(
+ "DO_(::google::protobuf::internal::WireFormatLite::SkipField(\n"
+ " input, tag, &unknown_fields_stream));\n");
+ }
} else {
printer->Print(
- "DO_(::google::protobuf::internal::WireFormatLite::SkipField(\n"
- " input, tag, &unknown_fields_stream));\n");
+ "DO_(::google::protobuf::internal::WireFormatLite::SkipField(input, tag));\n");
}
if (descriptor_->field_count() > 0) {
@@ -2232,11 +2660,15 @@ void MessageGenerator::GenerateSerializeOneField(
io::Printer* printer, const FieldDescriptor* field, bool to_array) {
PrintFieldComment(printer, field);
- if (!field->is_repeated()) {
+ bool have_enclosing_if = false;
+ if (!field->is_repeated() && HasFieldPresence(descriptor_->file())) {
printer->Print(
"if (has_$name$()) {\n",
"name", FieldName(field));
printer->Indent();
+ have_enclosing_if = true;
+ } else if (!HasFieldPresence(descriptor_->file())) {
+ have_enclosing_if = EmitFieldNonDefaultCondition(printer, "this->", field);
}
if (to_array) {
@@ -2246,7 +2678,7 @@ void MessageGenerator::GenerateSerializeOneField(
field_generators_.get(field).GenerateSerializeWithCachedSizes(printer);
}
- if (!field->is_repeated()) {
+ if (have_enclosing_if) {
printer->Outdent();
printer->Print("}\n");
}
@@ -2386,28 +2818,69 @@ GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
}
}
- if (UseUnknownFieldSet(descriptor_->file())) {
- printer->Print("if (!unknown_fields().empty()) {\n");
- printer->Indent();
- if (to_array) {
+ if (PreserveUnknownFields(descriptor_)) {
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print("if (_internal_metadata_.have_unknown_fields()) {\n");
+ printer->Indent();
+ if (to_array) {
+ printer->Print(
+ "target = "
+ "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n"
+ " unknown_fields(), target);\n");
+ } else {
+ printer->Print(
+ "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n"
+ " unknown_fields(), output);\n");
+ }
+ printer->Outdent();
+
printer->Print(
- "target = "
- "::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray(\n"
- " unknown_fields(), target);\n");
+ "}\n");
} else {
printer->Print(
- "::google::protobuf::internal::WireFormat::SerializeUnknownFields(\n"
- " unknown_fields(), output);\n");
+ "output->WriteRaw(unknown_fields().data(),\n"
+ " unknown_fields().size());\n");
}
- printer->Outdent();
+ }
+}
- printer->Print(
- "}\n");
- } else {
- printer->Print(
- "output->WriteRaw(unknown_fields().data(),\n"
- " unknown_fields().size());\n");
+static vector<uint32> RequiredFieldsBitMask(const Descriptor* desc) {
+ vector<uint32> result;
+ uint32 mask = 0;
+ for (int i = 0; i < desc->field_count(); i++) {
+ if (i > 0 && i % 32 == 0) {
+ result.push_back(mask);
+ mask = 0;
+ }
+ if (desc->field(i)->is_required()) {
+ mask |= (1 << (i & 31));
+ }
+ }
+ if (mask != 0) {
+ result.push_back(mask);
}
+ return result;
+}
+
+// Create an expression that evaluates to
+// "for all i, (_has_bits_[i] & masks[i]) == masks[i]"
+// masks is allowed to be shorter than _has_bits_, but at least one element of
+// masks must be non-zero.
+static string ConditionalToCheckBitmasks(const vector<uint32>& masks) {
+ vector<string> parts;
+ for (int i = 0; i < masks.size(); i++) {
+ if (masks[i] == 0) continue;
+ char buffer[kFastToBufferSize];
+ FastHex32ToBuffer(masks[i], buffer);
+ string m = StrCat("0x", buffer);
+ // Each xor evaluates to 0 if the expected bits are present.
+ parts.push_back(StrCat("((_has_bits_[", i, "] & ", m, ") ^ ", m, ")"));
+ }
+ GOOGLE_CHECK(!parts.empty());
+ // If we have multiple parts, each expected to be 0, then bitwise-or them.
+ string result = parts.size() == 1 ? parts[0] :
+ StrCat("(", Join(parts, "\n | "), ")");
+ return result + " == 0";
}
void MessageGenerator::
@@ -2420,8 +2893,10 @@ GenerateByteSize(io::Printer* printer) {
"classname", classname_);
GOOGLE_CHECK(UseUnknownFieldSet(descriptor_->file()));
printer->Print(
+ "if (_internal_metadata_.have_unknown_fields()) {\n"
" total_size += ::google::protobuf::internal::WireFormat::\n"
- " ComputeUnknownMessageSetItemsSize(unknown_fields());\n");
+ " ComputeUnknownMessageSetItemsSize(unknown_fields());\n"
+ "}\n");
printer->Print(
" GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n"
" _cached_size_ = total_size;\n"
@@ -2431,6 +2906,33 @@ GenerateByteSize(io::Printer* printer) {
return;
}
+ if (num_required_fields_ > 1 && HasFieldPresence(descriptor_->file())) {
+ // Emit a function (rarely used, we hope) that handles the required fields
+ // by checking for each one individually.
+ printer->Print(
+ "int $classname$::RequiredFieldsByteSizeFallback() const {\n",
+ "classname", classname_);
+ printer->Indent();
+ printer->Print("int total_size = 0;\n");
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (field->is_required()) {
+ printer->Print("\n"
+ "if (has_$name$()) {\n",
+ "name", FieldName(field));
+ printer->Indent();
+ PrintFieldComment(printer, field);
+ field_generators_.get(field).GenerateByteSize(printer);
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ }
+ printer->Print("\n"
+ "return total_size;\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+
printer->Print(
"int $classname$::ByteSize() const {\n",
"classname", classname_);
@@ -2439,45 +2941,121 @@ GenerateByteSize(io::Printer* printer) {
"int total_size = 0;\n"
"\n");
- int last_index = -1;
+ // Handle required fields (if any). We expect all of them to be
+ // present, so emit one conditional that checks for that. If they are all
+ // present then the fast path executes; otherwise the slow path executes.
+ if (num_required_fields_ > 1 && HasFieldPresence(descriptor_->file())) {
+ // The fast path works if all required fields are present.
+ vector<uint32> masks_for_has_bits = RequiredFieldsBitMask(descriptor_);
+ printer->Print((string("if (") +
+ ConditionalToCheckBitmasks(masks_for_has_bits) +
+ ") { // All required fields are present.\n").c_str());
+ printer->Indent();
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (!field->is_required()) continue;
+ PrintFieldComment(printer, field);
+ field_generators_.get(field).GenerateByteSize(printer);
+ printer->Print("\n");
+ }
+ printer->Outdent();
+ printer->Print("} else {\n" // the slow path
+ " total_size += RequiredFieldsByteSizeFallback();\n"
+ "}\n");
+ } else {
+ // num_required_fields_ <= 1: no need to be tricky
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (!field->is_required()) continue;
+ PrintFieldComment(printer, field);
+ printer->Print("if (has_$name$()) {\n",
+ "name", FieldName(field));
+ printer->Indent();
+ field_generators_.get(field).GenerateByteSize(printer);
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ }
+ // Handle optional fields (worry below about repeateds, oneofs, etc.).
+ // These are handled in chunks of 8. The first chunk is
+ // the non-requireds-non-repeateds-non-unions-non-extensions in
+ // descriptor_->field(0), descriptor_->field(1), ... descriptor_->field(7),
+ // and the second chunk is the same for
+ // descriptor_->field(8), descriptor_->field(9), ... descriptor_->field(15),
+ // etc.
+ hash_map<int, uint32> fields_mask_for_chunk;
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = descriptor_->field(i);
+ if (!field->is_required() && !field->is_repeated() &&
+ !field->containing_oneof()) {
+ fields_mask_for_chunk[i / 8] |= static_cast<uint32>(1) << (i % 32);
+ }
+ }
- if (!field->is_repeated() && !field->containing_oneof()) {
+ int last_index = -1;
+ bool chunk_block_in_progress = false;
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ if (!field->is_required() && !field->is_repeated() &&
+ !field->containing_oneof()) {
// See above in GenerateClear for an explanation of this.
// TODO(kenton): Share code? Unclear how to do so without
// over-engineering.
- if ((i / 8) != (last_index / 8) ||
- last_index < 0) {
- if (last_index >= 0) {
+ if (i / 8 != last_index / 8 || last_index < 0) {
+ // End previous chunk, if there was one.
+ if (chunk_block_in_progress) {
printer->Outdent();
printer->Print("}\n");
+ chunk_block_in_progress = false;
+ }
+ // Start chunk.
+ uint32 mask = fields_mask_for_chunk[i / 8];
+ int count = popcnt(mask);
+ GOOGLE_DCHECK_GE(count, 1);
+ if (count == 1) {
+ // No "if" here because the chunk is trivial.
+ } else {
+ if (HasFieldPresence(descriptor_->file())) {
+ printer->Print(
+ "if (_has_bits_[$index$ / 32] & $mask$) {\n",
+ "index", SimpleItoa(i),
+ "mask", SimpleItoa(mask));
+ printer->Indent();
+ chunk_block_in_progress = true;
+ }
}
- printer->Print(
- "if (_has_bits_[$index$ / 32] & (0xffu << ($index$ % 32))) {\n",
- "index", SimpleItoa(field->index()));
- printer->Indent();
}
last_index = i;
PrintFieldComment(printer, field);
- printer->Print(
- "if (has_$name$()) {\n",
- "name", FieldName(field));
- printer->Indent();
+ bool have_enclosing_if = false;
+ if (HasFieldPresence(descriptor_->file())) {
+ printer->Print(
+ "if (has_$name$()) {\n",
+ "name", FieldName(field));
+ printer->Indent();
+ have_enclosing_if = true;
+ } else {
+ // Without field presence: field is serialized only if it has a
+ // non-default value.
+ have_enclosing_if = EmitFieldNonDefaultCondition(
+ printer, "this->", field);
+ }
field_generators_.get(field).GenerateByteSize(printer);
- printer->Outdent();
- printer->Print(
- "}\n"
- "\n");
+ if (have_enclosing_if) {
+ printer->Outdent();
+ printer->Print(
+ "}\n"
+ "\n");
+ }
}
}
- if (last_index >= 0) {
+ if (chunk_block_in_progress) {
printer->Outdent();
printer->Print("}\n");
}
@@ -2532,19 +3110,19 @@ GenerateByteSize(io::Printer* printer) {
"\n");
}
- if (UseUnknownFieldSet(descriptor_->file())) {
- printer->Print("if (!unknown_fields().empty()) {\n");
- printer->Indent();
- printer->Print(
- "total_size +=\n"
- " ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n"
- " unknown_fields());\n");
- printer->Outdent();
- printer->Print("}\n");
- } else {
- printer->Print(
- "total_size += unknown_fields().size();\n"
- "\n");
+ if (PreserveUnknownFields(descriptor_)) {
+ if (UseUnknownFieldSet(descriptor_->file())) {
+ printer->Print(
+ "if (_internal_metadata_.have_unknown_fields()) {\n"
+ " total_size +=\n"
+ " ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize(\n"
+ " unknown_fields());\n"
+ "}\n");
+ } else {
+ printer->Print(
+ "total_size += unknown_fields().size();\n"
+ "\n");
+ }
}
// We update _cached_size_ even though this is a const method. In theory,
@@ -2569,27 +3147,29 @@ GenerateIsInitialized(io::Printer* printer) {
"classname", classname_);
printer->Indent();
- // Check that all required fields in this message are set. We can do this
- // most efficiently by checking 32 "has bits" at a time.
- int has_bits_array_size = (descriptor_->field_count() + 31) / 32;
- for (int i = 0; i < has_bits_array_size; i++) {
- uint32 mask = 0;
- for (int bit = 0; bit < 32; bit++) {
- int index = i * 32 + bit;
- if (index >= descriptor_->field_count()) break;
- const FieldDescriptor* field = descriptor_->field(index);
-
- if (field->is_required()) {
- mask |= 1 << bit;
+ if (HasFieldPresence(descriptor_->file())) {
+ // Check that all required fields in this message are set. We can do this
+ // most efficiently by checking 32 "has bits" at a time.
+ int has_bits_array_size = (descriptor_->field_count() + 31) / 32;
+ for (int i = 0; i < has_bits_array_size; i++) {
+ uint32 mask = 0;
+ for (int bit = 0; bit < 32; bit++) {
+ int index = i * 32 + bit;
+ if (index >= descriptor_->field_count()) break;
+ const FieldDescriptor* field = descriptor_->field(index);
+
+ if (field->is_required()) {
+ mask |= 1 << bit;
+ }
}
- }
- if (mask != 0) {
- char buffer[kFastToBufferSize];
- printer->Print(
- "if ((_has_bits_[$i$] & 0x$mask$) != 0x$mask$) return false;\n",
- "i", SimpleItoa(i),
- "mask", FastHex32ToBuffer(mask, buffer));
+ if (mask != 0) {
+ char buffer[kFastToBufferSize];
+ printer->Print(
+ "if ((_has_bits_[$i$] & 0x$mask$) != 0x$mask$) return false;\n",
+ "i", SimpleItoa(i),
+ "mask", FastHex32ToBuffer(mask, buffer));
+ }
}
}
@@ -2607,7 +3187,7 @@ GenerateIsInitialized(io::Printer* printer) {
"name", FieldName(field));
} else {
if (field->options().weak()) {
- // For weak fields, use the data member (google::protobuf::Message*) instead
+ // For weak fields, use the data member (::google::protobuf::Message*) instead
// of the getter to avoid a link dependency on the weak message type
// which is only forward declared.
printer->Print(
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index bfd3cec1..a781c234 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -36,6 +36,9 @@
#define GOOGLE_PROTOBUF_COMPILER_CPP_MESSAGE_H__
#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <string>
#include <vector>
#include <google/protobuf/compiler/cpp/cpp_field.h>
@@ -58,8 +61,7 @@ class ExtensionGenerator; // extension.h
class MessageGenerator {
public:
// See generator.cc for the meaning of dllexport_decl.
- explicit MessageGenerator(const Descriptor* descriptor,
- const Options& options);
+ MessageGenerator(const Descriptor* descriptor, const Options& options);
~MessageGenerator();
// Header stuff.
@@ -130,6 +132,8 @@ class MessageGenerator {
void GenerateSharedConstructorCode(io::Printer* printer);
// Generate the shared destructor code.
void GenerateSharedDestructorCode(io::Printer* printer);
+ // Generate the arena-specific destructor code.
+ void GenerateArenaDestructorCode(io::Printer* printer);
// Generate standard Message methods.
void GenerateClear(io::Printer* printer);
@@ -162,6 +166,7 @@ class MessageGenerator {
scoped_array<scoped_ptr<MessageGenerator> > nested_generators_;
scoped_array<scoped_ptr<EnumGenerator> > enum_generators_;
scoped_array<scoped_ptr<ExtensionGenerator> > extension_generators_;
+ int num_required_fields_;
bool uses_string_;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator);
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
index 6ac15a5a..da1ec60b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -86,6 +86,12 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
"inline $type$* mutable_$name$()$deprecation$;\n"
"inline $type$* $release_name$()$deprecation$;\n"
"inline void set_allocated_$name$($type$* $name$)$deprecation$;\n");
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ "inline $type$* unsafe_arena_release_$name$()$deprecation$;\n"
+ "inline void unsafe_arena_set_allocated_$name$(\n"
+ " $type$* $name$)$deprecation$;\n");
+ }
}
void MessageFieldGenerator::
@@ -101,36 +107,157 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
// Without.
" return $name$_ != NULL ? *$name$_ : *default_instance().$name$_;\n");
- printer->Print(variables_,
- "}\n"
- "inline $type$* $classname$::mutable_$name$() {\n"
- " set_has_$name$();\n"
- " if ($name$_ == NULL) $name$_ = new $type$;\n"
- " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
- " return $name$_;\n"
- "}\n"
- "inline $type$* $classname$::$release_name$() {\n"
- " clear_has_$name$();\n"
- " $type$* temp = $name$_;\n"
- " $name$_ = NULL;\n"
- " return temp;\n"
- "}\n"
- "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
- " delete $name$_;\n"
- " $name$_ = $name$;\n"
- " if ($name$) {\n"
- " set_has_$name$();\n"
- " } else {\n"
- " clear_has_$name$();\n"
- " }\n"
- " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
- "}\n");
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ "}\n"
+ "inline $type$* $classname$::mutable_$name$() {\n"
+ " $set_hasbit$\n"
+ " if ($name$_ == NULL) {\n");
+ if (SupportsArenas(descriptor_->message_type())) {
+ printer->Print(variables_,
+ " $name$_ = ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
+ " GetArenaNoVirtual());\n");
+ } else {
+ printer->Print(variables_,
+ " $name$_ = ::google::protobuf::Arena::Create< $type$ >(\n"
+ " GetArenaNoVirtual());\n");
+ }
+ printer->Print(variables_, " }\n"
+ " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+ " return $name$_;\n"
+ "}\n"
+ "inline $type$* $classname$::$release_name$() {\n"
+ " $clear_hasbit$\n"
+ " if (GetArenaNoVirtual() != NULL) {\n"
+ " if ($name$_ == NULL) {\n"
+ " return NULL;\n"
+ " } else {\n"
+ " $type$* temp = new $type$;\n"
+ " temp->MergeFrom(*$name$_);\n"
+ " $name$_ = NULL;\n"
+ " return temp;\n"
+ " }\n"
+ " } else {\n"
+ " $type$* temp = $name$_;\n"
+ " $name$_ = NULL;\n"
+ " return temp;\n"
+ " }\n"
+ "}\n"
+ "inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
+ " $clear_hasbit$\n"
+ " $type$* temp = $name$_;\n"
+ " $name$_ = NULL;\n"
+ " return temp;\n"
+ "}\n"
+ "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
+ " if (GetArenaNoVirtual() == NULL) {\n"
+ " delete $name$_;\n"
+ " }\n"
+ " if ($name$ != NULL) {\n");
+ if (SupportsArenas(descriptor_->message_type())) {
+ // If we're on an arena and the incoming message is not, simply Own() it
+ // rather than copy to the arena -- either way we need a heap dealloc,
+ // so we might as well defer it. Otherwise, if incoming message is on a
+ // different ownership domain (specific arena, or the heap) than we are,
+ // copy to our arena (or heap, as the case may be).
+ printer->Print(variables_,
+ " if (GetArenaNoVirtual() != NULL && \n"
+ " ::google::protobuf::Arena::GetArena($name$) == NULL) {\n"
+ " GetArenaNoVirtual()->Own($name$);\n"
+ " } else if (GetArenaNoVirtual() !=\n"
+ " ::google::protobuf::Arena::GetArena($name$)) {\n"
+ " $type$* new_$name$ = \n"
+ " ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
+ " GetArenaNoVirtual());\n"
+ " new_$name$->CopyFrom(*$name$);\n"
+ " $name$ = new_$name$;\n"
+ " }\n");
+ } else {
+ printer->Print(variables_,
+ " if (GetArenaNoVirtual() != NULL) {\n"
+ " GetArenaNoVirtual()->Own($name$);\n"
+ " }\n");
+ }
+
+ printer->Print(variables_,
+ " }\n"
+ " $name$_ = $name$;\n"
+ " if ($name$) {\n"
+ " $set_hasbit$\n"
+ " } else {\n"
+ " $clear_hasbit$\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n"
+ "inline void $classname$::unsafe_arena_set_allocated_$name$(\n"
+ " $type$* $name$) {\n"
+ // 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 (GetArenaNoVirtual() == NULL) {\n"
+ " delete $name$_;\n"
+ " }\n"
+ " $name$_ = $name$;\n"
+ " if ($name$) {\n"
+ " $set_hasbit$\n"
+ " } else {\n"
+ " $clear_hasbit$\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_unsafe_arena_set_allocated"
+ ":$full_name$)\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "}\n"
+ "inline $type$* $classname$::mutable_$name$() {\n"
+ " $set_hasbit$\n"
+ " if ($name$_ == NULL) {\n"
+ " $name$_ = new $type$;\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+ " return $name$_;\n"
+ "}\n"
+ "inline $type$* $classname$::$release_name$() {\n"
+ " $clear_hasbit$\n"
+ " $type$* temp = $name$_;\n"
+ " $name$_ = NULL;\n"
+ " return temp;\n"
+ "}\n"
+ "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
+ " delete $name$_;\n");
+
+ if (SupportsArenas(descriptor_->message_type())) {
+ printer->Print(variables_,
+ " if ($name$ != NULL && $name$->GetArena() != NULL) {\n"
+ " $type$* new_$name$ = new $type$;\n"
+ " new_$name$->CopyFrom(*$name$);\n"
+ " $name$ = new_$name$;\n"
+ " }\n");
+ }
+
+ printer->Print(variables_,
+ " $name$_ = $name$;\n"
+ " if ($name$) {\n"
+ " $set_hasbit$\n"
+ " } else {\n"
+ " $clear_hasbit$\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n");
+ }
}
void MessageFieldGenerator::
GenerateClearingCode(io::Printer* printer) const {
- printer->Print(variables_,
- "if ($name$_ != NULL) $name$_->$type$::Clear();\n");
+ if (!HasFieldPresence(descriptor_->file())) {
+ // If we don't have has-bits, message presence is indicated only by ptr !=
+ // NULL. Thus on clear, we need to delete the object.
+ printer->Print(variables_,
+ "if ($name$_ != NULL) delete $name$_;\n"
+ "$name$_ = NULL;\n");
+ } else {
+ printer->Print(variables_,
+ "if ($name$_ != NULL) $name$_->$type$::Clear();\n");
+ }
}
void MessageFieldGenerator::
@@ -198,43 +325,165 @@ MessageOneofFieldGenerator::~MessageOneofFieldGenerator() {}
void MessageOneofFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline const $type$& $classname$::$name$() const {\n"
- " return has_$name$() ? *$oneof_prefix$$name$_\n"
- " : $type$::default_instance();\n"
- "}\n"
- "inline $type$* $classname$::mutable_$name$() {\n"
- " if (!has_$name$()) {\n"
- " clear_$oneof_name$();\n"
- " set_has_$name$();\n"
- " $oneof_prefix$$name$_ = new $type$;\n"
- " }\n"
- " return $oneof_prefix$$name$_;\n"
- "}\n"
- "inline $type$* $classname$::$release_name$() {\n"
- " if (has_$name$()) {\n"
- " clear_has_$oneof_name$();\n"
- " $type$* temp = $oneof_prefix$$name$_;\n"
- " $oneof_prefix$$name$_ = NULL;\n"
- " return temp;\n"
- " } else {\n"
- " return NULL;\n"
- " }\n"
- "}\n"
- "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
- " clear_$oneof_name$();\n"
- " if ($name$) {\n"
- " set_has_$name$();\n"
- " $oneof_prefix$$name$_ = $name$;\n"
- " }\n"
- "}\n");
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ "inline const $type$& $classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
+ " return has_$name$() ? *$oneof_prefix$$name$_\n"
+ " : $type$::default_instance();\n"
+ "}\n"
+ "inline $type$* $classname$::mutable_$name$() {\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n");
+ if (SupportsArenas(descriptor_->message_type())) {
+ printer->Print(variables_,
+ " $oneof_prefix$$name$_ = \n"
+ " ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
+ " GetArenaNoVirtual());\n");
+ } else {
+ printer->Print(variables_,
+ " $oneof_prefix$$name$_ = \n"
+ " ::google::protobuf::Arena::Create< $type$ >(\n"
+ " GetArenaNoVirtual());\n");
+ }
+ printer->Print(variables_,
+ " }\n"
+ " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+ " return $oneof_prefix$$name$_;\n"
+ "}\n"
+ "inline $type$* $classname$::$release_name$() {\n"
+ " if (has_$name$()) {\n"
+ " clear_has_$oneof_name$();\n"
+ " if (GetArenaNoVirtual() != NULL) {\n"
+ // N.B.: safe to use the underlying field pointer here because we are sure
+ // that it is non-NULL (because has_$name$() returned true).
+ " $type$* temp = new $type$;\n"
+ " temp->MergeFrom(*$oneof_prefix$$name$_);\n"
+ " $oneof_prefix$$name$_ = NULL;\n"
+ " return temp;\n"
+ " } else {\n"
+ " $type$* temp = $oneof_prefix$$name$_;\n"
+ " $oneof_prefix$$name$_ = NULL;\n"
+ " return temp;\n"
+ " }\n"
+ " } else {\n"
+ " return NULL;\n"
+ " }\n"
+ "}\n"
+ "inline $type$* $classname$::unsafe_arena_release_$name$() {\n"
+ " if (has_$name$()) {\n"
+ " clear_has_$oneof_name$();\n"
+ " $type$* temp = $oneof_prefix$$name$_;\n"
+ " $oneof_prefix$$name$_ = NULL;\n"
+ " return temp;\n"
+ " } else {\n"
+ " return NULL;\n"
+ " }\n"
+ "}\n"
+ "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
+ " clear_$oneof_name$();\n"
+ " if ($name$) {\n");
+
+ if (SupportsArenas(descriptor_->message_type())) {
+ printer->Print(variables_,
+ // If incoming message is on the heap and we are on an arena, just Own()
+ // it (see above). If it's on a different arena than we are or one of us
+ // is on the heap, we make a copy to our arena/heap.
+ " if (GetArenaNoVirtual() != NULL &&\n"
+ " ::google::protobuf::Arena::GetArena($name$) == NULL) {\n"
+ " GetArenaNoVirtual()->Own($name$);\n"
+ " } else if (GetArenaNoVirtual() !=\n"
+ " ::google::protobuf::Arena::GetArena($name$)) {\n"
+ " $type$* new_$name$ = \n"
+ " ::google::protobuf::Arena::CreateMessage< $type$ >(\n"
+ " GetArenaNoVirtual());\n"
+ " new_$name$->CopyFrom(*$name$);\n"
+ " $name$ = new_$name$;\n"
+ " }\n");
+ } else {
+ printer->Print(variables_,
+ " if (GetArenaNoVirtual() != NULL) {\n"
+ " GetArenaNoVirtual()->Own($name$);\n"
+ " }\n");
+ }
+
+ printer->Print(variables_,
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_ = $name$;\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n"
+ "inline void $classname$::unsafe_arena_set_allocated_$name$("
+ "$type$* $name$) {\n"
+ // We rely on the oneof clear method to free the earlier contents of this
+ // oneof. We can directly use the pointer we're given to set the new
+ // value.
+ " clear_$oneof_name$();\n"
+ " if ($name$) {\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_ = $name$;\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_unsafe_arena_set_allocated:"
+ "$full_name$)\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "inline const $type$& $classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
+ " return has_$name$() ? *$oneof_prefix$$name$_\n"
+ " : $type$::default_instance();\n"
+ "}\n"
+ "inline $type$* $classname$::mutable_$name$() {\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_ = new $type$;\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+ " return $oneof_prefix$$name$_;\n"
+ "}\n"
+ "inline $type$* $classname$::$release_name$() {\n"
+ " if (has_$name$()) {\n"
+ " clear_has_$oneof_name$();\n"
+ " $type$* temp = $oneof_prefix$$name$_;\n"
+ " $oneof_prefix$$name$_ = NULL;\n"
+ " return temp;\n"
+ " } else {\n"
+ " return NULL;\n"
+ " }\n"
+ "}\n"
+ "inline void $classname$::set_allocated_$name$($type$* $name$) {\n"
+ " clear_$oneof_name$();\n"
+ " if ($name$) {\n");
+ if (SupportsArenas(descriptor_->message_type())) {
+ printer->Print(variables_,
+ " if ($name$->GetArena() != NULL) {\n"
+ " $type$* new_$name$ = new $type$;\n"
+ " new_$name$->CopyFrom(*$name$);\n"
+ " $name$ = new_$name$;\n"
+ " }\n");
+ }
+ printer->Print(variables_,
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_ = $name$;\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n");
+ }
}
void MessageOneofFieldGenerator::
GenerateClearingCode(io::Printer* printer) const {
- // if it is the active field, it cannot be NULL.
- printer->Print(variables_,
- "delete $oneof_prefix$$name$_;\n");
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ "if (GetArenaNoVirtual() == NULL) {\n"
+ " delete $oneof_prefix$$name$_;\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "delete $oneof_prefix$$name$_;\n");
+ }
}
void MessageOneofFieldGenerator::
@@ -318,7 +567,7 @@ GenerateMergingCode(io::Printer* printer) const {
void RepeatedMessageFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
- printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
+ printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n");
}
void RepeatedMessageFieldGenerator::
diff --git a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
index 2dbf14ce..26cefb2e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
@@ -35,6 +35,9 @@
// worth.
#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <google/protobuf/compiler/cpp/cpp_generator.h>
#include <google/protobuf/compiler/command_line_interface.h>
@@ -69,6 +72,100 @@ class TestGenerator : public CodeGenerator {
TryInsert("test.pb.cc", "includes", context);
TryInsert("test.pb.cc", "namespace_scope", context);
TryInsert("test.pb.cc", "global_scope", context);
+
+ // Check field accessors for an optional int32:
+ TryInsert("test.pb.h", "field_get:foo.Bar.optInt", context);
+ TryInsert("test.pb.h", "field_set:foo.Bar.optInt", context);
+
+ // Check field accessors for a repeated int32:
+ TryInsert("test.pb.h", "field_get:foo.Bar.repeatedInt", context);
+ TryInsert("test.pb.h", "field_set:foo.Bar.repeatedInt", context);
+
+ // Check field accessors for a required string:
+ TryInsert("test.pb.h", "field_get:foo.Bar.requiredString", context);
+ TryInsert("test.pb.h", "field_set:foo.Bar.requiredString", context);
+ TryInsert("test.pb.h", "field_set_char:foo.Bar.requiredString", context);
+ TryInsert("test.pb.h", "field_set_pointer:foo.Bar.requiredString", context);
+ TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredString", context);
+ TryInsert("test.pb.h", "field_set_allocated:foo.Bar.requiredString",
+ context);
+ TryInsert("test.pb.h", "field_set_char:foo.Bar.requiredString", context);
+ TryInsert("test.pb.h", "field_set_pointer:foo.Bar.requiredString", context);
+
+ // Check field accessors for a repeated string:
+ TryInsert("test.pb.h", "field_get:foo.Bar.repeatedString", context);
+ TryInsert("test.pb.h", "field_set:foo.Bar.repeatedString", context);
+ TryInsert("test.pb.h", "field_set_char:foo.Bar.repeatedString", context);
+ TryInsert("test.pb.h", "field_set_pointer:foo.Bar.repeatedString", context);
+ TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedString", context);
+ TryInsert("test.pb.h", "field_set_char:foo.Bar.repeatedString", context);
+ TryInsert("test.pb.h", "field_set_pointer:foo.Bar.repeatedString", context);
+
+ // Check field accessors for an int inside oneof{}:
+ TryInsert("test.pb.h", "field_get:foo.Bar.oneOfInt", context);
+ TryInsert("test.pb.h", "field_set:foo.Bar.oneOfInt", context);
+
+ // Check field accessors for a string inside oneof{}:
+ TryInsert("test.pb.h", "field_get:foo.Bar.oneOfString", context);
+ TryInsert("test.pb.h", "field_set:foo.Bar.oneOfString", context);
+ TryInsert("test.pb.h", "field_set_char:foo.Bar.oneOfString", context);
+ TryInsert("test.pb.h", "field_set_pointer:foo.Bar.oneOfString", context);
+ TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfString", context);
+ TryInsert("test.pb.h", "field_set_allocated:foo.Bar.oneOfString", context);
+ TryInsert("test.pb.h", "field_set_char:foo.Bar.oneOfString", context);
+ TryInsert("test.pb.h", "field_set_pointer:foo.Bar.oneOfString", context);
+
+ // Check field accessors for an optional message:
+ TryInsert("test.pb.h", "field_get:foo.Bar.optMessage", context);
+ TryInsert("test.pb.h", "field_mutable:foo.Bar.optMessage", context);
+ TryInsert("test.pb.h", "field_set_allocated:foo.Bar.optMessage", context);
+
+ // Check field accessors for a repeated message:
+ TryInsert("test.pb.h", "field_add:foo.Bar.repeatedMessage", context);
+ TryInsert("test.pb.h", "field_get:foo.Bar.repeatedMessage", context);
+ TryInsert("test.pb.h", "field_list:foo.Bar.repeatedMessage", context);
+ TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedMessage", context);
+ TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedMessage",
+ context);
+
+ // Check field accessors for a message inside oneof{}:
+ TryInsert("test.pb.h", "field_get:foo.Bar.oneOfMessage", context);
+ TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfMessage", context);
+ TryInsert("test.pb.h", "field_set_allocated:foo.Bar.oneOfMessage", context);
+
+ // Check field accessors for an optional enum:
+ TryInsert("test.pb.h", "field_get:foo.Bar.optEnum", context);
+ TryInsert("test.pb.h", "field_set:foo.Bar.optEnum", context);
+
+ // Check field accessors for a repeated enum:
+ TryInsert("test.pb.h", "field_get:foo.Bar.repeatedEnum", context);
+ TryInsert("test.pb.h", "field_set:foo.Bar.repeatedEnum", context);
+ TryInsert("test.pb.h", "field_add:foo.Bar.repeatedEnum", context);
+ TryInsert("test.pb.h", "field_list:foo.Bar.repeatedEnum", context);
+ TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedEnum", context);
+
+ // Check field accessors for an enum inside oneof{}:
+ TryInsert("test.pb.h", "field_get:foo.Bar.oneOfEnum", context);
+ TryInsert("test.pb.h", "field_set:foo.Bar.oneOfEnum", context);
+
+ // Check field accessors for a required cord:
+ TryInsert("test.pb.h", "field_get:foo.Bar.requiredCord", context);
+ TryInsert("test.pb.h", "field_set:foo.Bar.requiredCord", context);
+ TryInsert("test.pb.h", "field_mutable:foo.Bar.requiredCord", context);
+
+ // Check field accessors for a repeated cord:
+ TryInsert("test.pb.h", "field_get:foo.Bar.repeatedCord", context);
+ TryInsert("test.pb.h", "field_set:foo.Bar.repeatedCord", context);
+ TryInsert("test.pb.h", "field_add:foo.Bar.repeatedCord", context);
+ TryInsert("test.pb.h", "field_list:foo.Bar.repeatedCord", context);
+ TryInsert("test.pb.h", "field_mutable:foo.Bar.repeatedCord", context);
+ TryInsert("test.pb.h", "field_mutable_list:foo.Bar.repeatedCord", context);
+
+ // Check field accessors for a cord inside oneof{}:
+ TryInsert("test.pb.h", "field_get:foo.Bar.oneOfCord", context);
+ TryInsert("test.pb.h", "field_set:foo.Bar.oneOfCord", context);
+ TryInsert("test.pb.h", "field_mutable:foo.Bar.oneOfCord", context);
+
return true;
}
@@ -88,8 +185,39 @@ TEST(CppPluginTest, PluginTest) {
GOOGLE_CHECK_OK(File::SetContents(TestTempDir() + "/test.proto",
"syntax = \"proto2\";\n"
"package foo;\n"
+ "\n"
+ "enum Thud { VALUE = 0; }\n"
+ "\n"
"message Bar {\n"
" message Baz {}\n"
+ " optional int32 optInt = 1;\n"
+ " repeated int32 repeatedInt = 2;\n"
+ "\n"
+ " required string requiredString = 3;\n"
+ " repeated string repeatedString = 4;\n"
+ "\n"
+ " optional Baz optMessage = 6;\n"
+ " repeated Baz repeatedMessage = 7;\n"
+ "\n"
+ " optional Thud optEnum = 8;\n"
+ " repeated Thud repeatedEnum = 9;\n"
+ "\n"
+ " required string requiredCord = 10 [\n"
+ " ctype = CORD\n"
+ " ];\n"
+ " repeated string repeatedCord = 11 [\n"
+ " ctype = CORD\n"
+ " ];\n"
+ "\n"
+ " oneof Qux {\n"
+ " int64 oneOfInt = 20;\n"
+ " string oneOfString = 21;\n"
+ " Baz oneOfMessage = 22;\n"
+ " Thud oneOfEnum = 23;"
+ " string oneOfCord = 24 [\n"
+ " ctype = CORD\n"
+ " ];\n"
+ " }\n"
"}\n",
true));
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
index 44290a31..9a2c930e 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -129,7 +129,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" return $name$_;\n"
"}\n"
"inline void $classname$::set_$name$($type$ value) {\n"
- " set_has_$name$();\n"
+ " $set_hasbit$\n"
" $name$_ = value;\n"
" // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n");
@@ -161,7 +161,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
"DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n"
" $type$, $wire_format_field_type$>(\n"
" input, &$name$_)));\n"
- "set_has_$name$();\n");
+ "$set_hasbit$\n");
}
void PrimitiveFieldGenerator::
@@ -207,6 +207,7 @@ void PrimitiveOneofFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
printer->Print(variables_,
"inline $type$ $classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
" if (has_$name$()) {\n"
" return $oneof_prefix$$name$_;\n"
" }\n"
@@ -218,6 +219,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
" set_has_$name$();\n"
" }\n"
" $oneof_prefix$$name$_ = value;\n"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
"}\n");
}
@@ -330,7 +332,7 @@ GenerateMergingCode(io::Printer* printer) const {
void RepeatedPrimitiveFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
- printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
+ printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n");
}
void RepeatedPrimitiveFieldGenerator::
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index 180d236b..a2a8c81c 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -52,9 +52,14 @@ void SetStringVariables(const FieldDescriptor* descriptor,
(*variables)["default"] = DefaultValue(descriptor);
(*variables)["default_length"] =
SimpleItoa(descriptor->default_value_string().length());
- (*variables)["default_variable"] = descriptor->default_value_string().empty()
- ? "&::google::protobuf::internal::GetEmptyStringAlreadyInited()"
- : "_default_" + FieldName(descriptor) + "_";
+ string default_variable_string =
+ descriptor->default_value_string().empty()
+ ? "&::google::protobuf::internal::GetEmptyStringAlreadyInited()"
+ : "_default_" + FieldName(descriptor) + "_";
+ (*variables)["default_variable"] = default_variable_string;
+ (*variables)["default_value_init"] =
+ descriptor->default_value_string().empty()
+ ? "" : "*" + default_variable_string;
(*variables)["pointer_type"] =
descriptor->type() == FieldDescriptor::TYPE_BYTES ? "void" : "char";
// NOTE: Escaped here to unblock proto1->proto2 migration.
@@ -63,6 +68,8 @@ void SetStringVariables(const FieldDescriptor* descriptor,
SafeFunctionName(descriptor->containing_type(),
descriptor, "release_");
(*variables)["full_name"] = descriptor->full_name();
+
+ (*variables)["string_piece"] = "::std::string";
}
} // namespace
@@ -80,7 +87,19 @@ StringFieldGenerator::~StringFieldGenerator() {}
void StringFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
- printer->Print(variables_, "::std::string* $name$_;\n");
+ // N.B. that we continue to use |ArenaStringPtr| instead of |string*| for
+ // string fields, even when SupportArenas(descriptor_) == false. Why?
+ // The simple answer is to avoid unmaintainable complexity. The reflection
+ // code assumes ArenaStringPtrs. These are *almost* in-memory-compatible with
+ // string*, except for the pointer tags and related ownership semantics. We
+ // could modify the runtime code to use string* for the not-supporting-arenas
+ // case, but this would require a way to detect which type of class was
+ // generated (adding overhead and complexity to GeneratedMessageReflection)
+ // and littering the runtime code paths with conditionals. It's simpler to
+ // stick with this but use lightweight accessors that assume arena == NULL.
+ // There should be very little overhead anyway because it's just a tagged
+ // pointer in-memory.
+ printer->Print(variables_, "::google::protobuf::internal::ArenaStringPtr $name$_;\n");
}
void StringFieldGenerator::
@@ -125,6 +144,12 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
"inline ::std::string* mutable_$name$()$deprecation$;\n"
"inline ::std::string* $release_name$()$deprecation$;\n"
"inline void set_allocated_$name$(::std::string* $name$)$deprecation$;\n");
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ "inline ::std::string* unsafe_arena_release_$name$()$deprecation$;\n"
+ "inline void unsafe_arena_set_allocated_$name$(\n"
+ " ::std::string* $name$)$deprecation$;\n");
+ }
if (descriptor_->options().ctype() != FieldOptions::STRING) {
@@ -136,74 +161,113 @@ GenerateAccessorDeclarations(io::Printer* printer) const {
void StringFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline const ::std::string& $classname$::$name$() const {\n"
- " // @@protoc_insertion_point(field_get:$full_name$)\n"
- " return *$name$_;\n"
- "}\n"
- "inline void $classname$::set_$name$(const ::std::string& value) {\n"
- " set_has_$name$();\n"
- " if ($name$_ == $default_variable$) {\n"
- " $name$_ = new ::std::string;\n"
- " }\n"
- " $name$_->assign(value);\n"
- " // @@protoc_insertion_point(field_set:$full_name$)\n"
- "}\n"
- "inline void $classname$::set_$name$(const char* value) {\n"
- " set_has_$name$();\n"
- " if ($name$_ == $default_variable$) {\n"
- " $name$_ = new ::std::string;\n"
- " }\n"
- " $name$_->assign(value);\n"
- " // @@protoc_insertion_point(field_set_char:$full_name$)\n"
- "}\n"
- "inline "
- "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n"
- " set_has_$name$();\n"
- " if ($name$_ == $default_variable$) {\n"
- " $name$_ = new ::std::string;\n"
- " }\n"
- " $name$_->assign(reinterpret_cast<const char*>(value), size);\n"
- " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
- "}\n"
- "inline ::std::string* $classname$::mutable_$name$() {\n"
- " set_has_$name$();\n"
- " if ($name$_ == $default_variable$) {\n");
- if (descriptor_->default_value_string().empty()) {
+ if (SupportsArenas(descriptor_)) {
printer->Print(variables_,
- " $name$_ = new ::std::string;\n");
+ "inline const ::std::string& $classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
+ " return $name$_.Get($default_variable$);\n"
+ "}\n"
+ "inline void $classname$::set_$name$(const ::std::string& value) {\n"
+ " $set_hasbit$\n"
+ " $name$_.Set($default_variable$, value, GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
+ "}\n"
+ "inline void $classname$::set_$name$(const char* value) {\n"
+ " $set_hasbit$\n"
+ " $name$_.Set($default_variable$, $string_piece$(value),\n"
+ " GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set_char:$full_name$)\n"
+ "}\n"
+ "inline "
+ "void $classname$::set_$name$(const $pointer_type$* value,\n"
+ " size_t size) {\n"
+ " $set_hasbit$\n"
+ " $name$_.Set($default_variable$, $string_piece$(\n"
+ " reinterpret_cast<const char*>(value), size), GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
+ "}\n"
+ "inline ::std::string* $classname$::mutable_$name$() {\n"
+ " $set_hasbit$\n"
+ " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+ " return $name$_.Mutable($default_variable$, GetArenaNoVirtual());\n"
+ "}\n"
+ "inline ::std::string* $classname$::$release_name$() {\n"
+ " $clear_hasbit$\n"
+ " return $name$_.Release($default_variable$, GetArenaNoVirtual());\n"
+ "}\n"
+ "inline ::std::string* $classname$::unsafe_arena_release_$name$() {\n"
+ " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
+ " $clear_hasbit$\n"
+ " return $name$_.UnsafeArenaRelease($default_variable$,\n"
+ " GetArenaNoVirtual());\n"
+ "}\n"
+ "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+ " if ($name$ != NULL) {\n"
+ " $set_hasbit$\n"
+ " } else {\n"
+ " $clear_hasbit$\n"
+ " }\n"
+ " $name$_.SetAllocated($default_variable$, $name$,\n"
+ " GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n"
+ "inline void $classname$::unsafe_arena_set_allocated_$name$(\n"
+ " ::std::string* $name$) {\n"
+ " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
+ " if ($name$ != NULL) {\n"
+ " $set_hasbit$\n"
+ " } else {\n"
+ " $clear_hasbit$\n"
+ " }\n"
+ " $set_hasbit$\n"
+ " $name$_.UnsafeArenaSetAllocated($default_variable$,\n"
+ " $name$, GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n");
} else {
+ // No-arena case.
printer->Print(variables_,
- " $name$_ = new ::std::string(*$default_variable$);\n");
+ "inline const ::std::string& $classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
+ " return $name$_.GetNoArena($default_variable$);\n"
+ "}\n"
+ "inline void $classname$::set_$name$(const ::std::string& value) {\n"
+ " $set_hasbit$\n"
+ " $name$_.SetNoArena($default_variable$, value);\n"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
+ "}\n"
+ "inline void $classname$::set_$name$(const char* value) {\n"
+ " $set_hasbit$\n"
+ " $name$_.SetNoArena($default_variable$, $string_piece$(value));\n"
+ " // @@protoc_insertion_point(field_set_char:$full_name$)\n"
+ "}\n"
+ "inline "
+ "void $classname$::set_$name$(const $pointer_type$* value, "
+ "size_t size) {\n"
+ " $set_hasbit$\n"
+ " $name$_.SetNoArena($default_variable$,\n"
+ " $string_piece$(reinterpret_cast<const char*>(value), size));\n"
+ " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
+ "}\n"
+ "inline ::std::string* $classname$::mutable_$name$() {\n"
+ " $set_hasbit$\n"
+ " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+ " return $name$_.MutableNoArena($default_variable$);\n"
+ "}\n"
+ "inline ::std::string* $classname$::$release_name$() {\n"
+ " $clear_hasbit$\n"
+ " return $name$_.ReleaseNoArena($default_variable$);\n"
+ "}\n"
+ "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+ " if ($name$ != NULL) {\n"
+ " $set_hasbit$\n"
+ " } else {\n"
+ " $clear_hasbit$\n"
+ " }\n"
+ " $name$_.SetAllocatedNoArena($default_variable$, $name$);\n"
+ " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n");
}
- printer->Print(variables_,
- " }\n"
- " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
- " return $name$_;\n"
- "}\n"
- "inline ::std::string* $classname$::$release_name$() {\n"
- " clear_has_$name$();\n"
- " if ($name$_ == $default_variable$) {\n"
- " return NULL;\n"
- " } else {\n"
- " ::std::string* temp = $name$_;\n"
- " $name$_ = const_cast< ::std::string*>($default_variable$);\n"
- " return temp;\n"
- " }\n"
- "}\n"
- "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
- " if ($name$_ != $default_variable$) {\n"
- " delete $name$_;\n"
- " }\n"
- " if ($name$) {\n"
- " set_has_$name$();\n"
- " $name$_ = $name$;\n"
- " } else {\n"
- " clear_has_$name$();\n"
- " $name$_ = const_cast< ::std::string*>($default_variable$);\n"
- " }\n"
- " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
- "}\n");
}
void StringFieldGenerator::
@@ -217,16 +281,26 @@ GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {
void StringFieldGenerator::
GenerateClearingCode(io::Printer* printer) const {
- if (descriptor_->default_value_string().empty()) {
- printer->Print(variables_,
- "if ($name$_ != $default_variable$) {\n"
- " $name$_->clear();\n"
- "}\n");
+ // Two-dimension specialization here: supporting arenas or not, and default
+ // value is the empty string or not. Complexity here ensures the minimal
+ // number of branches / amount of extraneous code at runtime (given that the
+ // below methods are inlined one-liners)!
+ if (SupportsArenas(descriptor_)) {
+ if (descriptor_->default_value_string().empty()) {
+ printer->Print(variables_,
+ "$name$_.ClearToEmpty($default_variable$, GetArenaNoVirtual());\n");
+ } else {
+ printer->Print(variables_,
+ "$name$_.ClearToDefault($default_variable$, GetArenaNoVirtual());\n");
+ }
} else {
- printer->Print(variables_,
- "if ($name$_ != $default_variable$) {\n"
- " $name$_->assign(*$default_variable$);\n"
- "}\n");
+ if (descriptor_->default_value_string().empty()) {
+ printer->Print(variables_,
+ "$name$_.ClearToEmptyNoArena($default_variable$);\n");
+ } else {
+ printer->Print(variables_,
+ "$name$_.ClearToDefaultNoArena($default_variable$);\n");
+ }
}
}
@@ -237,21 +311,24 @@ GenerateMergingCode(io::Printer* printer) const {
void StringFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
- printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
+ printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
}
void StringFieldGenerator::
GenerateConstructorCode(io::Printer* printer) const {
printer->Print(variables_,
- "$name$_ = const_cast< ::std::string*>($default_variable$);\n");
+ "$name$_.UnsafeSetDefault($default_variable$);\n");
}
void StringFieldGenerator::
GenerateDestructorCode(io::Printer* printer) const {
- printer->Print(variables_,
- "if ($name$_ != $default_variable$) {\n"
- " delete $name$_;\n"
- "}\n");
+ if (SupportsArenas(descriptor_)) {
+ printer->Print(variables_,
+ "$name$_.Destroy($default_variable$, GetArenaNoVirtual());\n");
+ } else {
+ printer->Print(variables_,
+ "$name$_.DestroyNoArena($default_variable$);\n");
+ }
}
void StringFieldGenerator::
@@ -276,13 +353,14 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
printer->Print(variables_,
"DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
" input, this->mutable_$name$()));\n");
+
if (HasUtf8Verification(descriptor_->file()) &&
descriptor_->type() == FieldDescriptor::TYPE_STRING) {
printer->Print(variables_,
"::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
" this->$name$().data(), this->$name$().length(),\n"
" ::google::protobuf::internal::WireFormat::PARSE,\n"
- " \"$name$\");\n");
+ " \"$full_name$\");\n");
}
}
@@ -294,7 +372,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
"::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
" this->$name$().data(), this->$name$().length(),\n"
" ::google::protobuf::internal::WireFormat::SERIALIZE,\n"
- " \"$name$\");\n");
+ " \"$full_name$\");\n");
}
printer->Print(variables_,
"::google::protobuf::internal::WireFormatLite::Write$declared_type$MaybeAliased(\n"
@@ -309,7 +387,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
"::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
" this->$name$().data(), this->$name$().length(),\n"
" ::google::protobuf::internal::WireFormat::SERIALIZE,\n"
- " \"$name$\");\n");
+ " \"$full_name$\");\n");
}
printer->Print(variables_,
"target =\n"
@@ -338,84 +416,186 @@ StringOneofFieldGenerator::~StringOneofFieldGenerator() {}
void StringOneofFieldGenerator::
GenerateInlineAccessorDefinitions(io::Printer* printer) const {
- printer->Print(variables_,
- "inline const ::std::string& $classname$::$name$() const {\n"
- " if (has_$name$()) {\n"
- " return *$oneof_prefix$$name$_;\n"
- " }\n");
- if (descriptor_->default_value_string().empty()) {
- printer->Print(variables_,
- " return ::google::protobuf::internal::GetEmptyStringAlreadyInited();\n");
- } else {
- printer->Print(variables_,
- " return *$default_variable$;\n");
- }
- printer->Print(variables_,
- "}\n"
- "inline void $classname$::set_$name$(const ::std::string& value) {\n"
- " if (!has_$name$()) {\n"
- " clear_$oneof_name$();\n"
- " set_has_$name$();\n"
- " $oneof_prefix$$name$_ = new ::std::string;\n"
- " }\n"
- " $oneof_prefix$$name$_->assign(value);\n"
- "}\n"
- "inline void $classname$::set_$name$(const char* value) {\n"
- " if (!has_$name$()) {\n"
- " clear_$oneof_name$();\n"
- " set_has_$name$();\n"
- " $oneof_prefix$$name$_ = new ::std::string;\n"
- " }\n"
- " $oneof_prefix$$name$_->assign(value);\n"
- "}\n"
- "inline "
- "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n"
- " if (!has_$name$()) {\n"
- " clear_$oneof_name$();\n"
- " set_has_$name$();\n"
- " $oneof_prefix$$name$_ = new ::std::string;\n"
- " }\n"
- " $oneof_prefix$$name$_->assign(\n"
- " reinterpret_cast<const char*>(value), size);\n"
- "}\n"
- "inline ::std::string* $classname$::mutable_$name$() {\n"
- " if (!has_$name$()) {\n"
- " clear_$oneof_name$();\n"
- " set_has_$name$();\n");
- if (descriptor_->default_value_string().empty()) {
+ if (SupportsArenas(descriptor_)) {
printer->Print(variables_,
- " $oneof_prefix$$name$_ = new ::std::string;\n");
+ "inline const ::std::string& $classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
+ " if (has_$name$()) {\n"
+ " return $oneof_prefix$$name$_.Get($default_variable$);\n"
+ " }\n"
+ " return *$default_variable$;\n"
+ "}\n"
+ "inline void $classname$::set_$name$(const ::std::string& value) {\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " $oneof_prefix$$name$_.Set($default_variable$, value,\n"
+ " GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
+ "}\n"
+ "inline void $classname$::set_$name$(const char* value) {\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " $oneof_prefix$$name$_.Set($default_variable$,\n"
+ " $string_piece$(value), GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set_char:$full_name$)\n"
+ "}\n"
+ "inline "
+ "void $classname$::set_$name$(const $pointer_type$* value,\n"
+ " size_t size) {\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " $oneof_prefix$$name$_.Set($default_variable$, $string_piece$(\n"
+ " reinterpret_cast<const char*>(value), size),\n"
+ " GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
+ "}\n"
+ "inline ::std::string* $classname$::mutable_$name$() {\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " return $oneof_prefix$$name$_.Mutable($default_variable$,\n"
+ " GetArenaNoVirtual());\n"
+ " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+ "}\n"
+ "inline ::std::string* $classname$::$release_name$() {\n"
+ " if (has_$name$()) {\n"
+ " clear_has_$oneof_name$();\n"
+ " return $oneof_prefix$$name$_.Release($default_variable$,\n"
+ " GetArenaNoVirtual());\n"
+ " } else {\n"
+ " return NULL;\n"
+ " }\n"
+ "}\n"
+ "inline ::std::string* $classname$::unsafe_arena_release_$name$() {\n"
+ " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
+ " if (has_$name$()) {\n"
+ " clear_has_$oneof_name$();\n"
+ " return $oneof_prefix$$name$_.UnsafeArenaRelease(\n"
+ " $default_variable$, GetArenaNoVirtual());\n"
+ " } else {\n"
+ " return NULL;\n"
+ " }\n"
+ "}\n"
+ "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+ " if (!has_$name$()) {\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " clear_$oneof_name$();\n"
+ " if ($name$ != NULL) {\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.SetAllocated($default_variable$, $name$,\n"
+ " GetArenaNoVirtual());\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n"
+ "inline void $classname$::unsafe_arena_set_allocated_$name$("
+ "::std::string* $name$) {\n"
+ " GOOGLE_DCHECK(GetArenaNoVirtual() != NULL);\n"
+ " if (!has_$name$()) {\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " clear_$oneof_name$();\n"
+ " if ($name$) {\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeArenaSetAllocated($default_variable$, "
+ "$name$, GetArenaNoVirtual());\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n");
} else {
+ // No-arena case.
printer->Print(variables_,
- " $oneof_prefix$$name$_ = new ::std::string(*$default_variable$);\n");
+ "inline const ::std::string& $classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_get:$full_name$)\n"
+ " if (has_$name$()) {\n"
+ " return $oneof_prefix$$name$_.GetNoArena($default_variable$);\n"
+ " }\n"
+ " return *$default_variable$;\n"
+ "}\n"
+ "inline void $classname$::set_$name$(const ::std::string& value) {\n"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " $oneof_prefix$$name$_.SetNoArena($default_variable$, value);\n"
+ " // @@protoc_insertion_point(field_set:$full_name$)\n"
+ "}\n"
+ "inline void $classname$::set_$name$(const char* value) {\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " $oneof_prefix$$name$_.SetNoArena($default_variable$,\n"
+ " $string_piece$(value));\n"
+ " // @@protoc_insertion_point(field_set_char:$full_name$)\n"
+ "}\n"
+ "inline "
+ "void $classname$::set_$name$(const $pointer_type$* value, size_t size) {\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " $oneof_prefix$$name$_.SetNoArena($default_variable$, $string_piece$(\n"
+ " reinterpret_cast<const char*>(value), size));\n"
+ " // @@protoc_insertion_point(field_set_pointer:$full_name$)\n"
+ "}\n"
+ "inline ::std::string* $classname$::mutable_$name$() {\n"
+ " if (!has_$name$()) {\n"
+ " clear_$oneof_name$();\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_mutable:$full_name$)\n"
+ " return $oneof_prefix$$name$_.MutableNoArena($default_variable$);\n"
+ "}\n"
+ "inline ::std::string* $classname$::$release_name$() {\n"
+ " if (has_$name$()) {\n"
+ " clear_has_$oneof_name$();\n"
+ " return $oneof_prefix$$name$_.ReleaseNoArena($default_variable$);\n"
+ " } else {\n"
+ " return NULL;\n"
+ " }\n"
+ "}\n"
+ "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
+ " if (!has_$name$()) {\n"
+ " $oneof_prefix$$name$_.UnsafeSetDefault($default_variable$);\n"
+ " }\n"
+ " clear_$oneof_name$();\n"
+ " if ($name$ != NULL) {\n"
+ " set_has_$name$();\n"
+ " $oneof_prefix$$name$_.SetAllocatedNoArena($default_variable$,\n"
+ " $name$);\n"
+ " }\n"
+ " // @@protoc_insertion_point(field_set_allocated:$full_name$)\n"
+ "}\n");
}
- printer->Print(variables_,
- " }\n"
- " return $oneof_prefix$$name$_;\n"
- "}\n"
- "inline ::std::string* $classname$::$release_name$() {\n"
- " if (has_$name$()) {\n"
- " clear_has_$oneof_name$();\n"
- " ::std::string* temp = $oneof_prefix$$name$_;\n"
- " $oneof_prefix$$name$_ = NULL;\n"
- " return temp;\n"
- " } else {\n"
- " return NULL;\n"
- " }\n"
- "}\n"
- "inline void $classname$::set_allocated_$name$(::std::string* $name$) {\n"
- " clear_$oneof_name$();\n"
- " if ($name$) {\n"
- " set_has_$name$();\n"
- " $oneof_prefix$$name$_ = $name$;\n"
- " }\n"
- "}\n");
}
void StringOneofFieldGenerator::
GenerateClearingCode(io::Printer* printer) const {
+ if (SupportsArenas(descriptor_)) {
printer->Print(variables_,
- "delete $oneof_prefix$$name$_;\n");
+ "$oneof_prefix$$name$_.Destroy($default_variable$,\n"
+ " GetArenaNoVirtual());\n");
+ } else {
+ printer->Print(variables_,
+ "$oneof_prefix$$name$_.DestroyNoArena($default_variable$);\n");
+ }
}
void StringOneofFieldGenerator::
@@ -425,25 +605,45 @@ GenerateSwappingCode(io::Printer* printer) const {
void StringOneofFieldGenerator::
GenerateConstructorCode(io::Printer* printer) const {
- if (!descriptor_->default_value_string().empty()) {
+ printer->Print(variables_,
+ " const_cast< ::google::protobuf::internal::ArenaStringPtr*>("
+ "&$classname$_default_oneof_instance_->$name$_)->UnsafeSetDefault("
+ "$default_variable$);\n");
+}
+
+void StringOneofFieldGenerator::
+GenerateDestructorCode(io::Printer* printer) const {
+ if (SupportsArenas(descriptor_)) {
printer->Print(variables_,
- " $classname$_default_oneof_instance_->$name$_ = "
- "$classname$::$default_variable$;\n");
+ "if (has_$name$()) {\n"
+ " $oneof_prefix$$name$_.Destroy($default_variable$,\n"
+ " GetArenaNoVirtual());\n"
+ "}\n");
} else {
printer->Print(variables_,
- " $classname$_default_oneof_instance_->$name$_ = "
- "$default_variable$;\n");
+ "if (has_$name$()) {\n"
+ " $oneof_prefix$$name$_.DestroyNoArena($default_variable$);\n"
+ "}\n");
}
}
void StringOneofFieldGenerator::
-GenerateDestructorCode(io::Printer* printer) const {
- printer->Print(variables_,
- "if (has_$name$()) {\n"
- " delete $oneof_prefix$$name$_;\n"
- "}\n");
+GenerateMergeFromCodedStream(io::Printer* printer) const {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n"
+ " input, this->mutable_$name$()));\n");
+
+ if (HasUtf8Verification(descriptor_->file()) &&
+ descriptor_->type() == FieldDescriptor::TYPE_STRING) {
+ printer->Print(variables_,
+ "::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
+ " this->$name$().data(), this->$name$().length(),\n"
+ " ::google::protobuf::internal::WireFormat::PARSE,\n"
+ " \"$full_name$\");\n");
+ }
}
+
// ===================================================================
RepeatedStringFieldGenerator::
@@ -566,7 +766,7 @@ GenerateMergingCode(io::Printer* printer) const {
void RepeatedStringFieldGenerator::
GenerateSwappingCode(io::Printer* printer) const {
- printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
+ printer->Print(variables_, "$name$_.UnsafeArenaSwap(&other->$name$_);\n");
}
void RepeatedStringFieldGenerator::
@@ -586,7 +786,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
" this->$name$(this->$name$_size() - 1).data(),\n"
" this->$name$(this->$name$_size() - 1).length(),\n"
" ::google::protobuf::internal::WireFormat::PARSE,\n"
- " \"$name$\");\n");
+ " \"$full_name$\");\n");
}
}
@@ -600,7 +800,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
"::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
" this->$name$(i).data(), this->$name$(i).length(),\n"
" ::google::protobuf::internal::WireFormat::SERIALIZE,\n"
- " \"$name$\");\n");
+ " \"$full_name$\");\n");
}
printer->Print(variables_,
" ::google::protobuf::internal::WireFormatLite::Write$declared_type$(\n"
@@ -618,7 +818,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
" ::google::protobuf::internal::WireFormat::VerifyUTF8StringNamedField(\n"
" this->$name$(i).data(), this->$name$(i).length(),\n"
" ::google::protobuf::internal::WireFormat::SERIALIZE,\n"
- " \"$name$\");\n");
+ " \"$full_name$\");\n");
}
printer->Print(variables_,
" target = ::google::protobuf::internal::WireFormatLite::\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h
index 86da38f2..0a5ca440 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h
@@ -88,6 +88,7 @@ class StringOneofFieldGenerator : public StringFieldGenerator {
void GenerateSwappingCode(io::Printer* printer) const;
void GenerateConstructorCode(io::Printer* printer) const;
void GenerateDestructorCode(io::Printer* printer) const;
+ void GenerateMergeFromCodedStream(io::Printer* printer) const;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(StringOneofFieldGenerator);
diff --git a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
index 6b7f8308..4fa3c144 100644
--- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
+++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
@@ -35,6 +35,7 @@
// This file tests that various identifiers work as field and type names even
// though the same identifiers are used internally by the C++ code generator.
+syntax = "proto2";
// Some generic_services option(s) added automatically.
// See: http://go/proto2-generic-services-default
@@ -58,7 +59,7 @@ message TestConflictingSymbolNames {
optional int32 total_size = 6;
optional int32 tag = 7;
- enum TestEnum { FOO = 1; }
+ enum TestEnum { FOO = 0; }
message Data1 { repeated int32 data = 1; }
message Data2 { repeated TestEnum data = 1; }
message Data3 { repeated string data = 1; }
@@ -99,6 +100,8 @@ message TestConflictingSymbolNames {
optional uint32 int = 30;
optional uint32 friend = 31;
optional uint32 class = 37;
+ optional uint32 typedecl = 39;
+ optional uint32 auto = 40;
// The generator used to #define a macro called "DO" inside the .cc file.
message DO {}
@@ -116,15 +119,18 @@ message TestConflictingSymbolNames {
// names.
optional DO release_do = 36;
- extensions 1000 to max;
-}
+ // For clashing local variables in Serialize and ByteSize calculation.
+ optional string target = 38;
-message TestConflictingSymbolNamesExtension {
- extend TestConflictingSymbolNames {
- repeated int32 repeated_int32_ext = 20423638 [packed=true];
- }
+ extensions 1000 to max; // NO_PROTO3
}
+message TestConflictingSymbolNamesExtension { // NO_PROTO3
+ extend TestConflictingSymbolNames { // NO_PROTO3
+ repeated int32 repeated_int32_ext = 20423638 [packed=true]; // NO_PROTO3
+ } // NO_PROTO3
+} // NO_PROTO3
+
message DummyMessage {}
service TestConflictingMethodNames {
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index 93e1c3f1..c509a6a9 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -47,6 +47,9 @@
#include <google/protobuf/compiler/cpp/cpp_unittest.h>
#include <memory>
+#ifndef _SHARED_PTR_H
+#include <google/protobuf/stubs/shared_ptr.h>
+#endif
#include <vector>
#include <google/protobuf/unittest.pb.h>