Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(969)

Unified Diff: components/tracing/proto_zero_plugin/proto_zero_generator.cc

Issue 2083373002: proto_zero_plugin [NOT FOR REVIEW]. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: full_featured_will_split_into_smaller_CLs_for_review Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/tracing/proto_zero_plugin/proto_zero_generator.cc
diff --git a/components/tracing/proto_zero_plugin/proto_zero_generator.cc b/components/tracing/proto_zero_plugin/proto_zero_generator.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c4a504519951571a72358a8426747ec624f5539a
--- /dev/null
+++ b/components/tracing/proto_zero_plugin/proto_zero_generator.cc
@@ -0,0 +1,400 @@
+// Copyright (c) 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "proto_zero_generator.h"
+
+#include <algorithm>
+#include <memory>
+#include <string>
+
+#include "third_party/protobuf/src/google/protobuf/descriptor.h"
+#include "third_party/protobuf/src/google/protobuf/io/printer.h"
+#include "third_party/protobuf/src/google/protobuf/io/zero_copy_stream.h"
+#include "third_party/protobuf/src/google/protobuf/stubs/strutil.h"
+
+namespace tracing {
+namespace proto {
+
+// MessageDescriptor is a longer name but has more obvious meaning.
Primiano Tucci (use gerrit) 2016/07/11 16:52:07 It also makes the class harder to codesearch. I'd
+using MessageDescriptor = google::protobuf::Descriptor;
+using google::protobuf::EnumDescriptor;
+using google::protobuf::EnumValueDescriptor;
+using google::protobuf::FieldDescriptor;
+using google::protobuf::FileDescriptor;
+using google::protobuf::io::Printer;
+using google::protobuf::io::ZeroCopyOutputStream;
+
+using google::protobuf::Split;
+using google::protobuf::StripPrefixString;
+using google::protobuf::StripString;
+using google::protobuf::StripSuffixString;
+using google::protobuf::UpperString;
+
+namespace {
+
+class GeneratorJob {
+ public:
+ GeneratorJob(const FileDescriptor* file, Printer* printer)
+ : file_(file), printer_(printer) {}
+
+ bool GenerateStubs() {
+ Prepare();
+ PrintPrologue();
+ for (const EnumDescriptor* enumeration: enums_) {
Primiano Tucci (use gerrit) 2016/07/11 16:52:07 you can drop the braces for single line for loops
+ PrintEnum(enumeration);
+ }
+ for (const MessageDescriptor* message : messages_) {
+ PrintMessage(message);
+ }
+ PrintEpilogue();
+ return error_.empty();
+ }
+
+ std::string GetFirstError() {
Primiano Tucci (use gerrit) 2016/07/11 16:52:07 not sure you want to return this by copy. I think
+ return error_;
+ }
+
+ private:
+ // Get C++ class name corresponding to message/enum descriptor.
+ // Nested names are splitted by underscores.
+ template <class T>
+ std::string GetCppClassName(const T* descriptor, bool absolute = false) {
+ std::string local_name = descriptor->name();
+ if (local_name.find('_') != std::string::npos) {
+ Abort("Underscores are not permitted in proto's type name.");
+ return " /* Invalid name */ ";
+ }
+ std::string name =
+ StripPrefixString(descriptor->full_name(), package_ + ".");
+ StripString(&name, ".", '_');
+ if (absolute) {
+ name = full_namespace_prefix_ + name;
+ }
+ return name;
+ }
+
+ // Small enums can be written faster without involving VarInt encoder.
+ inline bool IsEnumOptimal(const EnumDescriptor* enumeration) {
+ for (int i = 0; i < enumeration->value_count(); ++i) {
+ int32_t number = enumeration->value(i)->number();
+ if (number < 0 || number > 0x7F)
+ return false;
+ }
+ return true;
+ }
+
+ // If something went wrong, plugin returns the first error occured.
+ void Abort(const std::string& reason) {
+ if (error_.empty()) {
+ error_ = reason;
+ }
+ }
+
+ // Scanning pass.
Primiano Tucci (use gerrit) 2016/07/11 16:52:07 This comment doesn't say anything more than "Prepa
+ void Prepare() {
+ // Package name evaluates to a series of namespaces.
+ package_ = file_->package();
+ namespaces_ = Split(package_, ".");
+ full_namespace_prefix_ = "::";
+ for (const std::string& ns : namespaces_) {
+ full_namespace_prefix_ += ns + "::";
+ }
+ // Collect message descriptors in DFS order.
+ std::vector<const MessageDescriptor*> stack;
+ for (int i = 0; i < file_->message_type_count(); ++i) {
+ stack.push_back(file_->message_type(i));
+ }
+ while (!stack.empty()) {
+ const MessageDescriptor* message = stack.back();
+ stack.pop_back();
+ messages_.push_back(message);
+ for (int i = 0; i < message->nested_type_count(); ++i) {
+ stack.push_back(message->nested_type(i));
+ }
+ }
+ // Collect enums.
+ for (int i = 0; i < file_->enum_type_count(); ++i) {
+ enums_.push_back(file_->enum_type(i));
+ }
+ for (const MessageDescriptor* message : messages_) {
+ for (int i = 0; i < message->enum_type_count(); ++i) {
+ enums_.push_back(message->enum_type(i));
+ }
+ }
+ }
+
+ // Print top header, namespaces and forward declarations.
+ void PrintPrologue() {
+ std::string guard = package_ + "_" + file_->name() + "_H_";
+ UpperString(&guard);
+ StripString(&guard, ".-", '_');
+ printer_->Print(
+ "// Autogenerated. DO NOT EDIT.\n"
+ "// Protoc has generated these stubs "
+ "with //components/tracing/proto_zero_plugin.\n\n"
+ "#ifndef $guard$\n"
+ "#define $guard$\n\n"
+ "#include <inttypes.h>\n\n"
Primiano Tucci (use gerrit) 2016/07/11 16:52:07 s/inttypes/stdint/
+ "// Runtime is optional for testing purposes.\n"
+ "#ifndef PROTO_ZERO_NO_RUNTIME\n"
+ "#include \"components/tracing/core/proto_zero_message.h\"\n"
+ "#endif\n\n",
+ "guard", guard);
+ // Print namespaces.
Primiano Tucci (use gerrit) 2016/07/11 16:52:07 add a blank newline before these comments. It make
+ for (const std::string& ns : namespaces_) {
+ printer_->Print("namespace $ns$ {\n", "ns", ns);
+ }
+ printer_->Print("\n");
+ // Print forward declarations.
+ for (const MessageDescriptor* message : messages_) {
+ printer_->Print(
+ "class $class$;\n",
+ "class", GetCppClassName(message));
+ }
+ printer_->Print("\n");
+ }
+
+ void PrintSimpleField(const FieldDescriptor* field) {
+ std::string appender;
+ std::string cpp_type;
+ std::string action = field->is_repeated() ? "add" : "set";
+
+ switch (field->type()) {
+ case FieldDescriptor::TYPE_BOOL: {
+ appender = "AppendBool";
+ cpp_type = "bool";
+ break;
+ }
+ case FieldDescriptor::TYPE_INT32: {
+ appender = "AppendInt32";
+ cpp_type = "int32_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_INT64: {
+ appender = "AppendInt64";
+ cpp_type = "int64_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_UINT32: {
+ appender = "AppendUint32";
+ cpp_type = "uint32_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_UINT64: {
+ appender = "AppendUint64";
+ cpp_type = "uint64_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_SINT32: {
+ appender = "AppendSint32";
+ cpp_type = "int32_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_SINT64: {
+ appender = "AppendSint64";
+ cpp_type = "int64_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_FIXED32: {
+ appender = "AppendFixed32";
+ cpp_type = "uint32_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_FIXED64: {
+ appender = "AppendFixed64";
+ cpp_type = "uint64_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_SFIXED32: {
+ appender = "AppendSfixed32";
+ cpp_type = "int32_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_SFIXED64: {
+ appender = "AppendSfixed64";
+ cpp_type = "int64_t";
+ break;
+ }
+ case FieldDescriptor::TYPE_FLOAT: {
+ appender = "AppendFloat";
+ cpp_type = "float";
+ break;
+ }
+ case FieldDescriptor::TYPE_DOUBLE: {
+ appender = "AppendDouble";
+ cpp_type = "double";
+ break;
+ }
+ case FieldDescriptor::TYPE_ENUM: {
+ if (IsEnumOptimal(field->enum_type())) {
+ appender = "AppendTinyNumber";
+ } else {
+ appender = "AppendInt32";
+ }
+ cpp_type = GetCppClassName(field->enum_type(), true);
+ break;
+ }
+ case FieldDescriptor::TYPE_STRING: {
+ appender = "AppendString";
+ cpp_type = "const char*";
+ break;
+ }
+ case FieldDescriptor::TYPE_BYTES: {
+ printer_->Print(
+ "void $action$_$name$(const uint8_t* data, size_t size) {\n"
+ " AppendBytes($key$, data, size);\n"
+ "}\n",
+ "action", action,
+ "name", field->name(),
+ "key", std::to_string(field->number()));
+ return;
+ }
+ default: {
+ Abort("Unsupported field type.");
+ return;
+ }
+ }
+ printer_->Print(
+ "void $action$_$name$($cpp_type$ value) {\n"
+ " $appender$($key$, value);\n"
+ "}\n",
+ "appender", appender,
+ "cpp_type", cpp_type,
+ "action", action,
+ "name", field->name(),
+ "key", std::to_string(field->number()));
+ }
+
+ // Embedded message field.
+ void PrintNestedMessageField(const FieldDescriptor* field) {
+ printer_->Print(
+ "$class$* $action$_$name$() {\n"
+ " $class$* nested;\n"
+ " OpenNestedMessage($key$, &nested);\n"
+ " return nested;\n"
+ "}\n",
+ "action", field->is_repeated() ? "add" : "set",
+ "class", GetCppClassName(field->message_type()),
+ "name", field->name(),
+ "key", std::to_string(field->number()));
+ }
+
+ // Print fields of the message.
+ void PrintFields(const MessageDescriptor* message) {
+ for (int i = 0; i < message->field_count(); ++i) {
+ const FieldDescriptor* field = message->field(i);
+ if (field->is_required()) {
+ Abort("Required fields are not supported.");
+ return;
+ }
+ if (field->is_packed()) {
+ Abort("Packed repeated fields are not supported.");
+ return;
+ }
+ if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
+ PrintSimpleField(field);
+ } else {
+ PrintNestedMessageField(field);
+ }
+ }
+ }
+
+ // Print enum type definition.
+ void PrintEnum(const EnumDescriptor* enumeration) {
+ printer_->Print(
+ "enum $class$ : int32_t {\n",
+ "class", GetCppClassName(enumeration));
+ printer_->Indent();
+ for (int i = 0; i < enumeration->value_count(); ++i) {
+ const EnumValueDescriptor* value = enumeration->value(i);
+ printer_->Print(
+ "$name$ = $number$,\n",
+ "name", value->name(),
+ "number", std::to_string(value->number()));
+ }
+ printer_->Outdent();
+ printer_->Print("};\n\n");
+ }
+
+ // Print message class definition.
+ void PrintMessage(const MessageDescriptor* message) {
+ printer_->Print(
+ "class $class$ : public $base$ {\n"
+ " public:\n",
+
+ "class", GetCppClassName(message),
+ "base", "::tracing::proto::AppendOnlyProtoMessage");
+ printer_->Indent();
+ // Using nested messages.
+ for (int i = 0; i < message->nested_type_count(); ++i) {
+ const MessageDescriptor* nested_message = message->nested_type(i);
+ printer_->Print(
+ "using $local_name$ = $global_name$;\n",
+ "local_name", nested_message->name(),
+ "global_name", GetCppClassName(nested_message, true));
+ }
+ // Using nested enums.
+ for (int i = 0; i < message->enum_type_count(); ++i) {
+ const EnumDescriptor* nested_enum = message->enum_type(i);
+ printer_->Print(
+ "using $local_name$ = $global_name$;\n",
+ "local_name", nested_enum->name(),
+ "global_name", GetCppClassName(nested_enum, true));
+ }
+ PrintFields(message);
+ printer_->Outdent();
+ printer_->Print("};\n\n");
+ }
+
+ // Closing braces.
+ void PrintEpilogue() {
+ for (auto it = namespaces_.rbegin(); it != namespaces_.rend(); ++it) {
+ printer_->Print("} // namespace $ns$\n", "ns", *it);
+ }
+ printer_->Print("#endif // Include guard.\n");
+ }
+
+ const FileDescriptor* const file_;
+ Printer* const printer_;
+ std::string error_;
+
+ std::string package_;
+ std::vector<std::string> namespaces_;
+ std::string full_namespace_prefix_;
+ std::vector<const MessageDescriptor*> messages_;
+ std::vector<const EnumDescriptor*> enums_;
+};
+
+} // namespace
+
+Generator::Generator() {
+}
+
+Generator::~Generator() {
+}
+
+bool Generator::Generate(const FileDescriptor* file,
+ const std::string& options,
+ google::protobuf::compiler::GeneratorContext* context,
+ std::string* error) const {
+
+ std::string stub_name = StripSuffixString(file->name(), ".proto") + ".zeropb";
+ std::unique_ptr<ZeroCopyOutputStream> pb_h(context->Open(stub_name + ".h"));
+ std::unique_ptr<ZeroCopyOutputStream> pb_cc(context->Open(stub_name + ".cc"));
+ // $ used as variable delimiter.
+ Printer pb_h_printer(pb_h.get(), '$');
+ Printer pb_cc_printer(pb_cc.get(), '$');
+
+ GeneratorJob job(file, &pb_h_printer);
+ if (!job.GenerateStubs()) {
+ *error = job.GetFirstError();
+ return false;
+ }
+ pb_cc_printer.Print("// This file intentionally left blank.\n");
+
+ return true;
+}
+
+} // namespace proto
+} // namespace tracing
« no previous file with comments | « components/tracing/proto_zero_plugin/proto_zero_generator.h ('k') | components/tracing/proto_zero_plugin/proto_zero_plugin.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698