From fccb146e3fe437b0df1e9c50d4b8e1080ddb4bd9 Mon Sep 17 00:00:00 2001 From: "kenton@google.com" Date: Fri, 18 Dec 2009 02:11:36 +0000 Subject: Massive roll-up of changes. See CHANGES.txt. --- src/Makefile.am | 29 +- src/google/protobuf/compiler/code_generator.cc | 9 +- src/google/protobuf/compiler/code_generator.h | 9 +- .../protobuf/compiler/command_line_interface.cc | 468 ++++++- .../protobuf/compiler/command_line_interface.h | 65 +- .../compiler/command_line_interface_unittest.cc | 576 ++++----- .../compiler/cpp/cpp_bootstrap_unittest.cc | 11 +- src/google/protobuf/compiler/cpp/cpp_enum.cc | 14 +- src/google/protobuf/compiler/cpp/cpp_enum_field.cc | 71 +- src/google/protobuf/compiler/cpp/cpp_enum_field.h | 1 + src/google/protobuf/compiler/cpp/cpp_extension.cc | 21 +- src/google/protobuf/compiler/cpp/cpp_field.cc | 29 +- src/google/protobuf/compiler/cpp/cpp_field.h | 6 + src/google/protobuf/compiler/cpp/cpp_file.cc | 59 +- src/google/protobuf/compiler/cpp/cpp_helpers.cc | 53 +- src/google/protobuf/compiler/cpp/cpp_helpers.h | 24 +- src/google/protobuf/compiler/cpp/cpp_message.cc | 99 +- src/google/protobuf/compiler/cpp/cpp_message.h | 1 + .../protobuf/compiler/cpp/cpp_message_field.cc | 36 +- .../protobuf/compiler/cpp/cpp_primitive_field.cc | 78 +- .../protobuf/compiler/cpp/cpp_primitive_field.h | 1 + .../protobuf/compiler/cpp/cpp_string_field.cc | 35 +- src/google/protobuf/compiler/cpp/cpp_unittest.cc | 73 +- src/google/protobuf/compiler/java/java_enum.cc | 5 + .../protobuf/compiler/java/java_enum_field.cc | 46 +- .../protobuf/compiler/java/java_enum_field.h | 3 + .../protobuf/compiler/java/java_extension.cc | 3 +- src/google/protobuf/compiler/java/java_field.cc | 10 + src/google/protobuf/compiler/java/java_field.h | 2 + src/google/protobuf/compiler/java/java_file.cc | 40 +- src/google/protobuf/compiler/java/java_file.h | 5 + .../protobuf/compiler/java/java_generator.cc | 1 + src/google/protobuf/compiler/java/java_helpers.cc | 43 +- src/google/protobuf/compiler/java/java_helpers.h | 18 +- src/google/protobuf/compiler/java/java_message.cc | 83 +- .../protobuf/compiler/java/java_message_field.cc | 18 +- .../protobuf/compiler/java/java_message_field.h | 2 + .../protobuf/compiler/java/java_primitive_field.cc | 46 +- .../protobuf/compiler/java/java_primitive_field.h | 3 + src/google/protobuf/compiler/main.cc | 1 + src/google/protobuf/compiler/parser.cc | 11 +- src/google/protobuf/compiler/parser_unittest.cc | 6 + .../protobuf/compiler/python/python_generator.cc | 227 +++- .../protobuf/compiler/python/python_generator.h | 16 +- src/google/protobuf/descriptor.cc | 20 +- src/google/protobuf/descriptor.h | 23 +- src/google/protobuf/descriptor.pb.cc | 1327 ++++++++++++-------- src/google/protobuf/descriptor.pb.h | 637 ++++++---- src/google/protobuf/descriptor.proto | 22 +- src/google/protobuf/descriptor_database.cc | 30 + src/google/protobuf/descriptor_database.h | 4 + .../protobuf/descriptor_database_unittest.cc | 34 + src/google/protobuf/descriptor_unittest.cc | 3 + src/google/protobuf/dynamic_message.cc | 80 +- src/google/protobuf/dynamic_message.h | 27 +- src/google/protobuf/extension_set.cc | 304 +++-- src/google/protobuf/extension_set.h | 202 ++- src/google/protobuf/extension_set_heavy.cc | 257 +++- src/google/protobuf/extension_set_unittest.cc | 159 +++ .../protobuf/generated_message_reflection.cc | 194 ++- src/google/protobuf/generated_message_reflection.h | 17 +- src/google/protobuf/generated_message_util.cc | 9 + src/google/protobuf/generated_message_util.h | 18 +- src/google/protobuf/io/coded_stream.cc | 379 +++--- src/google/protobuf/io/coded_stream.h | 347 ++++- src/google/protobuf/io/coded_stream_unittest.cc | 88 +- src/google/protobuf/io/gzip_stream.cc | 2 +- src/google/protobuf/io/printer.cc | 25 +- src/google/protobuf/io/printer.h | 19 +- src/google/protobuf/io/printer_unittest.cc | 69 +- src/google/protobuf/io/tokenizer.cc | 2 +- src/google/protobuf/io/tokenizer.h | 5 + src/google/protobuf/io/tokenizer_unittest.cc | 6 + src/google/protobuf/io/zero_copy_stream_impl.h | 9 +- .../protobuf/io/zero_copy_stream_unittest.cc | 3 +- src/google/protobuf/message.cc | 4 +- src/google/protobuf/message.h | 28 +- src/google/protobuf/message_lite.cc | 59 +- src/google/protobuf/repeated_field.cc | 12 + src/google/protobuf/repeated_field.h | 273 +++- src/google/protobuf/repeated_field_unittest.cc | 214 ++++ src/google/protobuf/stubs/common.h | 31 +- src/google/protobuf/stubs/strutil.cc | 34 +- src/google/protobuf/stubs/strutil.h | 8 + src/google/protobuf/test_util.cc | 88 +- src/google/protobuf/test_util.h | 3 + src/google/protobuf/testing/file.cc | 13 +- src/google/protobuf/text_format.cc | 156 ++- src/google/protobuf/text_format.h | 35 + src/google/protobuf/text_format_unittest.cc | 83 +- src/google/protobuf/unittest.proto | 93 +- .../protobuf/unittest_enormous_descriptor.proto | 1 + src/google/protobuf/unknown_field_set.cc | 12 +- src/google/protobuf/unknown_field_set.h | 10 +- src/google/protobuf/wire_format.cc | 185 ++- src/google/protobuf/wire_format_lite.cc | 175 ++- src/google/protobuf/wire_format_lite.h | 156 ++- src/google/protobuf/wire_format_lite_inl.h | 366 ++++-- src/google/protobuf/wire_format_unittest.cc | 71 ++ 99 files changed, 6391 insertions(+), 2397 deletions(-) (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index 53da6f1e..510613ce 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,7 +24,8 @@ AM_LDFLAGS = $(PTHREAD_CFLAGS) # If I say "dist_include_DATA", automake complains that $(includedir) is not # a "legitimate" directory for DATA. Screw you, automake. protodir = $(includedir) -nobase_dist_proto_DATA = google/protobuf/descriptor.proto +nobase_dist_proto_DATA = google/protobuf/descriptor.proto \ + google/protobuf/compiler/plugin.proto # Not sure why these don't get cleaned automatically. clean-local: @@ -66,6 +67,8 @@ nobase_include_HEADERS = \ google/protobuf/compiler/command_line_interface.h \ google/protobuf/compiler/importer.h \ google/protobuf/compiler/parser.h \ + google/protobuf/compiler/plugin.h \ + google/protobuf/compiler/plugin.pb.h \ google/protobuf/compiler/cpp/cpp_generator.h \ google/protobuf/compiler/java/java_generator.h \ google/protobuf/compiler/python/python_generator.h @@ -87,6 +90,7 @@ libprotobuf_lite_la_SOURCES = \ google/protobuf/repeated_field.cc \ google/protobuf/wire_format_lite.cc \ google/protobuf/io/coded_stream.cc \ + google/protobuf/io/coded_stream_inl.h \ google/protobuf/io/zero_copy_stream.cc \ google/protobuf/io/zero_copy_stream_impl_lite.cc @@ -123,6 +127,10 @@ libprotoc_la_LDFLAGS = -version-info 5:0:0 libprotoc_la_SOURCES = \ google/protobuf/compiler/code_generator.cc \ google/protobuf/compiler/command_line_interface.cc \ + google/protobuf/compiler/plugin.cc \ + google/protobuf/compiler/plugin.pb.cc \ + google/protobuf/compiler/subprocess.cc \ + google/protobuf/compiler/subprocess.h \ google/protobuf/compiler/cpp/cpp_enum.cc \ google/protobuf/compiler/cpp/cpp_enum.h \ google/protobuf/compiler/cpp/cpp_enum_field.cc \ @@ -186,6 +194,7 @@ protoc_inputs = \ google/protobuf/unittest_lite.proto \ google/protobuf/unittest_import_lite.proto \ google/protobuf/unittest_lite_imports_nonlite.proto \ + google/protobuf/unittest_no_generic_services.proto \ google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto EXTRA_DIST = \ @@ -226,6 +235,8 @@ protoc_outputs = \ google/protobuf/unittest_custom_options.pb.h \ google/protobuf/unittest_lite_imports_nonlite.pb.cc \ google/protobuf/unittest_lite_imports_nonlite.pb.h \ + google/protobuf/unittest_no_generic_services.pb.cc \ + google/protobuf/unittest_no_generic_services.pb.h \ google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.cc \ google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h @@ -265,7 +276,7 @@ COMMON_TEST_SOURCES = \ google/protobuf/testing/file.cc \ google/protobuf/testing/file.h -check_PROGRAMS = protobuf-test protobuf-lazy-descriptor-test protobuf-lite-test $(GZCHECKPROGRAMS) +check_PROGRAMS = protobuf-test protobuf-lazy-descriptor-test protobuf-lite-test test_plugin $(GZCHECKPROGRAMS) protobuf_test_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la \ $(top_builddir)/gtest/lib/libgtest.la \ $(top_builddir)/gtest/lib/libgtest_main.la @@ -297,9 +308,14 @@ protobuf_test_SOURCES = \ google/protobuf/io/zero_copy_stream_unittest.cc \ google/protobuf/compiler/command_line_interface_unittest.cc \ google/protobuf/compiler/importer_unittest.cc \ + google/protobuf/compiler/mock_code_generator.cc \ + google/protobuf/compiler/mock_code_generator.h \ google/protobuf/compiler/parser_unittest.cc \ google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc \ google/protobuf/compiler/cpp/cpp_unittest.cc \ + google/protobuf/compiler/cpp/cpp_plugin_unittest.cc \ + google/protobuf/compiler/java/java_plugin_unittest.cc \ + google/protobuf/compiler/python/python_plugin_unittest.cc \ $(COMMON_TEST_SOURCES) nodist_protobuf_test_SOURCES = $(protoc_outputs) @@ -325,6 +341,15 @@ protobuf_lite_test_SOURCES = \ google/protobuf/test_util_lite.h nodist_protobuf_lite_test_SOURCES = $(protoc_lite_outputs) +# Test plugin binary. +test_plugin_LDADD = $(PTHREAD_LIBS) libprotobuf.la libprotoc.la \ + $(top_builddir)/gtest/lib/libgtest.la +test_plugin_SOURCES = \ + google/protobuf/compiler/mock_code_generator.cc \ + google/protobuf/testing/file.cc \ + google/protobuf/testing/file.h \ + google/protobuf/compiler/test_plugin.cc + if HAVE_ZLIB zcgzip_LDADD = $(PTHREAD_LIBS) libprotobuf.la zcgzip_SOURCES = google/protobuf/testing/zcgzip.cc diff --git a/src/google/protobuf/compiler/code_generator.cc b/src/google/protobuf/compiler/code_generator.cc index 0def84d8..3413a36a 100644 --- a/src/google/protobuf/compiler/code_generator.cc +++ b/src/google/protobuf/compiler/code_generator.cc @@ -34,6 +34,7 @@ #include +#include #include namespace google { @@ -43,9 +44,15 @@ namespace compiler { CodeGenerator::~CodeGenerator() {} OutputDirectory::~OutputDirectory() {} +io::ZeroCopyOutputStream* OutputDirectory::OpenForInsert( + const string& filename, const string& insertion_point) { + GOOGLE_LOG(FATAL) << "This OutputDirectory does not support insertion."; + return NULL; // make compiler happy +} + // Parses a set of comma-delimited name/value pairs. void ParseGeneratorParameter(const string& text, - vector >* output) { + vector >* output) { vector parts; SplitStringUsing(text, ",", &parts); diff --git a/src/google/protobuf/compiler/code_generator.h b/src/google/protobuf/compiler/code_generator.h index 8a7081f7..47ebb4d2 100644 --- a/src/google/protobuf/compiler/code_generator.h +++ b/src/google/protobuf/compiler/code_generator.h @@ -103,6 +103,13 @@ class LIBPROTOC_EXPORT OutputDirectory { // contain "." or ".." components. virtual io::ZeroCopyOutputStream* Open(const string& filename) = 0; + // Creates a ZeroCopyOutputStream which will insert code into the given file + // at the given insertion point. See plugin.proto for more information on + // insertion points. The default implementation assert-fails -- it exists + // only for backwards-compatibility. + virtual io::ZeroCopyOutputStream* OpenForInsert( + const string& filename, const string& insertion_point); + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(OutputDirectory); }; @@ -114,7 +121,7 @@ class LIBPROTOC_EXPORT OutputDirectory { // parses to the pairs: // ("foo", "bar"), ("baz", ""), ("qux", "corge") extern void ParseGeneratorParameter(const string&, - vector >*); + vector >*); } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc index 3eba3486..39bd370e 100644 --- a/src/google/protobuf/compiler/command_line_interface.cc +++ b/src/google/protobuf/compiler/command_line_interface.cc @@ -32,6 +32,8 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include + #include #include #include @@ -46,15 +48,19 @@ #include #include -#include #include #include +#include +#include #include #include #include #include +#include #include #include +#include +#include namespace google { @@ -182,6 +188,8 @@ class CommandLineInterface::DiskOutputDirectory : public OutputDirectory { // implements OutputDirectory -------------------------------------- io::ZeroCopyOutputStream* Open(const string& filename); + io::ZeroCopyOutputStream* OpenForInsert( + const string& filename, const string& insertion_point); private: string root_; @@ -209,11 +217,45 @@ class CommandLineInterface::ErrorReportingFileOutput private: scoped_ptr file_stream_; - int file_descriptor_; string filename_; DiskOutputDirectory* directory_; }; +// Kind of like ErrorReportingFileOutput, but used when inserting +// (OutputDirectory::OpenForInsert()). In this case, we are writing to a +// temporary file, since we must copy data from the original. We copy the +// data up to the insertion point in the constructor, and the remainder in the +// destructor. We then replace the original file with the temporary, also in +// the destructor. +class CommandLineInterface::InsertionOutputStream + : public io::ZeroCopyOutputStream { + public: + InsertionOutputStream( + const string& filename, + const string& temp_filename, + const string& insertion_point, + int original_file_descriptor, // Takes ownership. + int temp_file_descriptor, // Takes ownership. + DiskOutputDirectory* directory); // Does not take ownership. + ~InsertionOutputStream(); + + // implements ZeroCopyOutputStream --------------------------------- + bool Next(void** data, int* size) { return temp_file_->Next(data, size); } + void BackUp(int count) { temp_file_->BackUp(count); } + int64 ByteCount() const { return temp_file_->ByteCount(); } + + private: + scoped_ptr original_file_; + scoped_ptr temp_file_; + + string filename_; + string temp_filename_; + DiskOutputDirectory* directory_; + + // The contents of the line containing the insertion point. + string magic_line_; +}; + // ------------------------------------------------------------------- CommandLineInterface::DiskOutputDirectory::DiskOutputDirectory( @@ -242,6 +284,8 @@ bool CommandLineInterface::DiskOutputDirectory::VerifyExistence() { return true; } +// ------------------------------------------------------------------- + io::ZeroCopyOutputStream* CommandLineInterface::DiskOutputDirectory::Open( const string& filename) { // Recursively create parent directories to the output file. @@ -286,7 +330,6 @@ CommandLineInterface::ErrorReportingFileOutput::ErrorReportingFileOutput( const string& filename, DiskOutputDirectory* directory) : file_stream_(new io::FileOutputStream(file_descriptor)), - file_descriptor_(file_descriptor), filename_(filename), directory_(directory) {} @@ -304,6 +347,201 @@ CommandLineInterface::ErrorReportingFileOutput::~ErrorReportingFileOutput() { } } +// ------------------------------------------------------------------- + +io::ZeroCopyOutputStream* +CommandLineInterface::DiskOutputDirectory::OpenForInsert( + const string& filename, const string& insertion_point) { + string path = root_ + filename; + + // Put the temp file in the same directory so that we can simply rename() it + // into place later. + string temp_path = path + ".protoc_temp"; + + // Open the original file. + int original_file; + do { + original_file = open(path.c_str(), O_RDONLY | O_BINARY); + } while (original_file < 0 && errno == EINTR); + + if (original_file < 0) { + // Failed to open. + cerr << path << ": " << strerror(errno) << endl; + had_error_ = true; + // Return a dummy stream. + return new io::ArrayOutputStream(NULL, 0); + } + + // Create the temp file. + int temp_file; + do { + temp_file = + open(temp_path.c_str(), + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666); + } while (temp_file < 0 && errno == EINTR); + + if (temp_file < 0) { + // Failed to open. + cerr << temp_path << ": " << strerror(errno) << endl; + had_error_ = true; + close(original_file); + // Return a dummy stream. + return new io::ArrayOutputStream(NULL, 0); + } + + return new InsertionOutputStream( + path, temp_path, insertion_point, original_file, temp_file, this); +} + +namespace { + +// Helper for reading lines from a ZeroCopyInputStream. +// TODO(kenton): Put somewhere reusable? +class LineReader { + public: + LineReader(io::ZeroCopyInputStream* input) + : input_(input), buffer_(NULL), size_(0) {} + + ~LineReader() { + if (size_ > 0) { + input_->BackUp(size_); + } + } + + bool ReadLine(string* line) { + line->clear(); + + while (true) { + for (int i = 0; i < size_; i++) { + if (buffer_[i] == '\n') { + line->append(buffer_, i + 1); + buffer_ += i + 1; + size_ -= i + 1; + return true; + } + } + + line->append(buffer_, size_); + + const void* void_buffer; + if (!input_->Next(&void_buffer, &size_)) { + buffer_ = NULL; + size_ = 0; + return false; + } + + buffer_ = reinterpret_cast(void_buffer); + } + } + + private: + io::ZeroCopyInputStream* input_; + const char* buffer_; + int size_; +}; + +} // namespace + +CommandLineInterface::InsertionOutputStream::InsertionOutputStream( + const string& filename, + const string& temp_filename, + const string& insertion_point, + int original_file_descriptor, + int temp_file_descriptor, + DiskOutputDirectory* directory) + : original_file_(new io::FileInputStream(original_file_descriptor)), + temp_file_(new io::FileOutputStream(temp_file_descriptor)), + filename_(filename), + temp_filename_(temp_filename), + directory_(directory) { + string magic_string = strings::Substitute( + "@@protoc_insertion_point($0)", insertion_point); + + LineReader reader(original_file_.get()); + io::Printer writer(temp_file_.get(), '$'); + string line; + + while (true) { + if (!reader.ReadLine(&line)) { + int error = temp_file_->GetErrno(); + if (error == 0) { + cerr << filename << ": Insertion point not found: " + << insertion_point << endl; + } else { + cerr << filename << ": " << strerror(error) << endl; + } + original_file_->Close(); + original_file_.reset(); + // Will finish handling error in the destructor. + break; + } + + if (line.find(magic_string) != string::npos) { + // Found the magic line. Since we want to insert before it, save it for + // later. + magic_line_ = line; + break; + } + + writer.PrintRaw(line); + } +} + +CommandLineInterface::InsertionOutputStream::~InsertionOutputStream() { + // C-style error handling is teh best. + bool had_error = false; + + if (original_file_ == NULL) { + // We had an error in the constructor. + had_error = true; + } else { + // Use CodedOutputStream for convenience, so we don't have to deal with + // copying buffers ourselves. + io::CodedOutputStream out(temp_file_.get()); + out.WriteRaw(magic_line_.data(), magic_line_.size()); + + // Write the rest of the original file. + const void* buffer; + int size; + while (original_file_->Next(&buffer, &size)) { + out.WriteRaw(buffer, size); + } + + // Close the original file. + if (!original_file_->Close()) { + cerr << filename_ << ": " << strerror(original_file_->GetErrno()) << endl; + had_error = true; + } + } + + // Check if we had any errors while writing. + if (temp_file_->GetErrno() != 0) { + cerr << filename_ << ": " << strerror(temp_file_->GetErrno()) << endl; + had_error = true; + } + + // Close the temp file. + if (!temp_file_->Close()) { + cerr << filename_ << ": " << strerror(temp_file_->GetErrno()) << endl; + had_error = true; + } + + // If everything was successful, overwrite the original file with the temp + // file. + if (!had_error) { + if (rename(temp_filename_.c_str(), filename_.c_str()) < 0) { + cerr << filename_ << ": rename: " << strerror(errno) << endl; + had_error = true; + } + } + + if (had_error) { + // We had some sort of error so let's try to delete the temp file. + remove(temp_filename_.c_str()); + directory_->set_had_error(true); + } +} + // =================================================================== CommandLineInterface::CommandLineInterface() @@ -323,6 +561,10 @@ void CommandLineInterface::RegisterGenerator(const string& flag_name, generators_[flag_name] = info; } +void CommandLineInterface::AllowPlugins(const string& exe_name_prefix) { + plugin_prefix_ = exe_name_prefix; +} + int CommandLineInterface::Run(int argc, const char* const argv[]) { Clear(); if (!ParseArguments(argc, argv)) return 1; @@ -346,7 +588,7 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { vector parsed_files; - // Parse each file and generate output. + // Parse each file. for (int i = 0; i < input_files_.size(); i++) { // Import the file. const FileDescriptor* parsed_file = importer.Import(input_files_[i]); @@ -359,13 +601,13 @@ int CommandLineInterface::Run(int argc, const char* const argv[]) { "--disallow_services was used." << endl; return 1; } + } - if (mode_ == MODE_COMPILE) { - // Generate output files. - for (int i = 0; i < output_directives_.size(); i++) { - if (!GenerateOutput(parsed_file, output_directives_[i])) { - return 1; - } + // Generate output. + if (mode_ == MODE_COMPILE) { + for (int i = 0; i < output_directives_.size(); i++) { + if (!GenerateOutput(parsed_files, output_directives_[i])) { + return 1; } } } @@ -686,10 +928,37 @@ bool CommandLineInterface::InterpretArgument(const string& name, return false; } + } else if (name == "--plugin") { + if (plugin_prefix_.empty()) { + cerr << "This compiler does not support plugins." << endl; + return false; + } + + string name; + string path; + + string::size_type equals_pos = value.find_first_of('='); + if (equals_pos == string::npos) { + // Use the basename of the file. + string::size_type slash_pos = value.find_last_of('/'); + if (slash_pos == string::npos) { + name = value; + } else { + name = value.substr(slash_pos + 1); + } + path = value; + } else { + name = value.substr(0, equals_pos); + path = value.substr(equals_pos + 1); + } + + plugins_[name] = path; + } else { // Some other flag. Look it up in the generators list. - GeneratorMap::const_iterator iter = generators_.find(name); - if (iter == generators_.end()) { + const GeneratorInfo* generator_info = FindOrNull(generators_, name); + if (generator_info == NULL && + (plugin_prefix_.empty() || !HasSuffixString(name, "_out"))) { cerr << "Unknown flag: " << name << endl; return false; } @@ -703,7 +972,11 @@ bool CommandLineInterface::InterpretArgument(const string& name, OutputDirective directive; directive.name = name; - directive.generator = iter->second.generator; + if (generator_info == NULL) { + directive.generator = NULL; + } else { + directive.generator = generator_info->generator; + } // Split value at ':' to separate the generator parameter from the // filename. However, avoid doing this if the colon is part of a valid @@ -755,6 +1028,17 @@ void CommandLineInterface::PrintHelpText() { " --error_format=FORMAT Set the format in which to print errors.\n" " FORMAT may be 'gcc' (the default) or 'msvs'\n" " (Microsoft Visual Studio format)." << endl; + if (!plugin_prefix_.empty()) { + cerr << +" --plugin=EXECUTABLE Specifies a plugin executable to use.\n" +" Normally, protoc searches the PATH for\n" +" plugins, but you may specify additional\n" +" executables not in the path using this flag.\n" +" Additionally, EXECUTABLE may be of the form\n" +" NAME=PATH, in which case the given plugin name\n" +" is mapped to the given executable even if\n" +" the executable's own name differs." << endl; + } for (GeneratorMap::iterator iter = generators_.begin(); iter != generators_.end(); ++iter) { @@ -768,7 +1052,7 @@ void CommandLineInterface::PrintHelpText() { } bool CommandLineInterface::GenerateOutput( - const FileDescriptor* parsed_file, + const vector& parsed_files, const OutputDirective& output_directive) { // Create the output directory. DiskOutputDirectory output_directory(output_directive.output_location); @@ -780,12 +1064,34 @@ bool CommandLineInterface::GenerateOutput( // Call the generator. string error; - if (!output_directive.generator->Generate( - parsed_file, output_directive.parameter, &output_directory, &error)) { - // Generator returned an error. - cerr << parsed_file->name() << ": " << output_directive.name << ": " - << error << endl; - return false; + if (output_directive.generator == NULL) { + // This is a plugin. + GOOGLE_CHECK(HasPrefixString(output_directive.name, "--") && + HasSuffixString(output_directive.name, "_out")) + << "Bad name for plugin generator: " << output_directive.name; + + // Strip the "--" and "_out" and add the plugin prefix. + string plugin_name = plugin_prefix_ + "gen-" + + output_directive.name.substr(2, output_directive.name.size() - 6); + + if (!GeneratePluginOutput(parsed_files, plugin_name, + output_directive.parameter, + &output_directory, &error)) { + cerr << output_directive.name << ": " << error << endl; + return false; + } + } else { + // Regular generator. + for (int i = 0; i < parsed_files.size(); i++) { + if (!output_directive.generator->Generate( + parsed_files[i], output_directive.parameter, + &output_directory, &error)) { + // Generator returned an error. + cerr << output_directive.name << ": " << parsed_files[i]->name() << ": " + << error << endl; + return false; + } + } } // Check for write errors. @@ -796,6 +1102,84 @@ bool CommandLineInterface::GenerateOutput( return true; } +bool CommandLineInterface::GeneratePluginOutput( + const vector& parsed_files, + const string& plugin_name, + const string& parameter, + OutputDirectory* output_directory, + string* error) { + CodeGeneratorRequest request; + CodeGeneratorResponse response; + + // Build the request. + if (!parameter.empty()) { + request.set_parameter(parameter); + } + + set already_seen; + for (int i = 0; i < parsed_files.size(); i++) { + request.add_file_to_generate(parsed_files[i]->name()); + GetTransitiveDependencies(parsed_files[i], &already_seen, + request.mutable_proto_file()); + } + + // Invoke the plugin. + Subprocess subprocess; + + if (plugins_.count(plugin_name) > 0) { + subprocess.Start(plugins_[plugin_name], Subprocess::EXACT_NAME); + } else { + subprocess.Start(plugin_name, Subprocess::SEARCH_PATH); + } + + string communicate_error; + if (!subprocess.Communicate(request, &response, &communicate_error)) { + *error = strings::Substitute("$0: $1", plugin_name, communicate_error); + return false; + } + + // Write the files. We do this even if there was a generator error in order + // to match the behavior of a compiled-in generator. + scoped_ptr current_output; + for (int i = 0; i < response.file_size(); i++) { + const CodeGeneratorResponse::File& output_file = response.file(i); + + if (!output_file.insertion_point().empty()) { + // Open a file for insert. + // We reset current_output to NULL first so that the old file is closed + // before the new one is opened. + current_output.reset(); + current_output.reset(output_directory->OpenForInsert( + output_file.name(), output_file.insertion_point())); + } else if (!output_file.name().empty()) { + // Starting a new file. Open it. + // We reset current_output to NULL first so that the old file is closed + // before the new one is opened. + current_output.reset(); + current_output.reset(output_directory->Open(output_file.name())); + } else if (current_output == NULL) { + *error = strings::Substitute( + "$0: First file chunk returned by plugin did not specify a file name.", + plugin_name); + return false; + } + + // Use CodedOutputStream for convenience; otherwise we'd need to provide + // our own buffer-copying loop. + io::CodedOutputStream writer(current_output.get()); + writer.WriteString(output_file.content()); + } + + // Check for errors. + if (!response.error().empty()) { + // Generator returned an error. + *error = response.error(); + return false; + } + + return true; +} + bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) { // Look up the type. const Descriptor* type = pool->FindMessageTypeByName(codec_type_); @@ -862,22 +1246,16 @@ bool CommandLineInterface::EncodeOrDecode(const DescriptorPool* pool) { bool CommandLineInterface::WriteDescriptorSet( const vector parsed_files) { FileDescriptorSet file_set; - set already_added; - vector to_add(parsed_files); - - while (!to_add.empty()) { - const FileDescriptor* file = to_add.back(); - to_add.pop_back(); - if (already_added.insert(file).second) { - // This file was not already in the set. - file->CopyTo(file_set.add_file()); - - if (imports_in_descriptor_set_) { - // Add all of this file's dependencies. - for (int i = 0; i < file->dependency_count(); i++) { - to_add.push_back(file->dependency(i)); - } - } + + if (imports_in_descriptor_set_) { + set already_seen; + for (int i = 0; i < parsed_files.size(); i++) { + GetTransitiveDependencies( + parsed_files[i], &already_seen, file_set.mutable_file()); + } + } else { + for (int i = 0; i < parsed_files.size(); i++) { + parsed_files[i]->CopyTo(file_set.add_file()); } } @@ -906,6 +1284,24 @@ bool CommandLineInterface::WriteDescriptorSet( return true; } +void CommandLineInterface::GetTransitiveDependencies( + const FileDescriptor* file, + set* already_seen, + RepeatedPtrField* output) { + if (!already_seen->insert(file).second) { + // Already saw this file. Skip. + return; + } + + // Add all dependencies. + for (int i = 0; i < file->dependency_count(); i++) { + GetTransitiveDependencies(file->dependency(i), already_seen, output); + } + + // Add this file. + file->CopyTo(output->Add()); +} + } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/command_line_interface.h b/src/google/protobuf/compiler/command_line_interface.h index ec658636..1070a83b 100644 --- a/src/google/protobuf/compiler/command_line_interface.h +++ b/src/google/protobuf/compiler/command_line_interface.h @@ -50,10 +50,13 @@ namespace protobuf { class FileDescriptor; // descriptor.h class DescriptorPool; // descriptor.h +class FileDescriptorProto; // descriptor.pb.h +template class RepeatedPtrField; // repeated_field.h namespace compiler { class CodeGenerator; // code_generator.h +class OutputDirectory; // code_generator.h class DiskSourceTree; // importer.h // This class implements the command-line interface to the protocol compiler. @@ -109,6 +112,37 @@ class LIBPROTOC_EXPORT CommandLineInterface { CodeGenerator* generator, const string& help_text); + // Enables "plugins". In this mode, if a command-line flag ends with "_out" + // but does not match any registered generator, the compiler will attempt to + // find a "plugin" to implement the generator. Plugins are just executables. + // They should live somewhere in the PATH. + // + // The compiler determines the executable name to search for by concatenating + // exe_name_prefix with the unrecognized flag name, removing "_out". So, for + // example, if exe_name_prefix is "protoc-" and you pass the flag --foo_out, + // the compiler will try to run the program "protoc-foo". + // + // The plugin program should implement the following usage: + // plugin [--out=OUTDIR] [--parameter=PARAMETER] PROTO_FILES < DESCRIPTORS + // --out indicates the output directory (as passed to the --foo_out + // parameter); if omitted, the current directory should be used. --parameter + // gives the generator parameter, if any was provided. The PROTO_FILES list + // the .proto files which were given on the compiler command-line; these are + // the files for which the plugin is expected to generate output code. + // Finally, DESCRIPTORS is an encoded FileDescriptorSet (as defined in + // descriptor.proto). This is piped to the plugin's stdin. The set will + // include descriptors for all the files listed in PROTO_FILES as well as + // all files that they import. The plugin MUST NOT attempt to read the + // PROTO_FILES directly -- it must use the FileDescriptorSet. + // + // The plugin should generate whatever files are necessary, as code generators + // normally do. It should write the names of all files it generates to + // stdout. The names should be relative to the output directory, NOT absolute + // names or relative to the current directory. If any errors occur, error + // messages should be written to stderr. If an error is fatal, the plugin + // should exit with a non-zero exit code. + void AllowPlugins(const string& exe_name_prefix); + // Run the Protocol Compiler with the given command-line parameters. // Returns the error code which should be returned by main(). // @@ -142,6 +176,7 @@ class LIBPROTOC_EXPORT CommandLineInterface { class ErrorPrinter; class DiskOutputDirectory; class ErrorReportingFileOutput; + class InsertionOutputStream; // Clear state from previous Run(). void Clear(); @@ -176,8 +211,13 @@ class LIBPROTOC_EXPORT CommandLineInterface { // Generate the given output file from the given input. struct OutputDirective; // see below - bool GenerateOutput(const FileDescriptor* proto_file, + bool GenerateOutput(const vector& parsed_files, const OutputDirective& output_directive); + bool GeneratePluginOutput(const vector& parsed_files, + const string& plugin_name, + const string& parameter, + OutputDirectory* output_directory, + string* error); // Implements --encode and --decode. bool EncodeOrDecode(const DescriptorPool* pool); @@ -185,6 +225,17 @@ class LIBPROTOC_EXPORT CommandLineInterface { // Implements the --descriptor_set_out option. bool WriteDescriptorSet(const vector parsed_files); + // Get all transitive dependencies of the given file (including the file + // itself), adding them to the given list of FileDescriptorProtos. The + // protos will be ordered such that every file is listed before any file that + // depends on it, so that you can call DescriptorPool::BuildFile() on them + // in order. Any files in *already_seen will not be added, and each file + // added will be inserted into *already_seen. + static void GetTransitiveDependencies( + const FileDescriptor* file, + set* already_seen, + RepeatedPtrField* output); + // ----------------------------------------------------------------- // The name of the executable as invoked (i.e. argv[0]). @@ -201,6 +252,14 @@ class LIBPROTOC_EXPORT CommandLineInterface { typedef map GeneratorMap; GeneratorMap generators_; + // See AllowPlugins(). If this is empty, plugins aren't allowed. + string plugin_prefix_; + + // Maps specific plugin names to files. When executing a plugin, this map + // is searched first to find the plugin executable. If not found here, the + // PATH (or other OS-specific search strategy) is searched. + map plugins_; + // Stuff parsed from command line. enum Mode { MODE_COMPILE, // Normal mode: parse .proto files and compile them. @@ -223,8 +282,8 @@ class LIBPROTOC_EXPORT CommandLineInterface { // output_directives_ lists all the files we are supposed to output and what // generator to use for each. struct OutputDirective { - string name; - CodeGenerator* generator; + string name; // E.g. "--foo_out" + CodeGenerator* generator; // NULL for plugins string parameter; string output_location; }; diff --git a/src/google/protobuf/compiler/command_line_interface_unittest.cc b/src/google/protobuf/compiler/command_line_interface_unittest.cc index 9da41c02..83850cf9 100644 --- a/src/google/protobuf/compiler/command_line_interface_unittest.cc +++ b/src/google/protobuf/compiler/command_line_interface_unittest.cc @@ -47,10 +47,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -83,28 +85,19 @@ class CommandLineInterfaceTest : public testing::Test { // ----------------------------------------------------------------- // Methods to set up the test (called before Run()). - class MockCodeGenerator; class NullCodeGenerator; - // Registers a MockCodeGenerator with the given name. - MockCodeGenerator* RegisterGenerator(const string& generator_name, - const string& flag_name, - const string& filename, - const string& help_text); - MockCodeGenerator* RegisterErrorGenerator(const string& generator_name, - const string& error_text, - const string& flag_name, - const string& filename, - const string& help_text); - - // Registers a CodeGenerator which will not actually generate anything, - // but records the parameter passed to the generator. - NullCodeGenerator* RegisterNullGenerator(const string& flag_name); + // Normally plugins are allowed for all tests. Call this to explicitly + // disable them. + void DisallowPlugins() { disallow_plugins_ = true; } // Create a temp file within temp_directory_ with the given name. // The containing directory is also created if necessary. void CreateTempFile(const string& name, const string& contents); + // Create a subdirectory within temp_directory_. + void CreateTempDir(const string& name); + void SetInputsAreProtoPathRelative(bool enable) { cli_.SetInputsAreProtoPathRelative(enable); } @@ -130,18 +123,28 @@ class CommandLineInterfaceTest : public testing::Test { bool HasAlternateErrorSubstring(const string& expected_substring); // Checks that MockCodeGenerator::Generate() was called in the given - // context. That is, this tests if the generator with the given name + // context (or the generator in test_plugin.cc, which produces the same + // output). That is, this tests if the generator with the given name // was called with the given parameter and proto file and produced the // given output file. This is checked by reading the output file and // checking that it contains the content that MockCodeGenerator would // generate given these inputs. message_name is the name of the first // message that appeared in the proto file; this is just to make extra // sure that the correct file was parsed. + void ExpectGenerated(const string& generator_name, + const string& parameter, + const string& proto_name, + const string& message_name); void ExpectGenerated(const string& generator_name, const string& parameter, const string& proto_name, const string& message_name, - const string& output_file); + const string& output_directory); + void ExpectGeneratedWithInsertions(const string& generator_name, + const string& parameter, + const string& insertions, + const string& proto_name, + const string& message_name); void ReadDescriptorSet(const string& filename, FileDescriptorSet* descriptor_set); @@ -150,6 +153,9 @@ class CommandLineInterfaceTest : public testing::Test { // The object we are testing. CommandLineInterface cli_; + // Was DisallowPlugins() called? + bool disallow_plugins_; + // We create a directory within TestTempDir() in order to add extra // protection against accidentally deleting user files (since we recursively // delete this directory during the test). This is the full path of that @@ -166,40 +172,6 @@ class CommandLineInterfaceTest : public testing::Test { vector mock_generators_to_delete_; }; -// A mock CodeGenerator which outputs information about the context in which -// it was called, which can then be checked. Output is written to a filename -// constructed by concatenating the filename_prefix (given to the constructor) -// with the proto file name, separated by a '.'. -class CommandLineInterfaceTest::MockCodeGenerator : public CodeGenerator { - public: - // Create a MockCodeGenerator whose Generate() method returns true. - MockCodeGenerator(const string& name, const string& filename_prefix); - - // Create a MockCodeGenerator whose Generate() method returns false - // and sets the error string to the given string. - MockCodeGenerator(const string& name, const string& filename_prefix, - const string& error); - - ~MockCodeGenerator(); - - void set_expect_write_error(bool value) { - expect_write_error_ = value; - } - - // implements CodeGenerator ---------------------------------------- - bool Generate(const FileDescriptor* file, - const string& parameter, - OutputDirectory* output_directory, - string* error) const; - - private: - string name_; - string filename_prefix_; - bool return_error_; - string error_; - bool expect_write_error_; -}; - class CommandLineInterfaceTest::NullCodeGenerator : public CodeGenerator { public: NullCodeGenerator() : called_(false) {} @@ -237,6 +209,22 @@ void CommandLineInterfaceTest::SetUp() { // Create the temp directory. GOOGLE_CHECK(File::CreateDir(temp_directory_.c_str(), DEFAULT_FILE_MODE)); + + // Register generators. + CodeGenerator* generator = new MockCodeGenerator("test_generator"); + mock_generators_to_delete_.push_back(generator); + cli_.RegisterGenerator("--test_out", generator, "Test output."); + cli_.RegisterGenerator("-t", generator, "Test output."); + + generator = new MockCodeGenerator("alt_generator"); + mock_generators_to_delete_.push_back(generator); + cli_.RegisterGenerator("--alt_out", generator, "Alt output."); + + generator = new NullCodeGenerator(); + mock_generators_to_delete_.push_back(generator); + cli_.RegisterGenerator("--null_out", generator, "Null output."); + + disallow_plugins_ = false; } void CommandLineInterfaceTest::TearDown() { @@ -254,6 +242,11 @@ void CommandLineInterfaceTest::Run(const string& command) { vector args; SplitStringUsing(command, " ", &args); + if (!disallow_plugins_) { + cli_.AllowPlugins("prefix-"); + args.push_back("--plugin=prefix-gen-plug=test_plugin"); + } + scoped_array argv(new const char*[args.size()]); for (int i = 0; i < args.size(); i++) { @@ -270,44 +263,6 @@ void CommandLineInterfaceTest::Run(const string& command) { // ------------------------------------------------------------------- -CommandLineInterfaceTest::MockCodeGenerator* -CommandLineInterfaceTest::RegisterGenerator( - const string& generator_name, - const string& flag_name, - const string& filename, - const string& help_text) { - MockCodeGenerator* generator = - new MockCodeGenerator(generator_name, filename); - mock_generators_to_delete_.push_back(generator); - - cli_.RegisterGenerator(flag_name, generator, help_text); - return generator; -} - -CommandLineInterfaceTest::MockCodeGenerator* -CommandLineInterfaceTest::RegisterErrorGenerator( - const string& generator_name, - const string& error_text, - const string& flag_name, - const string& filename_prefix, - const string& help_text) { - MockCodeGenerator* generator = - new MockCodeGenerator(generator_name, filename_prefix, error_text); - mock_generators_to_delete_.push_back(generator); - - cli_.RegisterGenerator(flag_name, generator, help_text); - return generator; -} - -CommandLineInterfaceTest::NullCodeGenerator* -CommandLineInterfaceTest::RegisterNullGenerator( - const string& flag_name) { - NullCodeGenerator* generator = new NullCodeGenerator; - mock_generators_to_delete_.push_back(generator); - cli_.RegisterGenerator(flag_name, generator, ""); - return generator; -} - void CommandLineInterfaceTest::CreateTempFile( const string& name, const string& contents) { @@ -323,6 +278,10 @@ void CommandLineInterfaceTest::CreateTempFile( File::WriteStringToFileOrDie(contents, full_name); } +void CommandLineInterfaceTest::CreateTempDir(const string& name) { + File::RecursivelyCreateDir(temp_directory_ + "/" + name, 0777); +} + // ------------------------------------------------------------------- void CommandLineInterfaceTest::ExpectNoErrors() { @@ -348,25 +307,35 @@ bool CommandLineInterfaceTest::HasAlternateErrorSubstring( return error_text_.find(expected_substring) != string::npos; } +void CommandLineInterfaceTest::ExpectGenerated( + const string& generator_name, + const string& parameter, + const string& proto_name, + const string& message_name) { + MockCodeGenerator::ExpectGenerated( + generator_name, parameter, "", proto_name, message_name, temp_directory_); +} + void CommandLineInterfaceTest::ExpectGenerated( const string& generator_name, const string& parameter, const string& proto_name, const string& message_name, - const string& output_file_prefix) { - // Open and read the file. - string output_file = output_file_prefix + "." + proto_name; - string file_contents; - ASSERT_TRUE(File::ReadFileToString(temp_directory_ + "/" + output_file, - &file_contents)) - << "Failed to open file: " + output_file; + const string& output_directory) { + MockCodeGenerator::ExpectGenerated( + generator_name, parameter, "", proto_name, message_name, + temp_directory_ + "/" + output_directory); +} - // Check that the contents are as we expect. - string expected_contents = - generator_name + ": " + parameter + ", " + proto_name + ", " + - message_name + "\n"; - EXPECT_EQ(expected_contents, file_contents) - << "Output file did not have expected contents: " + output_file; +void CommandLineInterfaceTest::ExpectGeneratedWithInsertions( + const string& generator_name, + const string& parameter, + const string& insertions, + const string& proto_name, + const string& message_name) { + MockCodeGenerator::ExpectGenerated( + generator_name, parameter, insertions, proto_name, message_name, + temp_directory_); } void CommandLineInterfaceTest::ReadDescriptorSet( @@ -383,77 +352,52 @@ void CommandLineInterfaceTest::ReadDescriptorSet( // =================================================================== -CommandLineInterfaceTest::MockCodeGenerator::MockCodeGenerator( - const string& name, const string& filename_prefix) - : name_(name), - filename_prefix_(filename_prefix), - return_error_(false), - expect_write_error_(false) { -} - -CommandLineInterfaceTest::MockCodeGenerator::MockCodeGenerator( - const string& name, const string& filename_prefix, const string& error) - : name_(name), - filename_prefix_(filename_prefix), - return_error_(true), - error_(error), - expect_write_error_(false) { -} +TEST_F(CommandLineInterfaceTest, BasicOutput) { + // Test that the common case works. -CommandLineInterfaceTest::MockCodeGenerator::~MockCodeGenerator() {} + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); -bool CommandLineInterfaceTest::MockCodeGenerator::Generate( - const FileDescriptor* file, - const string& parameter, - OutputDirectory* output_directory, - string* error) const { - scoped_ptr output( - output_directory->Open(filename_prefix_ + "." + file->name())); - io::Printer printer(output.get(), '$'); - map vars; - vars["name"] = name_; - vars["parameter"] = parameter; - vars["proto_name"] = file->name(); - vars["message_name"] = file->message_type_count() > 0 ? - file->message_type(0)->full_name().c_str() : "(none)"; - - printer.Print(vars, "$name$: $parameter$, $proto_name$, $message_name$\n"); - - if (expect_write_error_) { - EXPECT_TRUE(printer.failed()); - } else { - EXPECT_FALSE(printer.failed()); - } + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); - *error = error_; - return !return_error_; + ExpectNoErrors(); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } -// =================================================================== +TEST_F(CommandLineInterfaceTest, BasicPlugin) { + // Test that basic plugins work. -TEST_F(CommandLineInterfaceTest, BasicOutput) { - // Test that the common case works. + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); + Run("protocol_compiler --plug_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_plugin", "", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, GeneratorAndPlugin) { + // Invoke a generator and a plugin at the same time. CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); - Run("protocol_compiler --test_out=$tmpdir " + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); + ExpectGenerated("test_plugin", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, MultipleInputs) { // Test parsing multiple input files. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -461,48 +405,68 @@ TEST_F(CommandLineInterfaceTest, MultipleInputs) { "syntax = \"proto2\";\n" "message Bar {}\n"); - Run("protocol_compiler --test_out=$tmpdir " + Run("protocol_compiler --test_out=$tmpdir --plug_out=$tmpdir " "--proto_path=$tmpdir foo.proto bar.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); - ExpectGenerated("test_generator", "", "bar.proto", "Bar", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); + ExpectGenerated("test_generator", "", "bar.proto", "Bar"); } TEST_F(CommandLineInterfaceTest, CreateDirectory) { // Test that when we output to a sub-directory, it is created. - RegisterGenerator("test_generator", "--test_out", - "bar/baz/output.test", "Test output."); - - CreateTempFile("foo.proto", + CreateTempFile("bar/baz/foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); + CreateTempDir("out"); + CreateTempDir("plugout"); - Run("protocol_compiler --test_out=$tmpdir " - "--proto_path=$tmpdir foo.proto"); + Run("protocol_compiler --test_out=$tmpdir/out --plug_out=$tmpdir/plugout " + "--proto_path=$tmpdir bar/baz/foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", - "foo.proto", "Foo", "bar/baz/output.test"); + ExpectGenerated("test_generator", "", "bar/baz/foo.proto", "Foo", "out"); + ExpectGenerated("test_plugin", "", "bar/baz/foo.proto", "Foo", "plugout"); } TEST_F(CommandLineInterfaceTest, GeneratorParameters) { // Test that generator parameters are correctly parsed from the command line. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); Run("protocol_compiler --test_out=TestParameter:$tmpdir " + "--plug_out=TestPluginParameter:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectNoErrors(); + ExpectGenerated("test_generator", "TestParameter", "foo.proto", "Foo"); + ExpectGenerated("test_plugin", "TestPluginParameter", "foo.proto", "Foo"); +} + +TEST_F(CommandLineInterfaceTest, Insert) { + // Test running a generator that inserts code into another's output. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler " + "--test_out=TestParameter:$tmpdir " + "--plug_out=TestPluginParameter:$tmpdir " + "--test_out=insert=test_generator,test_plugin:$tmpdir " + "--plug_out=insert=test_generator,test_plugin:$tmpdir " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "TestParameter", - "foo.proto", "Foo", "output.test"); + ExpectGeneratedWithInsertions( + "test_generator", "TestParameter", "test_generator,test_plugin", + "foo.proto", "Foo"); + ExpectGeneratedWithInsertions( + "test_plugin", "TestPluginParameter", "test_generator,test_plugin", + "foo.proto", "Foo"); } #if defined(_WIN32) || defined(__CYGWIN__) @@ -510,12 +474,10 @@ TEST_F(CommandLineInterfaceTest, GeneratorParameters) { TEST_F(CommandLineInterfaceTest, WindowsOutputPath) { // Test that the output path can be a Windows-style path. - NullCodeGenerator* generator = RegisterNullGenerator("--test_out"); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n"); - Run("protocol_compiler --test_out=C:\\ " + Run("protocol_compiler --null_out=C:\\ " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); @@ -526,12 +488,10 @@ TEST_F(CommandLineInterfaceTest, WindowsOutputPath) { TEST_F(CommandLineInterfaceTest, WindowsOutputPathAndParameter) { // Test that we can have a windows-style output path and a parameter. - NullCodeGenerator* generator = RegisterNullGenerator("--test_out"); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n"); - Run("protocol_compiler --test_out=bar:C:\\ " + Run("protocol_compiler --null_out=bar:C:\\ " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); @@ -543,9 +503,6 @@ TEST_F(CommandLineInterfaceTest, TrailingBackslash) { // Test that the directories can end in backslashes. Some users claim this // doesn't work on their system. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -554,7 +511,7 @@ TEST_F(CommandLineInterfaceTest, TrailingBackslash) { "--proto_path=$tmpdir\\ foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } #endif // defined(_WIN32) || defined(__CYGWIN__) @@ -562,9 +519,6 @@ TEST_F(CommandLineInterfaceTest, TrailingBackslash) { TEST_F(CommandLineInterfaceTest, PathLookup) { // Test that specifying multiple directories in the proto search path works. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("b/bar.proto", "syntax = \"proto2\";\n" "message Bar {}\n"); @@ -580,15 +534,12 @@ TEST_F(CommandLineInterfaceTest, PathLookup) { "--proto_path=$tmpdir/a --proto_path=$tmpdir/b foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, ColonDelimitedPath) { // Same as PathLookup, but we provide the proto_path in a single flag. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("b/bar.proto", "syntax = \"proto2\";\n" "message Bar {}\n"); @@ -613,15 +564,12 @@ TEST_F(CommandLineInterfaceTest, ColonDelimitedPath) { #undef PATH_SEPARATOR ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, NonRootMapping) { // Test setting up a search path mapping a directory to a non-root location. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -630,42 +578,34 @@ TEST_F(CommandLineInterfaceTest, NonRootMapping) { "--proto_path=bar=$tmpdir bar/foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "bar/foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "bar/foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, MultipleGenerators) { // Test that we can have multiple generators and use both in one invocation, // each with a different output directory. - RegisterGenerator("test_generator_1", "--test1_out", - "output1.test", "Test output 1."); - RegisterGenerator("test_generator_2", "--test2_out", - "output2.test", "Test output 2."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); // Create the "a" and "b" sub-directories. - CreateTempFile("a/dummy", ""); - CreateTempFile("b/dummy", ""); + CreateTempDir("a"); + CreateTempDir("b"); Run("protocol_compiler " - "--test1_out=$tmpdir/a " - "--test2_out=$tmpdir/b " + "--test_out=$tmpdir/a " + "--alt_out=$tmpdir/b " "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator_1", "", "foo.proto", "Foo", "a/output1.test"); - ExpectGenerated("test_generator_2", "", "foo.proto", "Foo", "b/output2.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo", "a"); + ExpectGenerated("alt_generator", "", "foo.proto", "Foo", "b"); } TEST_F(CommandLineInterfaceTest, DisallowServicesNoServices) { // Test that --disallow_services doesn't cause a problem when there are no // services. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -674,15 +614,12 @@ TEST_F(CommandLineInterfaceTest, DisallowServicesNoServices) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, DisallowServicesHasService) { // Test that --disallow_services produces an error when there are services. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n" @@ -697,9 +634,6 @@ TEST_F(CommandLineInterfaceTest, DisallowServicesHasService) { TEST_F(CommandLineInterfaceTest, AllowServicesHasService) { // Test that services work fine as long as --disallow_services is not used. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n" @@ -709,7 +643,7 @@ TEST_F(CommandLineInterfaceTest, AllowServicesHasService) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) { @@ -717,9 +651,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -728,7 +659,7 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputs) { "--proto_path=$tmpdir $tmpdir/foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, WriteDescriptorSet) { @@ -787,9 +718,6 @@ TEST_F(CommandLineInterfaceTest, WriteTransitiveDescriptorSet) { TEST_F(CommandLineInterfaceTest, ParseErrors) { // Test that parse errors are reported. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "badsyntax\n"); @@ -804,9 +732,6 @@ TEST_F(CommandLineInterfaceTest, ParseErrors) { TEST_F(CommandLineInterfaceTest, ParseErrorsMultipleFiles) { // Test that parse errors are reported from multiple files. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - // We set up files such that foo.proto actually depends on bar.proto in // two ways: Directly and through baz.proto. bar.proto's errors should // only be reported once. @@ -834,9 +759,6 @@ TEST_F(CommandLineInterfaceTest, ParseErrorsMultipleFiles) { TEST_F(CommandLineInterfaceTest, InputNotFoundError) { // Test what happens if the input file is not found. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir foo.proto"); @@ -850,9 +772,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundError) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir $tmpdir/foo.proto"); @@ -866,9 +785,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotMappedError) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -895,9 +811,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputNotFoundAndNotMappedError) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - // Create a directory called "bar" so that we can point --proto_path at it. CreateTempFile("bar/dummy", ""); @@ -914,9 +827,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputShadowedError) { SetInputsAreProtoPathRelative(false); - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo/foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -938,9 +848,6 @@ TEST_F(CommandLineInterfaceTest, CwdRelativeInputShadowedError) { TEST_F(CommandLineInterfaceTest, ProtoPathNotFoundError) { // Test what happens if the input file is not found. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir/foo foo.proto"); @@ -952,9 +859,6 @@ TEST_F(CommandLineInterfaceTest, ProtoPathNotFoundError) { TEST_F(CommandLineInterfaceTest, MissingInputError) { // Test that we get an error if no inputs are given. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir"); @@ -962,9 +866,6 @@ TEST_F(CommandLineInterfaceTest, MissingInputError) { } TEST_F(CommandLineInterfaceTest, MissingOutputError) { - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -975,35 +876,56 @@ TEST_F(CommandLineInterfaceTest, MissingOutputError) { } TEST_F(CommandLineInterfaceTest, OutputWriteError) { - MockCodeGenerator* generator = - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - generator->set_expect_write_error(true); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); + string output_file = + MockCodeGenerator::GetOutputFileName("test_generator", "foo.proto"); + // Create a directory blocking our output location. - CreateTempFile("output.test.foo.proto/foo", ""); + CreateTempDir(output_file); Run("protocol_compiler --test_out=$tmpdir " "--proto_path=$tmpdir foo.proto"); + ExpectErrorSubstring("MockCodeGenerator detected write error."); + #if defined(_WIN32) && !defined(__CYGWIN__) // Windows with MSVCRT.dll produces EPERM instead of EISDIR. - if (HasAlternateErrorSubstring("output.test.foo.proto: Permission denied")) { + if (HasAlternateErrorSubstring(output_file + ": Permission denied")) { return; } #endif - ExpectErrorSubstring("output.test.foo.proto: Is a directory"); + ExpectErrorSubstring(output_file + ": Is a directory"); } -TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) { - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); +TEST_F(CommandLineInterfaceTest, PluginOutputWriteError) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + string output_file = + MockCodeGenerator::GetOutputFileName("test_plugin", "foo.proto"); + + // Create a directory blocking our output location. + CreateTempDir(output_file); + + Run("protocol_compiler --plug_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + +#if defined(_WIN32) && !defined(__CYGWIN__) + // Windows with MSVCRT.dll produces EPERM instead of EISDIR. + if (HasAlternateErrorSubstring(output_file + ": Permission denied")) { + return; + } +#endif + + ExpectErrorSubstring(output_file + ": Is a directory"); +} +TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) { CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1011,14 +933,21 @@ TEST_F(CommandLineInterfaceTest, OutputDirectoryNotFoundError) { Run("protocol_compiler --test_out=$tmpdir/nosuchdir " "--proto_path=$tmpdir foo.proto"); - ExpectErrorSubstring("nosuchdir/: " - "No such file or directory"); + ExpectErrorSubstring("nosuchdir/: No such file or directory"); } -TEST_F(CommandLineInterfaceTest, OutputDirectoryIsFileError) { - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); +TEST_F(CommandLineInterfaceTest, PluginOutputDirectoryNotFoundError) { + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + Run("protocol_compiler --plug_out=$tmpdir/nosuchdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("nosuchdir/: No such file or directory"); +} + +TEST_F(CommandLineInterfaceTest, OutputDirectoryIsFileError) { CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1037,45 +966,109 @@ TEST_F(CommandLineInterfaceTest, OutputDirectoryIsFileError) { } TEST_F(CommandLineInterfaceTest, GeneratorError) { - RegisterErrorGenerator("error_generator", "Test error message.", - "--error_out", "output.test", "Test error output."); + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_Error {}\n"); + + Run("protocol_compiler --test_out=$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring( + "--test_out: foo.proto: Saw message type MockCodeGenerator_Error."); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginError) { + // Test a generator plugin that returns an error. CreateTempFile("foo.proto", "syntax = \"proto2\";\n" - "message Foo {}\n"); + "message MockCodeGenerator_Error {}\n"); - Run("protocol_compiler --error_out=$tmpdir " + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " "--proto_path=$tmpdir foo.proto"); - ExpectErrorSubstring("--error_out: Test error message."); + ExpectErrorSubstring( + "--plug_out: foo.proto: Saw message type MockCodeGenerator_Error."); } -TEST_F(CommandLineInterfaceTest, HelpText) { - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - RegisterErrorGenerator("error_generator", "Test error message.", - "--error_out", "output.test", "Test error output."); +TEST_F(CommandLineInterfaceTest, GeneratorPluginFail) { + // Test a generator plugin that exits with an error code. CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_Exit {}\n"); + + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("Saw message type MockCodeGenerator_Exit."); + ExpectErrorSubstring( + "--plug_out: prefix-gen-plug: Plugin failed with status code 123."); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginCrash) { + // Test a generator plugin that crashes. + + CreateTempFile("foo.proto", + "syntax = \"proto2\";\n" + "message MockCodeGenerator_Abort {}\n"); + + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--proto_path=$tmpdir foo.proto"); + + ExpectErrorSubstring("Saw message type MockCodeGenerator_Abort."); + + // Don't depend on the exact signal number. + ExpectErrorSubstring( + "--plug_out: prefix-gen-plug: Plugin killed by signal"); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginNotFound) { + // Test what happens if the plugin isn't found. + + CreateTempFile("error.proto", + "syntax = \"proto2\";\n" + "message Foo {}\n"); + + Run("protocol_compiler --badplug_out=TestParameter:$tmpdir " + "--plugin=prefix-gen-badplug=no_such_file " + "--proto_path=$tmpdir error.proto"); + + ExpectErrorSubstring( + "no_such_file: program not found or is not executable"); + + ExpectErrorSubstring( + "--badplug_out: prefix-gen-badplug: Plugin failed with status code 1."); +} + +TEST_F(CommandLineInterfaceTest, GeneratorPluginNotAllowed) { + // Test what happens if plugins aren't allowed. + + CreateTempFile("error.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); + DisallowPlugins(); + Run("protocol_compiler --plug_out=TestParameter:$tmpdir " + "--proto_path=$tmpdir error.proto"); + + ExpectErrorSubstring("Unknown flag: --plug_out"); +} + +TEST_F(CommandLineInterfaceTest, HelpText) { Run("test_exec_name --help"); ExpectErrorSubstring("Usage: test_exec_name "); ExpectErrorSubstring("--test_out=OUT_DIR"); ExpectErrorSubstring("Test output."); - ExpectErrorSubstring("--error_out=OUT_DIR"); - ExpectErrorSubstring("Test error output."); + ExpectErrorSubstring("--alt_out=OUT_DIR"); + ExpectErrorSubstring("Alt output."); } TEST_F(CommandLineInterfaceTest, GccFormatErrors) { // Test --error_format=gcc (which is the default, but we want to verify // that it can be set explicitly). - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "badsyntax\n"); @@ -1090,9 +1083,6 @@ TEST_F(CommandLineInterfaceTest, GccFormatErrors) { TEST_F(CommandLineInterfaceTest, MsvsFormatErrors) { // Test --error_format=msvs - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "badsyntax\n"); @@ -1108,9 +1098,6 @@ TEST_F(CommandLineInterfaceTest, MsvsFormatErrors) { TEST_F(CommandLineInterfaceTest, InvalidErrorFormat) { // Test --error_format=msvs - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "badsyntax\n"); @@ -1128,9 +1115,6 @@ TEST_F(CommandLineInterfaceTest, InvalidErrorFormat) { TEST_F(CommandLineInterfaceTest, ParseSingleCharacterFlag) { // Test that a single-character flag works. - RegisterGenerator("test_generator", "-t", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1139,15 +1123,12 @@ TEST_F(CommandLineInterfaceTest, ParseSingleCharacterFlag) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, ParseSpaceDelimitedValue) { // Test that separating the flag value with a space works. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1156,16 +1137,13 @@ TEST_F(CommandLineInterfaceTest, ParseSpaceDelimitedValue) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, ParseSingleCharacterSpaceDelimitedValue) { // Test that separating the flag value with a space works for // single-character flags. - RegisterGenerator("test_generator", "-t", - "output.test", "Test output."); - CreateTempFile("foo.proto", "syntax = \"proto2\";\n" "message Foo {}\n"); @@ -1174,15 +1152,12 @@ TEST_F(CommandLineInterfaceTest, ParseSingleCharacterSpaceDelimitedValue) { "--proto_path=$tmpdir foo.proto"); ExpectNoErrors(); - ExpectGenerated("test_generator", "", "foo.proto", "Foo", "output.test"); + ExpectGenerated("test_generator", "", "foo.proto", "Foo"); } TEST_F(CommandLineInterfaceTest, MissingValueError) { // Test that we get an error if a flag is missing its value. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out --proto_path=$tmpdir foo.proto"); ExpectErrorText("Missing value for flag: --test_out\n"); @@ -1192,9 +1167,6 @@ TEST_F(CommandLineInterfaceTest, MissingValueAtEndError) { // Test that we get an error if the last argument is a flag requiring a // value. - RegisterGenerator("test_generator", "--test_out", - "output.test", "Test output."); - Run("protocol_compiler --test_out"); ExpectErrorText("Missing value for flag: --test_out\n"); diff --git a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc index a7bc35bd..30b1d2bf 100644 --- a/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_bootstrap_unittest.cc @@ -123,8 +123,11 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) { Importer importer(&source_tree, &error_collector); const FileDescriptor* proto_file = importer.Import("google/protobuf/descriptor.proto"); + const FileDescriptor* plugin_proto_file = + importer.Import("google/protobuf/compiler/plugin.proto"); EXPECT_EQ("", error_collector.text_); ASSERT_TRUE(proto_file != NULL); + ASSERT_TRUE(plugin_proto_file != NULL); CppGenerator generator; MockOutputDirectory output_directory; @@ -133,11 +136,18 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) { parameter = "dllexport_decl=LIBPROTOBUF_EXPORT"; ASSERT_TRUE(generator.Generate(proto_file, parameter, &output_directory, &error)); + parameter = "dllexport_decl=LIBPROTOC_EXPORT"; + ASSERT_TRUE(generator.Generate(plugin_proto_file, parameter, + &output_directory, &error)); output_directory.ExpectFileMatches("google/protobuf/descriptor.pb.h", "google/protobuf/descriptor.pb.h"); output_directory.ExpectFileMatches("google/protobuf/descriptor.pb.cc", "google/protobuf/descriptor.pb.cc"); + output_directory.ExpectFileMatches("google/protobuf/compiler/plugin.pb.h", + "google/protobuf/compiler/plugin.pb.h"); + output_directory.ExpectFileMatches("google/protobuf/compiler/plugin.pb.cc", + "google/protobuf/compiler/plugin.pb.cc"); } } // namespace @@ -145,5 +155,4 @@ TEST(BootstrapTest, GeneratedDescriptorMatches) { } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 90e9172a..76d2b798 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -98,6 +98,7 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { "$dllexport$bool $classname$_IsValid(int value);\n" "const $classname$ $prefix$$short_name$_MIN = $prefix$$min_name$;\n" "const $classname$ $prefix$$short_name$_MAX = $prefix$$max_name$;\n" + "const int $prefix$$short_name$_ARRAYSIZE = $prefix$$short_name$_MAX + 1;\n" "\n"); if (HasDescriptorMethods(descriptor_->file())) { @@ -149,17 +150,21 @@ void EnumGenerator::GenerateSymbolImports(io::Printer* printer) { "static const $nested_name$ $nested_name$_MIN =\n" " $classname$_$nested_name$_MIN;\n" "static const $nested_name$ $nested_name$_MAX =\n" - " $classname$_$nested_name$_MAX;\n"); + " $classname$_$nested_name$_MAX;\n" + "static const int $nested_name$_ARRAYSIZE =\n" + " $classname$_$nested_name$_ARRAYSIZE;\n"); if (HasDescriptorMethods(descriptor_->file())) { printer->Print(vars, "static inline const ::google::protobuf::EnumDescriptor*\n" "$nested_name$_descriptor() {\n" " return $classname$_descriptor();\n" - "}\n" + "}\n"); + printer->Print(vars, "static inline const ::std::string& $nested_name$_Name($nested_name$ value) {\n" " return $classname$_Name(value);\n" - "}\n" + "}\n"); + printer->Print(vars, "static inline bool $nested_name$_Parse(const ::std::string& name,\n" " $nested_name$* value) {\n" " return $classname$_Parse(name, value);\n" @@ -240,7 +245,8 @@ void EnumGenerator::GenerateMethods(io::Printer* printer) { } printer->Print(vars, "const $classname$ $parent$::$nested_name$_MIN;\n" - "const $classname$ $parent$::$nested_name$_MAX;\n"); + "const $classname$ $parent$::$nested_name$_MAX;\n" + "const int $parent$::$nested_name$_ARRAYSIZE;\n"); printer->Print("#endif // _MSC_VER\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc index 7ca11c8c..91ce493a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc @@ -114,7 +114,9 @@ void EnumFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, "int value;\n" - "DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &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 (HasUnknownFields(descriptor_->file())) { @@ -170,24 +172,17 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "inline const ::google::protobuf::RepeatedField& $name$() const$deprecation$;\n" - "inline ::google::protobuf::RepeatedField* mutable_$name$()$deprecation$;\n" "inline $type$ $name$(int index) const$deprecation$;\n" "inline void set_$name$(int index, $type$ value)$deprecation$;\n" "inline void add_$name$($type$ value)$deprecation$;\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedField& $name$() const$deprecation$;\n" + "inline ::google::protobuf::RepeatedField* mutable_$name$()$deprecation$;\n"); } void RepeatedEnumFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { printer->Print(variables_, - "inline const ::google::protobuf::RepeatedField&\n" - "$classname$::$name$() const {\n" - " return $name$_;\n" - "}\n" - "inline ::google::protobuf::RepeatedField*\n" - "$classname$::mutable_$name$() {\n" - " return &$name$_;\n" - "}\n" "inline $type$ $classname$::$name$(int index) const {\n" " return static_cast< $type$ >($name$_.Get(index));\n" "}\n" @@ -199,6 +194,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { " GOOGLE_DCHECK($type$_IsValid(value));\n" " $name$_.Add(value);\n" "}\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedField&\n" + "$classname$::$name$() const {\n" + " return $name$_;\n" + "}\n" + "inline ::google::protobuf::RepeatedField*\n" + "$classname$::mutable_$name$() {\n" + " return &$name$_;\n" + "}\n"); } void RepeatedEnumFieldGenerator:: @@ -223,7 +227,33 @@ GenerateConstructorCode(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { - if (descriptor_->options().packed()) { + // Don't use ReadRepeatedPrimitive here so that the enum can be validated. + printer->Print(variables_, + "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 (HasUnknownFields(descriptor_->file())) { + printer->Print(variables_, + "} else {\n" + " mutable_unknown_fields()->AddVarint($number$, value);\n"); + } + printer->Print("}\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { + if (!descriptor_->options().packed()) { + // We use a non-inlined implementation in this case, since this path will + // rarely be executed. + printer->Print(variables_, + "DO_((::google::protobuf::internal::WireFormatLite::ReadPackedEnumNoInline(\n" + " input,\n" + " &$type$_IsValid,\n" + " this->mutable_$name$())));\n"); + } else { printer->Print(variables_, "::google::protobuf::uint32 length;\n" "DO_(input->ReadVarint32(&length));\n" @@ -231,25 +261,14 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { "input->PushLimit(length);\n" "while (input->BytesUntilLimit() > 0) {\n" " int value;\n" - " DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &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" " }\n" "}\n" "input->PopLimit(limit);\n"); - } else { - printer->Print(variables_, - "int value;\n" - "DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value));\n" - "if ($type$_IsValid(value)) {\n" - " add_$name$(static_cast< $type$ >(value));\n"); - if (HasUnknownFields(descriptor_->file())) { - printer->Print(variables_, - "} else {\n" - " mutable_unknown_fields()->AddVarint($number$, value);\n"); - } - printer->Print(variables_, - "}\n"); } } diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h index 20dd57bb..0793430c 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h @@ -83,6 +83,7 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; + void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; void GenerateByteSize(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.cc b/src/google/protobuf/compiler/cpp/cpp_extension.cc index 7208ed3a..658a7077 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.cc +++ b/src/google/protobuf/compiler/cpp/cpp_extension.cc @@ -33,6 +33,7 @@ // Sanjay Ghemawat, Jeff Dean, and others. #include +#include #include #include #include @@ -43,6 +44,18 @@ namespace protobuf { namespace compiler { namespace cpp { +namespace { + +// Returns the fully-qualified class name of the message that this field +// extends. This function is used in the Google-internal code to handle some +// legacy cases. +string ExtendeeClassName(const FieldDescriptor* descriptor) { + const Descriptor* extendee = descriptor->containing_type(); + return ClassName(extendee, true); +} + +} // anonymous namespace + ExtensionGenerator::ExtensionGenerator(const FieldDescriptor* descriptor, const string& dllexport_decl) : descriptor_(descriptor), @@ -80,7 +93,7 @@ ExtensionGenerator::~ExtensionGenerator() {} void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) { map vars; - vars["extendee" ] = ClassName(descriptor_->containing_type(), true); + vars["extendee" ] = ExtendeeClassName(descriptor_); vars["number" ] = SimpleItoa(descriptor_->number()); vars["type_traits" ] = type_traits_; vars["name" ] = descriptor_->name(); @@ -106,6 +119,7 @@ void ExtensionGenerator::GenerateDeclaration(io::Printer* printer) { " ::google::protobuf::internal::$type_traits$, $field_type$, $packed$ >\n" " $name$;\n" ); + } void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { @@ -115,7 +129,7 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { string name = scope + descriptor_->name(); map vars; - vars["extendee" ] = ClassName(descriptor_->containing_type(), true); + vars["extendee" ] = ExtendeeClassName(descriptor_); vars["type_traits" ] = type_traits_; vars["name" ] = name; vars["constant_name"] = FieldConstantName(descriptor_); @@ -154,7 +168,7 @@ void ExtensionGenerator::GenerateDefinition(io::Printer* printer) { void ExtensionGenerator::GenerateRegistration(io::Printer* printer) { map vars; - vars["extendee" ] = ClassName(descriptor_->containing_type(), true); + vars["extendee" ] = ExtendeeClassName(descriptor_); vars["number" ] = SimpleItoa(descriptor_->number()); vars["field_type" ] = SimpleItoa(static_cast(descriptor_->type())); vars["is_repeated"] = descriptor_->is_repeated() ? "true" : "false"; @@ -193,5 +207,4 @@ void ExtensionGenerator::GenerateRegistration(io::Printer* printer) { } // namespace cpp } // namespace compiler } // namespace protobuf - } // namespace google diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc index c546e964..103cac4a 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_field.cc @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -61,11 +62,24 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor, (*variables)["tag_size"] = SimpleItoa( WireFormat::TagSize(descriptor->number(), descriptor->type())); (*variables)["deprecation"] = descriptor->options().deprecated() - ? " DEPRECATED_PROTOBUF_FIELD" : ""; + ? " PROTOBUF_DEPRECATED" : ""; + } FieldGenerator::~FieldGenerator() {} +void FieldGenerator:: +GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { + // Reaching here indicates a bug. Cases are: + // - This FieldGenerator should support packing, but this method should be + // overridden. + // - This FieldGenerator doesn't support packing, and this method should + // never have been called. + GOOGLE_LOG(FATAL) << "GenerateMergeFromCodedStreamWithPacking() " + << "called on field generator that does not support packing."; + +} + FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor) : descriptor_(descriptor), field_generators_( @@ -82,7 +96,11 @@ FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_MESSAGE: return new RepeatedMessageFieldGenerator(field); case FieldDescriptor::CPPTYPE_STRING: - return new RepeatedStringFieldGenerator(field); + switch (field->options().ctype()) { + default: // RepeatedStringFieldGenerator handles unknown ctypes. + case FieldOptions::STRING: + return new RepeatedStringFieldGenerator(field); + } case FieldDescriptor::CPPTYPE_ENUM: return new RepeatedEnumFieldGenerator(field); default: @@ -93,7 +111,11 @@ FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_MESSAGE: return new MessageFieldGenerator(field); case FieldDescriptor::CPPTYPE_STRING: - return new StringFieldGenerator(field); + switch (field->options().ctype()) { + default: // StringFieldGenerator handles unknown ctypes. + case FieldOptions::STRING: + return new StringFieldGenerator(field); + } case FieldDescriptor::CPPTYPE_ENUM: return new EnumFieldGenerator(field); default: @@ -110,6 +132,7 @@ const FieldGenerator& FieldGeneratorMap::get( return *field_generators_[field->index()]; } + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h index 00ec2c7c..c303a337 100644 --- a/src/google/protobuf/compiler/cpp/cpp_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_field.h @@ -118,6 +118,11 @@ class FieldGenerator { // message's MergeFromCodedStream() method. virtual void GenerateMergeFromCodedStream(io::Printer* printer) const = 0; + // Generate lines to decode this field from a packed value, which will be + // placed inside the message's MergeFromCodedStream() method. + virtual void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) + const; + // Generate lines to serialize this field, which are placed within the // message's SerializeWithCachedSizes() method. virtual void GenerateSerializeWithCachedSizes(io::Printer* printer) const = 0; @@ -153,6 +158,7 @@ class FieldGeneratorMap { GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); }; + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index 51859bb3..80da7e40 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -93,12 +94,14 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { // Generate top of header. printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" + "// source: $filename$\n" "\n" "#ifndef PROTOBUF_$filename_identifier$__INCLUDED\n" "#define PROTOBUF_$filename_identifier$__INCLUDED\n" "\n" "#include \n" "\n", + "filename", file_->name(), "filename_identifier", filename_identifier); printer->Print( @@ -132,19 +135,23 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { if (HasDescriptorMethods(file_)) { printer->Print( "#include \n"); + } - if (file_->service_count() > 0) { - printer->Print( - "#include \n"); - } + if (HasGenericServices(file_)) { + printer->Print( + "#include \n"); } + for (int i = 0; i < file_->dependency_count(); i++) { printer->Print( "#include \"$dependency$.pb.h\"\n", "dependency", StripProto(file_->dependency(i)->name())); } + printer->Print( + "// @@protoc_insertion_point(includes)\n"); + // Open namespace. GenerateNamespaceOpeners(printer); @@ -198,7 +205,7 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { printer->Print(kThickSeparator); printer->Print("\n"); - if (HasDescriptorMethods(file_)) { + if (HasGenericServices(file_)) { // Generate service definitions. for (int i = 0; i < file_->service_count(); i++) { if (i > 0) { @@ -232,6 +239,10 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { message_generators_[i]->GenerateInlineMethods(printer); } + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); + // Close up namespace. GenerateNamespaceClosers(printer); @@ -255,10 +266,14 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { printer->Print( "\n" "} // namespace google\n} // namespace protobuf\n" - "#endif // SWIG\n" - "\n"); + "#endif // SWIG\n"); } + printer->Print( + "\n" + "// @@protoc_insertion_point(global_scope)\n" + "\n"); + printer->Print( "#endif // PROTOBUF_$filename_identifier$__INCLUDED\n", "filename_identifier", filename_identifier); @@ -285,6 +300,9 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "#include \n"); } + printer->Print( + "// @@protoc_insertion_point(includes)\n"); + GenerateNamespaceOpeners(printer); if (HasDescriptorMethods(file_)) { @@ -300,10 +318,13 @@ void FileGenerator::GenerateSource(io::Printer* printer) { "const ::google::protobuf::EnumDescriptor* $name$_descriptor_ = NULL;\n", "name", ClassName(file_->enum_type(i), false)); } - for (int i = 0; i < file_->service_count(); i++) { - printer->Print( - "const ::google::protobuf::ServiceDescriptor* $name$_descriptor_ = NULL;\n", - "name", file_->service(i)->name()); + + if (HasGenericServices(file_)) { + for (int i = 0; i < file_->service_count(); i++) { + printer->Print( + "const ::google::protobuf::ServiceDescriptor* $name$_descriptor_ = NULL;\n", + "name", file_->service(i)->name()); + } } printer->Print( @@ -329,7 +350,7 @@ void FileGenerator::GenerateSource(io::Printer* printer) { message_generators_[i]->GenerateClassMethods(printer); } - if (HasDescriptorMethods(file_)) { + if (HasGenericServices(file_)) { // Generate services. for (int i = 0; i < file_->service_count(); i++) { if (i == 0) printer->Print("\n"); @@ -344,7 +365,15 @@ void FileGenerator::GenerateSource(io::Printer* printer) { extension_generators_[i]->GenerateDefinition(printer); } + printer->Print( + "\n" + "// @@protoc_insertion_point(namespace_scope)\n"); + GenerateNamespaceClosers(printer); + + printer->Print( + "\n" + "// @@protoc_insertion_point(global_scope)\n"); } void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { @@ -397,8 +426,10 @@ void FileGenerator::GenerateBuildDescriptors(io::Printer* printer) { for (int i = 0; i < file_->enum_type_count(); i++) { enum_generators_[i]->GenerateDescriptorInitializer(printer, i); } - for (int i = 0; i < file_->service_count(); i++) { - service_generators_[i]->GenerateDescriptorInitializer(printer, i); + if (HasGenericServices(file_)) { + for (int i = 0; i < file_->service_count(); i++) { + service_generators_[i]->GenerateDescriptorInitializer(printer, i); + } } printer->Outdent(); diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc index 723a8b45..e3df88b0 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc @@ -32,6 +32,7 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include #include #include @@ -40,6 +41,7 @@ #include #include + namespace google { namespace protobuf { namespace compiler { @@ -111,6 +113,7 @@ const char kThinSeparator[] = "// -------------------------------------------------------------------\n"; string ClassName(const Descriptor* descriptor, bool qualified) { + // Find "outer", the descriptor of the top-level message in which // "descriptor" is embedded. const Descriptor* outer = descriptor; @@ -141,6 +144,12 @@ string ClassName(const EnumDescriptor* enum_descriptor, bool qualified) { } } + +string SuperClassName(const Descriptor* descriptor) { + return HasDescriptorMethods(descriptor->file()) ? + "::google::protobuf::Message" : "::google::protobuf::MessageLite"; +} + string FieldName(const FieldDescriptor* field) { string result = field->name(); LowerString(&result); @@ -166,6 +175,12 @@ string FieldConstantName(const FieldDescriptor *field) { return result; } +string FieldMessageTypeName(const FieldDescriptor* field) { + // Note: The Google-internal version of Protocol Buffers uses this function + // as a hook point for hacks to support legacy code. + return ClassName(field->message_type(), true); +} + string StripProto(const string& filename) { if (HasSuffixString(filename, ".protodevel")) { return StripSuffixString(filename, ".protodevel"); @@ -235,17 +250,37 @@ string DefaultValue(const FieldDescriptor* field) { return "GOOGLE_LONGLONG(" + SimpleItoa(field->default_value_int64()) + ")"; case FieldDescriptor::CPPTYPE_UINT64: return "GOOGLE_ULONGLONG(" + SimpleItoa(field->default_value_uint64())+ ")"; - case FieldDescriptor::CPPTYPE_DOUBLE: - return SimpleDtoa(field->default_value_double()); + case FieldDescriptor::CPPTYPE_DOUBLE: { + double value = field->default_value_double(); + if (value == numeric_limits::infinity()) { + return "::google::protobuf::internal::Infinity()"; + } else if (value == -numeric_limits::infinity()) { + return "-::google::protobuf::internal::Infinity()"; + } else if (value != value) { + return "::google::protobuf::internal::NaN()"; + } else { + return SimpleDtoa(value); + } + } case FieldDescriptor::CPPTYPE_FLOAT: { - // If floating point value contains a period (.) or an exponent (either - // E or e), then append suffix 'f' to make it a floating-point literal. - string float_value = SimpleFtoa(field->default_value_float()); - if (float_value.find_first_of(".eE") != string::npos) { - float_value.push_back('f'); + float value = field->default_value_float(); + if (value == numeric_limits::infinity()) { + return "static_cast(::google::protobuf::internal::Infinity())"; + } else if (value == -numeric_limits::infinity()) { + return "static_cast(-::google::protobuf::internal::Infinity())"; + } else if (value != value) { + return "static_cast(::google::protobuf::internal::NaN())"; + } else { + string float_value = SimpleFtoa(value); + // If floating point value contains a period (.) or an exponent + // (either E or e), then append suffix 'f' to make it a float + // literal. + if (float_value.find_first_of(".eE") != string::npos) { + float_value.push_back('f'); + } + return float_value; } - return float_value; } case FieldDescriptor::CPPTYPE_BOOL: return field->default_value_bool() ? "true" : "false"; @@ -259,7 +294,7 @@ string DefaultValue(const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_STRING: return "\"" + CEscape(field->default_value_string()) + "\""; case FieldDescriptor::CPPTYPE_MESSAGE: - return ClassName(field->message_type(), true) + "::default_instance()"; + return FieldMessageTypeName(field) + "::default_instance()"; } // Can't actually get here; make compiler happy. (We could add a default // case above but then we wouldn't get the nice compiler warning when a diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h index 83e12501..f99b5fe8 100644 --- a/src/google/protobuf/compiler/cpp/cpp_helpers.h +++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h @@ -60,6 +60,8 @@ extern const char kThinSeparator[]; string ClassName(const Descriptor* descriptor, bool qualified); string ClassName(const EnumDescriptor* enum_descriptor, bool qualified); +string SuperClassName(const Descriptor* descriptor); + // Get the (unqualified) name that should be used for this field in C++ code. // The name is coerced to lower-case to emulate proto1 behavior. People // should be using lowercase-with-underscores style for proto field names @@ -77,6 +79,10 @@ inline const Descriptor* FieldScope(const FieldDescriptor* field) { field->extension_scope() : field->containing_type(); } +// Returns the fully-qualified type name field->message_type(). Usually this +// is just ClassName(field->message_type(), true); +string FieldMessageTypeName(const FieldDescriptor* field); + // Strips ".proto" or ".protodevel" from the end of a filename. string StripProto(const string& filename); @@ -107,33 +113,41 @@ string GlobalAssignDescriptorsName(const string& filename); string GlobalShutdownFileName(const string& filename); // Do message classes in this file keep track of unknown fields? -inline const bool HasUnknownFields(const FileDescriptor *file) { +inline bool HasUnknownFields(const FileDescriptor *file) { return file->options().optimize_for() != FileOptions::LITE_RUNTIME; } // Does this file have generated parsing, serialization, and other // standard methods for which reflection-based fallback implementations exist? -inline const bool HasGeneratedMethods(const FileDescriptor *file) { +inline bool HasGeneratedMethods(const FileDescriptor *file) { return file->options().optimize_for() != FileOptions::CODE_SIZE; } // Do message classes in this file have descriptor and refelction methods? -inline const bool HasDescriptorMethods(const FileDescriptor *file) { +inline bool HasDescriptorMethods(const FileDescriptor *file) { return file->options().optimize_for() != FileOptions::LITE_RUNTIME; } +// Should we generate generic services for this file? +inline bool HasGenericServices(const FileDescriptor *file) { + return file->service_count() > 0 && + file->options().optimize_for() != FileOptions::LITE_RUNTIME && + file->options().cc_generic_services(); +} + // Should string fields in this file verify that their contents are UTF-8? -inline const bool HasUtf8Verification(const FileDescriptor* file) { +inline bool HasUtf8Verification(const FileDescriptor* file) { return file->options().optimize_for() != FileOptions::LITE_RUNTIME; } // Should we generate a separate, super-optimized code path for serializing to // flat arrays? We don't do this in Lite mode because we'd rather reduce code // size. -inline const bool HasFastArraySerialization(const FileDescriptor* file) { +inline bool HasFastArraySerialization(const FileDescriptor* file) { return file->options().optimize_for() == FileOptions::SPEED; } + } // 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 eb836418..cbdcce8f 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -308,11 +308,10 @@ GenerateClassDefinition(io::Printer* printer) { } else { vars["dllexport"] = dllexport_decl_ + " "; } - vars["superclass"] = HasDescriptorMethods(descriptor_->file()) ? - "Message" : "MessageLite"; + vars["superclass"] = SuperClassName(descriptor_); printer->Print(vars, - "class $dllexport$$classname$ : public ::google::protobuf::$superclass$ {\n" + "class $dllexport$$classname$ : public $superclass$ {\n" " public:\n"); printer->Indent(); @@ -349,6 +348,10 @@ GenerateClassDefinition(io::Printer* printer) { printer->Print(vars, "static const $classname$& default_instance();\n" + "\n"); + + + printer->Print(vars, "void Swap($classname$* other);\n" "\n" "// implements Message ----------------------------------------------\n" @@ -387,7 +390,7 @@ GenerateClassDefinition(io::Printer* printer) { "private:\n" "void SharedCtor();\n" "void SharedDtor();\n" - "void SetCachedSize(int size) const { _cached_size_ = size; }\n" + "void SetCachedSize(int size) const;\n" "public:\n" "\n"); @@ -436,6 +439,11 @@ GenerateClassDefinition(io::Printer* printer) { extension_generators_[i]->GenerateDeclaration(printer); } + + printer->Print( + "// @@protoc_insertion_point(class_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + // Generate private members for fields. printer->Outdent(); printer->Print(" private:\n"); @@ -623,6 +631,7 @@ GenerateDefaultInstanceAllocator(io::Printer* printer) { for (int i = 0; i < descriptor_->nested_type_count(); i++) { nested_generators_[i]->GenerateDefaultInstanceAllocator(printer); } + } void MessageGenerator:: @@ -751,6 +760,7 @@ GenerateClassMethods(io::Printer* printer) { "classname", classname_, "type_name", descriptor_->full_name()); } + } void MessageGenerator:: @@ -833,9 +843,8 @@ GenerateSharedDestructorCode(io::Printer* printer) { void MessageGenerator:: GenerateStructors(io::Printer* printer) { - string superclass = HasDescriptorMethods(descriptor_->file()) ? - "Message" : "MessageLite"; - + string superclass = SuperClassName(descriptor_); + // Generate the default constructor. printer->Print( "$classname$::$classname$()\n" @@ -864,7 +873,7 @@ GenerateStructors(io::Printer* printer) { printer->Print( " $name$_ = const_cast< $type$*>(&$type$::default_instance());\n", "name", FieldName(field), - "type", ClassName(field->message_type(), true)); + "type", FieldMessageTypeName(field)); } } printer->Print( @@ -896,6 +905,15 @@ GenerateStructors(io::Printer* printer) { // Generate the shared destructor code. GenerateSharedDestructorCode(printer); + // Generate SetCachedSize. + printer->Print( + "void $classname$::SetCachedSize(int size) const {\n" + " GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" + " _cached_size_ = size;\n" + " GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" + "}\n", + "classname", classname_); + // Only generate this member if it's not disabled. if (HasDescriptorMethods(descriptor_->file()) && !descriptor_->options().no_standard_descriptor_accessor()) { @@ -924,6 +942,7 @@ GenerateStructors(io::Printer* printer) { "classname", classname_, "adddescriptorsname", GlobalAddDescriptorsName(descriptor_->file()->name())); + } void MessageGenerator:: @@ -1237,12 +1256,15 @@ GenerateMergeFromCodedStream(io::Printer* printer) { PrintFieldComment(printer, field); printer->Print( - "case $number$: {\n" - " if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) !=\n" - " ::google::protobuf::internal::WireFormatLite::WIRETYPE_$wiretype$) {\n" - " goto handle_uninterpreted;\n" - " }\n", - "number", SimpleItoa(field->number()), + "case $number$: {\n", + "number", SimpleItoa(field->number())); + printer->Indent(); + const FieldGenerator& field_generator = field_generators_.get(field); + + // Emit code to parse the common, expected case. + printer->Print( + "if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) ==\n" + " ::google::protobuf::internal::WireFormatLite::WIRETYPE_$wiretype$) {\n", "wiretype", kWireTypeNames[WireFormat::WireTypeForField(field)]); if (i > 0 || (field->is_repeated() && !field->options().packed())) { @@ -1252,8 +1274,38 @@ GenerateMergeFromCodedStream(io::Printer* printer) { } printer->Indent(); + if (field->options().packed()) { + field_generator.GenerateMergeFromCodedStreamWithPacking(printer); + } else { + field_generator.GenerateMergeFromCodedStream(printer); + } + printer->Outdent(); - field_generators_.get(field).GenerateMergeFromCodedStream(printer); + // Emit code to parse unexpectedly packed or unpacked values. + if (field->is_packable() && field->options().packed()) { + printer->Print( + "} else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag)\n" + " == ::google::protobuf::internal::WireFormatLite::\n" + " WIRETYPE_$wiretype$) {\n", + "wiretype", + kWireTypeNames[WireFormat::WireTypeForFieldType(field->type())]); + printer->Indent(); + field_generator.GenerateMergeFromCodedStream(printer); + printer->Outdent(); + } else if (field->is_packable() && !field->options().packed()) { + printer->Print( + "} else if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag)\n" + " == ::google::protobuf::internal::WireFormatLite::\n" + " WIRETYPE_LENGTH_DELIMITED) {\n"); + printer->Indent(); + field_generator.GenerateMergeFromCodedStreamWithPacking(printer); + printer->Outdent(); + } + + printer->Print( + "} else {\n" + " goto handle_uninterpreted;\n" + "}\n"); // switch() is slow since it can't be predicted well. Insert some if()s // here that attempt to predict the next tag. @@ -1434,18 +1486,6 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) { "classname", classname_); printer->Indent(); - if (HasFastArraySerialization(descriptor_->file())) { - printer->Print( - "::google::protobuf::uint8* raw_buffer = " - "output->GetDirectBufferForNBytesAndAdvance(_cached_size_);\n" - "if (raw_buffer != NULL) {\n" - " $classname$::SerializeWithCachedSizesToArray(raw_buffer);\n" - " return;\n" - "}\n" - "\n", - "classname", classname_); - } - GenerateSerializeWithCachedSizesBody(printer, false); printer->Outdent(); @@ -1555,7 +1595,9 @@ GenerateByteSize(io::Printer* printer) { " ComputeUnknownMessageSetItemsSize(unknown_fields());\n"); } printer->Print( + " GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" " _cached_size_ = total_size;\n" + " GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" " return total_size;\n" "}\n"); return; @@ -1647,7 +1689,9 @@ GenerateByteSize(io::Printer* printer) { // exact same value, it works on all common processors. In a future version // of C++, _cached_size_ should be made into an atomic. printer->Print( + "GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN();\n" "_cached_size_ = total_size;\n" + "GOOGLE_SAFE_CONCURRENT_WRITES_END();\n" "return total_size;\n"); printer->Outdent(); @@ -1719,6 +1763,7 @@ GenerateIsInitialized(io::Printer* printer) { "}\n"); } + } // namespace cpp } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h index f1c57141..04778f6d 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.h +++ b/src/google/protobuf/compiler/cpp/cpp_message.h @@ -150,6 +150,7 @@ class MessageGenerator { io::Printer* printer, const Descriptor::ExtensionRange* range, bool unbounded); + const Descriptor* descriptor_; string classname_; string dllexport_decl_; diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc index 059fba6e..c04bdc66 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc @@ -47,7 +47,11 @@ namespace { void SetMessageVariables(const FieldDescriptor* descriptor, map* variables) { SetCommonFieldVariables(descriptor, variables); - (*variables)["type"] = ClassName(descriptor->message_type(), true); + (*variables)["type"] = FieldMessageTypeName(descriptor); + (*variables)["stream_writer"] = (*variables)["declared_type"] + + (HasFastArraySerialization(descriptor->message_type()->file()) ? + "MaybeToArray" : + ""); } } // namespace @@ -125,7 +129,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { void MessageFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, - "::google::protobuf::internal::WireFormatLite::Write$declared_type$NoVirtual(\n" + "::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n" " $number$, this->$name$(), output);\n"); } @@ -164,26 +168,19 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedMessageFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "inline const ::google::protobuf::RepeatedPtrField< $type$ >& $name$() const" - "$deprecation$;\n" - "inline ::google::protobuf::RepeatedPtrField< $type$ >* mutable_$name$()" - "$deprecation$;\n" "inline const $type$& $name$(int index) const$deprecation$;\n" "inline $type$* mutable_$name$(int index)$deprecation$;\n" "inline $type$* add_$name$()$deprecation$;\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + " $name$() const$deprecation$;\n" + "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" + " mutable_$name$()$deprecation$;\n"); } void RepeatedMessageFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { printer->Print(variables_, - "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" - "$classname$::$name$() const {\n" - " return $name$_;\n" - "}\n" - "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" - "$classname$::mutable_$name$() {\n" - " return &$name$_;\n" - "}\n" "inline const $type$& $classname$::$name$(int index) const {\n" " return $name$_.Get(index);\n" "}\n" @@ -193,6 +190,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "inline $type$* $classname$::add_$name$() {\n" " return $name$_.Add();\n" "}\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedPtrField< $type$ >&\n" + "$classname$::$name$() const {\n" + " return $name$_;\n" + "}\n" + "inline ::google::protobuf::RepeatedPtrField< $type$ >*\n" + "$classname$::mutable_$name$() {\n" + " return &$name$_;\n" + "}\n"); } void RepeatedMessageFieldGenerator:: @@ -232,7 +238,7 @@ void RepeatedMessageFieldGenerator:: GenerateSerializeWithCachedSizes(io::Printer* printer) const { printer->Print(variables_, "for (int i = 0; i < this->$name$_size(); i++) {\n" - " ::google::protobuf::internal::WireFormatLite::Write$declared_type$NoVirtual(\n" + " ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n" " $number$, this->$name$(i), output);\n" "}\n"); } diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc index 81f5ce07..a69c48b5 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc @@ -84,10 +84,14 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, SetCommonFieldVariables(descriptor, variables); (*variables)["type"] = PrimitiveTypeName(descriptor->cpp_type()); (*variables)["default"] = DefaultValue(descriptor); + (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); int fixed_size = FixedSize(descriptor->type()); if (fixed_size != -1) { (*variables)["fixed_size"] = SimpleItoa(fixed_size); } + (*variables)["wire_format_field_type"] = + "::google::protobuf::internal::WireFormatLite::" + FieldDescriptorProto_Type_Name( + static_cast(descriptor->type())); } } // namespace @@ -149,8 +153,9 @@ GenerateConstructorCode(io::Printer* printer) const { void PrimitiveFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { printer->Print(variables_, - "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" - " input, &$name$_));\n" + "DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive<\n" + " $type$, $wire_format_field_type$>(\n" + " input, &$name$_)));\n" "_set_bit($index$);\n"); } @@ -188,6 +193,14 @@ RepeatedPrimitiveFieldGenerator:: RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor) : descriptor_(descriptor) { SetPrimitiveVariables(descriptor, &variables_); + + if (descriptor->options().packed()) { + variables_["packed_reader"] = "ReadPackedPrimitive"; + variables_["repeated_reader"] = "ReadRepeatedPrimitiveNoInline"; + } else { + variables_["packed_reader"] = "ReadPackedPrimitiveNoInline"; + variables_["repeated_reader"] = "ReadRepeatedPrimitive"; + } } RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} @@ -205,25 +218,19 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { printer->Print(variables_, - "inline const ::google::protobuf::RepeatedField< $type$ >& $name$() const\n" - " $deprecation$;\n" - "inline ::google::protobuf::RepeatedField< $type$ >* mutable_$name$()$deprecation$;\n" "inline $type$ $name$(int index) const$deprecation$;\n" "inline void set_$name$(int index, $type$ value)$deprecation$;\n" "inline void add_$name$($type$ value)$deprecation$;\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedField< $type$ >&\n" + " $name$() const$deprecation$;\n" + "inline ::google::protobuf::RepeatedField< $type$ >*\n" + " mutable_$name$()$deprecation$;\n"); } void RepeatedPrimitiveFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { printer->Print(variables_, - "inline const ::google::protobuf::RepeatedField< $type$ >&\n" - "$classname$::$name$() const {\n" - " return $name$_;\n" - "}\n" - "inline ::google::protobuf::RepeatedField< $type$ >*\n" - "$classname$::mutable_$name$() {\n" - " return &$name$_;\n" - "}\n" "inline $type$ $classname$::$name$(int index) const {\n" " return $name$_.Get(index);\n" "}\n" @@ -233,6 +240,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "inline void $classname$::add_$name$($type$ value) {\n" " $name$_.Add(value);\n" "}\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedField< $type$ >&\n" + "$classname$::$name$() const {\n" + " return $name$_;\n" + "}\n" + "inline ::google::protobuf::RepeatedField< $type$ >*\n" + "$classname$::mutable_$name$() {\n" + " return &$name$_;\n" + "}\n"); } void RepeatedPrimitiveFieldGenerator:: @@ -257,30 +273,18 @@ GenerateConstructorCode(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateMergeFromCodedStream(io::Printer* printer) const { - if (descriptor_->options().packed()) { - printer->Print("{\n"); - printer->Indent(); - printer->Print(variables_, - "::google::protobuf::uint32 length;\n" - "DO_(input->ReadVarint32(&length));\n" - "::google::protobuf::io::CodedInputStream::Limit limit =\n" - " input->PushLimit(length);\n" - "while (input->BytesUntilLimit() > 0) {\n" - " $type$ value;\n" - " DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" - " input, &value));\n" - " add_$name$(value);\n" - "}\n" - "input->PopLimit(limit);\n"); - printer->Outdent(); - printer->Print("}\n"); - } else { - printer->Print(variables_, - "$type$ value;\n" - "DO_(::google::protobuf::internal::WireFormatLite::Read$declared_type$(\n" - " input, &value));\n" - "add_$name$(value);\n"); - } + printer->Print(variables_, + "DO_((::google::protobuf::internal::WireFormatLite::$repeated_reader$<\n" + " $type$, $wire_format_field_type$>(\n" + " $tag_size$, $tag$, input, this->mutable_$name$())));\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const { + printer->Print(variables_, + "DO_((::google::protobuf::internal::WireFormatLite::$packed_reader$<\n" + " $type$, $wire_format_field_type$>(\n" + " input, this->mutable_$name$())));\n"); } void RepeatedPrimitiveFieldGenerator:: diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h index 6b96614c..8fcd74ae 100644 --- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h +++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h @@ -83,6 +83,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { void GenerateSwappingCode(io::Printer* printer) const; void GenerateConstructorCode(io::Printer* printer) const; void GenerateMergeFromCodedStream(io::Printer* printer) const; + void GenerateMergeFromCodedStreamWithPacking(io::Printer* printer) const; void GenerateSerializeWithCachedSizes(io::Printer* printer) const; void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const; void GenerateByteSize(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc index 72258e89..ea6809a9 100644 --- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc +++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc @@ -91,7 +91,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const { // files that applied the ctype. The field can still be accessed via the // reflection interface since the reflection interface is independent of // the string's underlying representation. - if (descriptor_->options().has_ctype()) { + if (descriptor_->options().ctype() != FieldOptions::STRING) { printer->Outdent(); printer->Print( " private:\n" @@ -107,7 +107,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const { "$deprecation$;\n" "inline ::std::string* mutable_$name$()$deprecation$;\n"); - if (descriptor_->options().has_ctype()) { + if (descriptor_->options().ctype() != FieldOptions::STRING) { printer->Outdent(); printer->Print(" public:\n"); printer->Indent(); @@ -278,7 +278,7 @@ GeneratePrivateMembers(io::Printer* printer) const { void RepeatedStringFieldGenerator:: GenerateAccessorDeclarations(io::Printer* printer) const { // See comment above about unknown ctypes. - if (descriptor_->options().has_ctype()) { + if (descriptor_->options().ctype() != FieldOptions::STRING) { printer->Outdent(); printer->Print( " private:\n" @@ -287,10 +287,6 @@ GenerateAccessorDeclarations(io::Printer* printer) const { } printer->Print(variables_, - "inline const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const" - "$deprecation$;\n" - "inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()" - "$deprecation$;\n" "inline const ::std::string& $name$(int index) const$deprecation$;\n" "inline ::std::string* mutable_$name$(int index)$deprecation$;\n" "inline void set_$name$(int index, const ::std::string& value)$deprecation$;\n" @@ -304,7 +300,13 @@ GenerateAccessorDeclarations(io::Printer* printer) const { "inline void add_$name$(const $pointer_type$* value, size_t size)" "$deprecation$;\n"); - if (descriptor_->options().has_ctype()) { + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedPtrField< ::std::string>& $name$() const" + "$deprecation$;\n" + "inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_$name$()" + "$deprecation$;\n"); + + if (descriptor_->options().ctype() != FieldOptions::STRING) { printer->Outdent(); printer->Print(" public:\n"); printer->Indent(); @@ -314,14 +316,6 @@ GenerateAccessorDeclarations(io::Printer* printer) const { void RepeatedStringFieldGenerator:: GenerateInlineAccessorDefinitions(io::Printer* printer) const { printer->Print(variables_, - "inline const ::google::protobuf::RepeatedPtrField< ::std::string>&\n" - "$classname$::$name$() const {\n" - " return $name$_;\n" - "}\n" - "inline ::google::protobuf::RepeatedPtrField< ::std::string>*\n" - "$classname$::mutable_$name$() {\n" - " return &$name$_;\n" - "}\n" "inline const ::std::string& $classname$::$name$(int index) const {\n" " return $name$_.Get(index);\n" "}\n" @@ -353,6 +347,15 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const { "$classname$::add_$name$(const $pointer_type$* value, size_t size) {\n" " $name$_.Add()->assign(reinterpret_cast(value), size);\n" "}\n"); + printer->Print(variables_, + "inline const ::google::protobuf::RepeatedPtrField< ::std::string>&\n" + "$classname$::$name$() const {\n" + " return $name$_;\n" + "}\n" + "inline ::google::protobuf::RepeatedPtrField< ::std::string>*\n" + "$classname$::mutable_$name$() {\n" + " return &$name$_;\n" + "}\n"); } void RepeatedStringFieldGenerator:: diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc index d7575c05..a7e852de 100644 --- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc +++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -154,6 +155,16 @@ TEST(GeneratedMessageTest, FloatingPointDefaults) { EXPECT_EQ(-1.5f, extreme_default.negative_float()); EXPECT_EQ(2.0e8f, extreme_default.large_float()); EXPECT_EQ(-8e-28f, extreme_default.small_negative_float()); + EXPECT_EQ(numeric_limits::infinity(), + extreme_default.inf_double()); + EXPECT_EQ(-numeric_limits::infinity(), + extreme_default.neg_inf_double()); + EXPECT_TRUE(extreme_default.nan_double() != extreme_default.nan_double()); + EXPECT_EQ(numeric_limits::infinity(), + extreme_default.inf_float()); + EXPECT_EQ(-numeric_limits::infinity(), + extreme_default.neg_inf_float()); + EXPECT_TRUE(extreme_default.nan_float() != extreme_default.nan_float()); } TEST(GeneratedMessageTest, Accessors) { @@ -779,22 +790,39 @@ TEST(GeneratedEnumTest, IsValidValue) { } TEST(GeneratedEnumTest, MinAndMax) { - EXPECT_EQ(unittest::TestAllTypes::FOO,unittest::TestAllTypes::NestedEnum_MIN); - EXPECT_EQ(unittest::TestAllTypes::BAZ,unittest::TestAllTypes::NestedEnum_MAX); + EXPECT_EQ(unittest::TestAllTypes::FOO, + unittest::TestAllTypes::NestedEnum_MIN); + EXPECT_EQ(unittest::TestAllTypes::BAZ, + unittest::TestAllTypes::NestedEnum_MAX); + EXPECT_EQ(4, unittest::TestAllTypes::NestedEnum_ARRAYSIZE); EXPECT_EQ(unittest::FOREIGN_FOO, unittest::ForeignEnum_MIN); EXPECT_EQ(unittest::FOREIGN_BAZ, unittest::ForeignEnum_MAX); + EXPECT_EQ(7, unittest::ForeignEnum_ARRAYSIZE); EXPECT_EQ(1, unittest::TestEnumWithDupValue_MIN); EXPECT_EQ(3, unittest::TestEnumWithDupValue_MAX); + EXPECT_EQ(4, unittest::TestEnumWithDupValue_ARRAYSIZE); EXPECT_EQ(unittest::SPARSE_E, unittest::TestSparseEnum_MIN); EXPECT_EQ(unittest::SPARSE_C, unittest::TestSparseEnum_MAX); + EXPECT_EQ(12589235, unittest::TestSparseEnum_ARRAYSIZE); - // Make sure we can use _MIN and _MAX as switch cases. - switch(unittest::SPARSE_A) { + // Make sure we can take the address of _MIN, _MAX and _ARRAYSIZE. + void* nullptr = 0; // NULL may be integer-type, not pointer-type. + EXPECT_NE(nullptr, &unittest::TestAllTypes::NestedEnum_MIN); + EXPECT_NE(nullptr, &unittest::TestAllTypes::NestedEnum_MAX); + EXPECT_NE(nullptr, &unittest::TestAllTypes::NestedEnum_ARRAYSIZE); + + EXPECT_NE(nullptr, &unittest::ForeignEnum_MIN); + EXPECT_NE(nullptr, &unittest::ForeignEnum_MAX); + EXPECT_NE(nullptr, &unittest::ForeignEnum_ARRAYSIZE); + + // Make sure we can use _MIN, _MAX and _ARRAYSIZE as switch cases. + switch (unittest::SPARSE_A) { case unittest::TestSparseEnum_MIN: case unittest::TestSparseEnum_MAX: + case unittest::TestSparseEnum_ARRAYSIZE: break; default: break; @@ -1136,6 +1164,43 @@ TEST_F(GeneratedServiceTest, NotImplemented) { EXPECT_TRUE(controller.called_); } +} // namespace cpp_unittest +} // namespace cpp +} // namespace compiler + +namespace no_generic_services_test { + // Verify that no class called "TestService" was defined in + // unittest_no_generic_services.pb.h by defining a different type by the same + // name. If such a service was generated, this will not compile. + struct TestService { + int i; + }; +} + +namespace compiler { +namespace cpp { +namespace cpp_unittest { + +TEST_F(GeneratedServiceTest, NoGenericServices) { + // Verify that non-services in unittest_no_generic_services.proto were + // generated. + no_generic_services_test::TestMessage message; + message.set_a(1); + message.SetExtension(no_generic_services_test::test_extension, 123); + no_generic_services_test::TestEnum e = no_generic_services_test::FOO; + EXPECT_EQ(e, 1); + + // Verify that a ServiceDescriptor is generated for the service even if the + // class itself is not. + const FileDescriptor* file = + no_generic_services_test::TestMessage::descriptor()->file(); + + ASSERT_EQ(1, file->service_count()); + EXPECT_EQ("TestService", file->service(0)->name()); + ASSERT_EQ(1, file->service(0)->method_count()); + EXPECT_EQ("Foo", file->service(0)->method(0)->name()); +} + #endif // !PROTOBUF_TEST_NO_DESCRIPTORS // =================================================================== diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc index 8ade50c9..85e39f53 100644 --- a/src/google/protobuf/compiler/java/java_enum.cc +++ b/src/google/protobuf/compiler/java/java_enum.cc @@ -223,6 +223,11 @@ void EnumGenerator::Generate(io::Printer* printer) { "file", ClassName(descriptor_->file())); } + printer->Print( + "\n" + "// @@protoc_insertion_point(enum_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); + printer->Outdent(); printer->Print("}\n\n"); } diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc index dc36e06e..af6b1cd2 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.cc +++ b/src/google/protobuf/compiler/java/java_enum_field.cc @@ -62,7 +62,7 @@ void SetEnumVariables(const FieldDescriptor* descriptor, (*variables)["default"] = DefaultValue(descriptor); (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); (*variables)["tag_size"] = SimpleItoa( - internal::WireFormat::TagSize(descriptor->number(), descriptor->type())); + internal::WireFormat::TagSize(descriptor->number(), GetType(descriptor))); } } // namespace @@ -81,7 +81,7 @@ void EnumFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private boolean has$capitalized_name$;\n" - "private $type$ $name$_ = $default$;\n" + "private $type$ $name$_;\n" "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n" "public $type$ get$capitalized_name$() { return $name$_; }\n"); } @@ -110,6 +110,11 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n"); } +void EnumFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $default$;\n"); +} + void EnumFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, @@ -240,6 +245,11 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n"); } +void RepeatedEnumFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + // Initialized inline. +} + void RepeatedEnumFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, @@ -262,15 +272,6 @@ GenerateBuildingCode(io::Printer* printer) const { void RepeatedEnumFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { - // If packed, set up the while loop - if (descriptor_->options().packed()) { - printer->Print(variables_, - "int length = input.readRawVarint32();\n" - "int oldLimit = input.pushLimit(length);\n" - "while(input.getBytesUntilLimit() > 0) {\n"); - printer->Indent(); - } - // Read and store the enum printer->Print(variables_, "int rawValue = input.readEnum();\n" @@ -287,13 +288,24 @@ GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, " add$capitalized_name$(value);\n" "}\n"); +} - if (descriptor_->options().packed()) { - printer->Outdent(); - printer->Print(variables_, - "}\n" - "input.popLimit(oldLimit);\n"); - } +void RepeatedEnumFieldGenerator:: +GenerateParsingCodeFromPacked(io::Printer* printer) const { + // Wrap GenerateParsingCode's contents with a while loop. + + printer->Print(variables_, + "int length = input.readRawVarint32();\n" + "int oldLimit = input.pushLimit(length);\n" + "while(input.getBytesUntilLimit() > 0) {\n"); + printer->Indent(); + + GenerateParsingCode(printer); + + printer->Outdent(); + printer->Print(variables_, + "}\n" + "input.popLimit(oldLimit);\n"); } void RepeatedEnumFieldGenerator:: diff --git a/src/google/protobuf/compiler/java/java_enum_field.h b/src/google/protobuf/compiler/java/java_enum_field.h index 63f68153..c54a0faf 100644 --- a/src/google/protobuf/compiler/java/java_enum_field.h +++ b/src/google/protobuf/compiler/java/java_enum_field.h @@ -52,6 +52,7 @@ class EnumFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; @@ -75,9 +76,11 @@ class RepeatedEnumFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; + void GenerateParsingCodeFromPacked(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/java/java_extension.cc b/src/google/protobuf/compiler/java/java_extension.cc index 4403220b..5932433f 100644 --- a/src/google/protobuf/compiler/java/java_extension.cc +++ b/src/google/protobuf/compiler/java/java_extension.cc @@ -133,7 +133,7 @@ void ExtensionGenerator::GenerateInitializationCode(io::Printer* printer) { vars["extendee"] = ClassName(descriptor_->containing_type()); vars["default"] = descriptor_->is_repeated() ? "" : DefaultValue(descriptor_); vars["number"] = SimpleItoa(descriptor_->number()); - vars["type_constant"] = TypeName(descriptor_->type()); + vars["type_constant"] = TypeName(GetType(descriptor_)); vars["packed"] = descriptor_->options().packed() ? "true" : "false"; vars["enum_map"] = "null"; vars["prototype"] = "null"; @@ -208,5 +208,4 @@ void ExtensionGenerator::GenerateRegistrationCode(io::Printer* printer) { } // namespace java } // namespace compiler } // namespace protobuf - } // namespace google diff --git a/src/google/protobuf/compiler/java/java_field.cc b/src/google/protobuf/compiler/java/java_field.cc index f9d34ad7..978c8f33 100644 --- a/src/google/protobuf/compiler/java/java_field.cc +++ b/src/google/protobuf/compiler/java/java_field.cc @@ -46,6 +46,16 @@ namespace java { FieldGenerator::~FieldGenerator() {} +void FieldGenerator::GenerateParsingCodeFromPacked(io::Printer* printer) const { + // Reaching here indicates a bug. Cases are: + // - This FieldGenerator should support packing, but this method should be + // overridden. + // - This FieldGenerator doesn't support packing, and this method should + // never have been called. + GOOGLE_LOG(FATAL) << "GenerateParsingCodeFromPacked() " + << "called on field generator that does not support packing."; +} + FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor) : descriptor_(descriptor), field_generators_( diff --git a/src/google/protobuf/compiler/java/java_field.h b/src/google/protobuf/compiler/java/java_field.h index cab463c8..f5bef7ab 100644 --- a/src/google/protobuf/compiler/java/java_field.h +++ b/src/google/protobuf/compiler/java/java_field.h @@ -57,9 +57,11 @@ class FieldGenerator { virtual void GenerateMembers(io::Printer* printer) const = 0; virtual void GenerateBuilderMembers(io::Printer* printer) const = 0; + virtual void GenerateInitializationCode(io::Printer* printer) const = 0; virtual void GenerateMergingCode(io::Printer* printer) const = 0; virtual void GenerateBuildingCode(io::Printer* printer) const = 0; virtual void GenerateParsingCode(io::Printer* printer) const = 0; + virtual void GenerateParsingCodeFromPacked(io::Printer* printer) const; virtual void GenerateSerializationCode(io::Printer* printer) const = 0; virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0; diff --git a/src/google/protobuf/compiler/java/java_file.cc b/src/google/protobuf/compiler/java/java_file.cc index 2aedde5e..7ea127c0 100644 --- a/src/google/protobuf/compiler/java/java_file.cc +++ b/src/google/protobuf/compiler/java/java_file.cc @@ -64,7 +64,7 @@ bool UsesExtensions(const Message& message) { for (int i = 0; i < fields.size(); i++) { if (fields[i]->is_extension()) return true; - if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (GetJavaType(fields[i]) == JAVATYPE_MESSAGE) { if (fields[i]->is_repeated()) { int size = reflection->FieldSize(message, fields[i]); for (int j = 0; j < size; j++) { @@ -82,6 +82,7 @@ bool UsesExtensions(const Message& message) { return false; } + } // namespace FileGenerator::FileGenerator(const FileDescriptor* file) @@ -134,7 +135,9 @@ void FileGenerator::Generate(io::Printer* printer) { // fully-qualified names in the generated source. printer->Print( "// Generated by the protocol buffer compiler. DO NOT EDIT!\n" - "\n"); + "// source: $filename$\n" + "\n", + "filename", file_->name()); if (!java_package_.empty()) { printer->Print( "package $package$;\n" @@ -178,8 +181,10 @@ void FileGenerator::Generate(io::Printer* printer) { for (int i = 0; i < file_->message_type_count(); i++) { MessageGenerator(file_->message_type(i)).Generate(printer); } - for (int i = 0; i < file_->service_count(); i++) { - ServiceGenerator(file_->service(i)).Generate(printer); + if (HasGenericServices(file_)) { + for (int i = 0; i < file_->service_count(); i++) { + ServiceGenerator(file_->service(i)).Generate(printer); + } } } @@ -228,6 +233,10 @@ void FileGenerator::Generate(io::Printer* printer) { "\n" "public static void internalForceInit() {}\n"); + printer->Print( + "\n" + "// @@protoc_insertion_point(outer_class_scope)\n"); + printer->Outdent(); printer->Print("}\n"); } @@ -245,6 +254,7 @@ void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) { // embedded raw, which is what we want. FileDescriptorProto file_proto; file_->CopyTo(&file_proto); + string file_data; file_proto.SerializeToString(&file_data); @@ -343,9 +353,11 @@ void FileGenerator::GenerateEmbeddedDescriptor(io::Printer* printer) { " new com.google.protobuf.Descriptors.FileDescriptor[] {\n"); for (int i = 0; i < file_->dependency_count(); i++) { - printer->Print( - " $dependency$.getDescriptor(),\n", - "dependency", ClassName(file_->dependency(i))); + if (ShouldIncludeDependency(file_->dependency(i))) { + printer->Print( + " $dependency$.getDescriptor(),\n", + "dependency", ClassName(file_->dependency(i))); + } } printer->Print( @@ -396,14 +408,20 @@ void FileGenerator::GenerateSiblings(const string& package_dir, file_->message_type(i), output_directory, file_list); } - for (int i = 0; i < file_->service_count(); i++) { - GenerateSibling(package_dir, java_package_, - file_->service(i), - output_directory, file_list); + if (HasGenericServices(file_)) { + for (int i = 0; i < file_->service_count(); i++) { + GenerateSibling(package_dir, java_package_, + file_->service(i), + output_directory, file_list); + } } } } +bool FileGenerator::ShouldIncludeDependency(const FileDescriptor* descriptor) { + return true; +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_file.h b/src/google/protobuf/compiler/java/java_file.h index cb82cea2..9e35d330 100644 --- a/src/google/protobuf/compiler/java/java_file.h +++ b/src/google/protobuf/compiler/java/java_file.h @@ -77,6 +77,11 @@ class FileGenerator { const string& classname() { return classname_; } private: + // Returns whether the dependency should be included in the output file. + // Always returns true for opensource, but used internally at Google to help + // improve compatibility with version 1 of protocol buffers. + bool ShouldIncludeDependency(const FileDescriptor* descriptor); + const FileDescriptor* file_; string java_package_; string classname_; diff --git a/src/google/protobuf/compiler/java/java_generator.cc b/src/google/protobuf/compiler/java/java_generator.cc index 8ed3affb..745b55ae 100644 --- a/src/google/protobuf/compiler/java/java_generator.cc +++ b/src/google/protobuf/compiler/java/java_generator.cc @@ -45,6 +45,7 @@ namespace protobuf { namespace compiler { namespace java { + JavaGenerator::JavaGenerator() {} JavaGenerator::~JavaGenerator() {} diff --git a/src/google/protobuf/compiler/java/java_helpers.cc b/src/google/protobuf/compiler/java/java_helpers.cc index dc6748e3..7ed0c3cc 100644 --- a/src/google/protobuf/compiler/java/java_helpers.cc +++ b/src/google/protobuf/compiler/java/java_helpers.cc @@ -32,6 +32,7 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include #include #include @@ -57,7 +58,7 @@ const string& FieldName(const FieldDescriptor* field) { // Groups are hacky: The name of the field is just the lower-cased name // of the group type. In Java, though, we would like to retain the original // capitalization of the type name. - if (field->type() == FieldDescriptor::TYPE_GROUP) { + if (GetType(field) == FieldDescriptor::TYPE_GROUP) { return field->message_type()->name(); } else { return field->name(); @@ -178,8 +179,12 @@ string FieldConstantName(const FieldDescriptor *field) { return name; } -JavaType GetJavaType(FieldDescriptor::Type field_type) { - switch (field_type) { +FieldDescriptor::Type GetType(const FieldDescriptor* field) { + return field->type(); +} + +JavaType GetJavaType(const FieldDescriptor* field) { + switch (GetType(field)) { case FieldDescriptor::TYPE_INT32: case FieldDescriptor::TYPE_UINT32: case FieldDescriptor::TYPE_SINT32: @@ -254,7 +259,7 @@ bool AllAscii(const string& text) { } string DefaultValue(const FieldDescriptor* field) { - // Switch on cpp_type since we need to know which default_value_* method + // Switch on CppType since we need to know which default_value_* method // of FieldDescriptor to call. switch (field->cpp_type()) { case FieldDescriptor::CPPTYPE_INT32: @@ -267,14 +272,34 @@ string DefaultValue(const FieldDescriptor* field) { case FieldDescriptor::CPPTYPE_UINT64: return SimpleItoa(static_cast(field->default_value_uint64())) + "L"; - case FieldDescriptor::CPPTYPE_DOUBLE: - return SimpleDtoa(field->default_value_double()) + "D"; - case FieldDescriptor::CPPTYPE_FLOAT: - return SimpleFtoa(field->default_value_float()) + "F"; + case FieldDescriptor::CPPTYPE_DOUBLE: { + double value = field->default_value_double(); + if (value == numeric_limits::infinity()) { + return "Double.POSITIVE_INFINITY"; + } else if (value == -numeric_limits::infinity()) { + return "Double.NEGATIVE_INFINITY"; + } else if (value != value) { + return "Double.NaN"; + } else { + return SimpleDtoa(value) + "D"; + } + } + case FieldDescriptor::CPPTYPE_FLOAT: { + float value = field->default_value_float(); + if (value == numeric_limits::infinity()) { + return "Float.POSITIVE_INFINITY"; + } else if (value == -numeric_limits::infinity()) { + return "Float.NEGATIVE_INFINITY"; + } else if (value != value) { + return "Float.NaN"; + } else { + return SimpleFtoa(value) + "F"; + } + } case FieldDescriptor::CPPTYPE_BOOL: return field->default_value_bool() ? "true" : "false"; case FieldDescriptor::CPPTYPE_STRING: - if (field->type() == FieldDescriptor::TYPE_BYTES) { + if (GetType(field) == FieldDescriptor::TYPE_BYTES) { if (field->has_default_value()) { // See comments in Internal.java for gory details. return strings::Substitute( diff --git a/src/google/protobuf/compiler/java/java_helpers.h b/src/google/protobuf/compiler/java/java_helpers.h index f1b643c3..3c8974c9 100644 --- a/src/google/protobuf/compiler/java/java_helpers.h +++ b/src/google/protobuf/compiler/java/java_helpers.h @@ -93,6 +93,11 @@ string ClassName(const FileDescriptor* descriptor); // number constant. string FieldConstantName(const FieldDescriptor *field); +// Returns the type of the FieldDescriptor. +// This does nothing interesting for the open source release, but is used for +// hacks that improve compatability with version 1 protocol buffers at Google. +FieldDescriptor::Type GetType(const FieldDescriptor* field); + enum JavaType { JAVATYPE_INT, JAVATYPE_LONG, @@ -105,11 +110,7 @@ enum JavaType { JAVATYPE_MESSAGE }; -JavaType GetJavaType(FieldDescriptor::Type field_type); - -inline JavaType GetJavaType(const FieldDescriptor* field) { - return GetJavaType(field->type()); -} +JavaType GetJavaType(const FieldDescriptor* field); // Get the fully-qualified class name for a boxed primitive type, e.g. // "java.lang.Integer" for JAVATYPE_INT. Returns NULL for enum and message @@ -145,6 +146,13 @@ inline bool HasDescriptorMethods(const FileDescriptor* descriptor) { FileOptions::LITE_RUNTIME; } +// Should we generate generic services for this file? +inline bool HasGenericServices(const FileDescriptor *file) { + return file->service_count() > 0 && + file->options().optimize_for() != FileOptions::LITE_RUNTIME && + file->options().java_generic_services(); +} + } // namespace java } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 99b57c95..1f8e209c 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -127,7 +127,7 @@ static bool HasRequiredFields( if (field->is_required()) { return true; } - if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (GetJavaType(field) == JAVATYPE_MESSAGE) { if (HasRequiredFields(field->message_type(), already_seen)) { return true; } @@ -292,9 +292,14 @@ void MessageGenerator::Generate(io::Printer* printer) { printer->Indent(); printer->Print( "// Use $classname$.newBuilder() to construct.\n" - "private $classname$() {}\n" + "private $classname$() {\n" + " initFields();\n" + "}\n" + // Used when constructing the default instance, which cannot be initialized + // immediately because it may cyclically refer to other default instances. + "private $classname$(boolean noInit) {}\n" "\n" - "private static final $classname$ defaultInstance = new $classname$();\n" + "private static final $classname$ defaultInstance;\n" "public static $classname$ getDefaultInstance() {\n" " return defaultInstance;\n" "}\n" @@ -344,6 +349,17 @@ void MessageGenerator::Generate(io::Printer* printer) { printer->Print("\n"); } + // Called by the constructor, except in the case of the default instance, + // in which case this is called by static init code later on. + printer->Print("private void initFields() {\n"); + printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GenerateInitializationCode(printer); + } + printer->Outdent(); + printer->Print("}\n"); + if (HasGeneratedMethods(descriptor_)) { GenerateIsInitialized(printer); GenerateMessageSerializationMethods(printer); @@ -352,25 +368,23 @@ void MessageGenerator::Generate(io::Printer* printer) { GenerateParseFromMethods(printer); GenerateBuilder(printer); - if (HasDescriptorMethods(descriptor_)) { - // Force the static initialization code for the file to run, since it may - // initialize static variables declared in this class. - printer->Print( - "\n" - "static {\n" - " $file$.getDescriptor();\n" - "}\n", - "file", ClassName(descriptor_->file())); - } - // Force initialization of outer class. Otherwise, nested extensions may - // not be initialized. + // not be initialized. Also carefully initialize the default instance in + // such a way that it doesn't conflict with other initialization. printer->Print( "\n" "static {\n" + " defaultInstance = new $classname$(true);\n" " $file$.internalForceInit();\n" + " defaultInstance.initFields();\n" "}\n", - "file", ClassName(descriptor_->file())); + "file", ClassName(descriptor_->file()), + "classname", descriptor_->name()); + + printer->Print( + "\n" + "// @@protoc_insertion_point(class_scope:$full_name$)\n", + "full_name", descriptor_->full_name()); printer->Outdent(); printer->Print("}\n\n"); @@ -529,14 +543,23 @@ GenerateParseFromMethods(io::Printer* printer) { "}\n" "public static $classname$ parseDelimitedFrom(java.io.InputStream input)\n" " throws java.io.IOException {\n" - " return newBuilder().mergeDelimitedFrom(input).buildParsed();\n" + " Builder builder = newBuilder();\n" + " if (builder.mergeDelimitedFrom(input)) {\n" + " return builder.buildParsed();\n" + " } else {\n" + " return null;\n" + " }\n" "}\n" "public static $classname$ parseDelimitedFrom(\n" " java.io.InputStream input,\n" " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" " throws java.io.IOException {\n" - " return newBuilder().mergeDelimitedFrom(input, extensionRegistry)\n" - " .buildParsed();\n" + " Builder builder = newBuilder();\n" + " if (builder.mergeDelimitedFrom(input, extensionRegistry)) {\n" + " return builder.buildParsed();\n" + " } else {\n" + " return null;\n" + " }\n" "}\n" "public static $classname$ parseFrom(\n" " com.google.protobuf.CodedInputStream input)\n" @@ -827,7 +850,7 @@ void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) { for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = sorted_fields[i]; uint32 tag = WireFormatLite::MakeTag(field->number(), - WireFormat::WireTypeForField(field)); + WireFormat::WireTypeForFieldType(field->type())); printer->Print( "case $tag$: {\n", @@ -840,6 +863,24 @@ void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) { printer->Print( " break;\n" "}\n"); + + if (field->is_packable()) { + // To make packed = true wire compatible, we generate parsing code from a + // packed version of this field regardless of field->options().packed(). + uint32 packed_tag = WireFormatLite::MakeTag(field->number(), + WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + printer->Print( + "case $tag$: {\n", + "tag", SimpleItoa(packed_tag)); + printer->Indent(); + + field_generators_.get(field).GenerateParsingCodeFromPacked(printer); + + printer->Outdent(); + printer->Print( + " break;\n" + "}\n"); + } } printer->Outdent(); @@ -875,7 +916,7 @@ void MessageGenerator::GenerateIsInitialized(io::Printer* printer) { // Now check that all embedded messages are initialized. for (int i = 0; i < descriptor_->field_count(); i++) { const FieldDescriptor* field = descriptor_->field(i); - if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE && + if (GetJavaType(field) == JAVATYPE_MESSAGE && HasRequiredFields(field->message_type())) { switch (field->label()) { case FieldDescriptor::LABEL_REQUIRED: diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc index bbddddde..71edc024 100644 --- a/src/google/protobuf/compiler/java/java_message_field.cc +++ b/src/google/protobuf/compiler/java/java_message_field.cc @@ -59,7 +59,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor, (*variables)["number"] = SimpleItoa(descriptor->number()); (*variables)["type"] = ClassName(descriptor->message_type()); (*variables)["group_or_message"] = - (descriptor->type() == FieldDescriptor::TYPE_GROUP) ? + (GetType(descriptor) == FieldDescriptor::TYPE_GROUP) ? "Group" : "Message"; } @@ -79,7 +79,7 @@ void MessageFieldGenerator:: GenerateMembers(io::Printer* printer) const { printer->Print(variables_, "private boolean has$capitalized_name$;\n" - "private $type$ $name$_ = $type$.getDefaultInstance();\n" + "private $type$ $name$_;\n" "public boolean has$capitalized_name$() { return has$capitalized_name$; }\n" "public $type$ get$capitalized_name$() { return $name$_; }\n"); } @@ -124,6 +124,11 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n"); } +void MessageFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + printer->Print(variables_, "$name$_ = $type$.getDefaultInstance();\n"); +} + void MessageFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, @@ -145,7 +150,7 @@ GenerateParsingCode(io::Printer* printer) const { " subBuilder.mergeFrom(get$capitalized_name$());\n" "}\n"); - if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { + if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, "input.readGroup($number$, subBuilder, extensionRegistry);\n"); } else { @@ -261,6 +266,11 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n"); } +void RepeatedMessageFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + // Initialized inline. +} + void RepeatedMessageFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, @@ -286,7 +296,7 @@ GenerateParsingCode(io::Printer* printer) const { printer->Print(variables_, "$type$.Builder subBuilder = $type$.newBuilder();\n"); - if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { + if (GetType(descriptor_) == FieldDescriptor::TYPE_GROUP) { printer->Print(variables_, "input.readGroup($number$, subBuilder, extensionRegistry);\n"); } else { diff --git a/src/google/protobuf/compiler/java/java_message_field.h b/src/google/protobuf/compiler/java/java_message_field.h index 90a90976..66bdd884 100644 --- a/src/google/protobuf/compiler/java/java_message_field.h +++ b/src/google/protobuf/compiler/java/java_message_field.h @@ -52,6 +52,7 @@ class MessageFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; @@ -75,6 +76,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc index 1fbca5a2..f6179bfa 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.cc +++ b/src/google/protobuf/compiler/java/java_primitive_field.cc @@ -93,7 +93,7 @@ bool IsReferenceType(JavaType type) { } const char* GetCapitalizedType(const FieldDescriptor* field) { - switch (field->type()) { + switch (GetType(field)) { case FieldDescriptor::TYPE_INT32 : return "Int32" ; case FieldDescriptor::TYPE_UINT32 : return "UInt32" ; case FieldDescriptor::TYPE_SINT32 : return "SInt32" ; @@ -166,7 +166,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, (*variables)["capitalized_type"] = GetCapitalizedType(descriptor); (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); (*variables)["tag_size"] = SimpleItoa( - WireFormat::TagSize(descriptor->number(), descriptor->type())); + WireFormat::TagSize(descriptor->number(), GetType(descriptor))); if (IsReferenceType(GetJavaType(descriptor))) { (*variables)["null_check"] = " if (value == null) {\n" @@ -175,7 +175,7 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor, } else { (*variables)["null_check"] = ""; } - int fixed_size = FixedSize(descriptor->type()); + int fixed_size = FixedSize(GetType(descriptor)); if (fixed_size != -1) { (*variables)["fixed_size"] = SimpleItoa(fixed_size); } @@ -218,7 +218,8 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n" "public Builder clear$capitalized_name$() {\n" " result.has$capitalized_name$ = false;\n"); - if (descriptor_->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { + JavaType type = GetJavaType(descriptor_); + if (type == JAVATYPE_STRING || type == JAVATYPE_BYTES) { // The default value is not a simple literal so we want to avoid executing // it multiple times. Instead, get the default out of the default instance. printer->Print(variables_, @@ -232,6 +233,11 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n"); } +void PrimitiveFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + // Initialized inline. +} + void PrimitiveFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, @@ -345,6 +351,11 @@ GenerateBuilderMembers(io::Printer* printer) const { "}\n"); } +void RepeatedPrimitiveFieldGenerator:: +GenerateInitializationCode(io::Printer* printer) const { + // Initialized inline. +} + void RepeatedPrimitiveFieldGenerator:: GenerateMergingCode(io::Printer* printer) const { printer->Print(variables_, @@ -367,18 +378,19 @@ GenerateBuildingCode(io::Printer* printer) const { void RepeatedPrimitiveFieldGenerator:: GenerateParsingCode(io::Printer* printer) const { - if (descriptor_->options().packed()) { - printer->Print(variables_, - "int length = input.readRawVarint32();\n" - "int limit = input.pushLimit(length);\n" - "while (input.getBytesUntilLimit() > 0) {\n" - " add$capitalized_name$(input.read$capitalized_type$());\n" - "}\n" - "input.popLimit(limit);\n"); - } else { - printer->Print(variables_, - "add$capitalized_name$(input.read$capitalized_type$());\n"); - } + printer->Print(variables_, + "add$capitalized_name$(input.read$capitalized_type$());\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateParsingCodeFromPacked(io::Printer* printer) const { + printer->Print(variables_, + "int length = input.readRawVarint32();\n" + "int limit = input.pushLimit(length);\n" + "while (input.getBytesUntilLimit() > 0) {\n" + " add$capitalized_name$(input.read$capitalized_type$());\n" + "}\n" + "input.popLimit(limit);\n"); } void RepeatedPrimitiveFieldGenerator:: @@ -407,7 +419,7 @@ GenerateSerializedSizeCode(io::Printer* printer) const { " int dataSize = 0;\n"); printer->Indent(); - if (FixedSize(descriptor_->type()) == -1) { + if (FixedSize(GetType(descriptor_)) == -1) { printer->Print(variables_, "for ($type$ element : get$capitalized_name$List()) {\n" " dataSize += com.google.protobuf.CodedOutputStream\n" diff --git a/src/google/protobuf/compiler/java/java_primitive_field.h b/src/google/protobuf/compiler/java/java_primitive_field.h index f9da0a62..4e482a05 100644 --- a/src/google/protobuf/compiler/java/java_primitive_field.h +++ b/src/google/protobuf/compiler/java/java_primitive_field.h @@ -52,6 +52,7 @@ class PrimitiveFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; @@ -75,9 +76,11 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator { // implements FieldGenerator --------------------------------------- void GenerateMembers(io::Printer* printer) const; void GenerateBuilderMembers(io::Printer* printer) const; + void GenerateInitializationCode(io::Printer* printer) const; void GenerateMergingCode(io::Printer* printer) const; void GenerateBuildingCode(io::Printer* printer) const; void GenerateParsingCode(io::Printer* printer) const; + void GenerateParsingCodeFromPacked(io::Printer* printer) const; void GenerateSerializationCode(io::Printer* printer) const; void GenerateSerializedSizeCode(io::Printer* printer) const; diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc index 0a2c0b2c..d9b0c3f9 100644 --- a/src/google/protobuf/compiler/main.cc +++ b/src/google/protobuf/compiler/main.cc @@ -39,6 +39,7 @@ int main(int argc, char* argv[]) { google::protobuf::compiler::CommandLineInterface cli; + cli.AllowPlugins("protoc-"); // Proto2 C++ google::protobuf::compiler::cpp::CppGenerator cpp_generator; diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc index 02304d6d..758f70dc 100644 --- a/src/google/protobuf/compiler/parser.cc +++ b/src/google/protobuf/compiler/parser.cc @@ -34,8 +34,9 @@ // // Recursive descent FTW. -#include #include +#include +#include #include @@ -206,6 +207,14 @@ bool Parser::ConsumeNumber(double* output, const char* error) { *output = value; input_->Next(); return true; + } else if (LookingAt("inf")) { + *output = numeric_limits::infinity(); + input_->Next(); + return true; + } else if (LookingAt("nan")) { + *output = numeric_limits::quiet_NaN(); + input_->Next(); + return true; } else { AddError(error); return false; diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc index c4f08e7f..e2262b8b 100644 --- a/src/google/protobuf/compiler/parser_unittest.cc +++ b/src/google/protobuf/compiler/parser_unittest.cc @@ -336,6 +336,9 @@ TEST_F(ParseMessageTest, FieldDefaults) { " required double foo = 1 [default= 10.5];\n" " required double foo = 1 [default=-11.5];\n" " required double foo = 1 [default= 12 ];\n" + " required double foo = 1 [default= inf ];\n" + " required double foo = 1 [default=-inf ];\n" + " required double foo = 1 [default= nan ];\n" " required string foo = 1 [default='13\\001'];\n" " required string foo = 1 [default='a' \"b\" \n \"c\"];\n" " required bytes foo = 1 [default='14\\002'];\n" @@ -367,6 +370,9 @@ TEST_F(ParseMessageTest, FieldDefaults) { " field { type:TYPE_DOUBLE default_value:\"10.5\" "ETC" }" " field { type:TYPE_DOUBLE default_value:\"-11.5\" "ETC" }" " field { type:TYPE_DOUBLE default_value:\"12\" "ETC" }" + " field { type:TYPE_DOUBLE default_value:\"inf\" "ETC" }" + " field { type:TYPE_DOUBLE default_value:\"-inf\" "ETC" }" + " field { type:TYPE_DOUBLE default_value:\"nan\" "ETC" }" " field { type:TYPE_STRING default_value:\"13\\001\" "ETC" }" " field { type:TYPE_STRING default_value:\"abc\" "ETC" }" " field { type:TYPE_BYTES default_value:\"14\\\\002\" "ETC" }" diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc index d301f015..54ab0a2d 100644 --- a/src/google/protobuf/compiler/python/python_generator.cc +++ b/src/google/protobuf/compiler/python/python_generator.cc @@ -42,8 +42,9 @@ // performance-minded Python code leverage the fast C++ implementation // directly. -#include +#include #include +#include #include #include @@ -105,6 +106,13 @@ string NamePrefixedWithNestedTypes(const DescriptorT& descriptor, const char kDescriptorKey[] = "DESCRIPTOR"; +// Should we generate generic services for this file? +inline bool HasGenericServices(const FileDescriptor *file) { + return file->service_count() > 0 && + file->options().py_generic_services(); +} + + // Prints the common boilerplate needed at the top of every .py // file output by this generator. void PrintTopBoilerplate( @@ -115,14 +123,21 @@ void PrintTopBoilerplate( "\n" "from google.protobuf import descriptor\n" "from google.protobuf import message\n" - "from google.protobuf import reflection\n" - "from google.protobuf import service\n" - "from google.protobuf import service_reflection\n"); + "from google.protobuf import reflection\n"); + if (HasGenericServices(file)) { + printer->Print( + "from google.protobuf import service\n" + "from google.protobuf import service_reflection\n"); + } + // Avoid circular imports if this module is descriptor_pb2. if (!descriptor_proto) { printer->Print( "from google.protobuf import descriptor_pb2\n"); } + printer->Print( + "# @@protoc_insertion_point(imports)\n"); + printer->Print("\n\n"); } @@ -150,10 +165,30 @@ string StringifyDefaultValue(const FieldDescriptor& field) { return SimpleItoa(field.default_value_int64()); case FieldDescriptor::CPPTYPE_UINT64: return SimpleItoa(field.default_value_uint64()); - case FieldDescriptor::CPPTYPE_DOUBLE: - return SimpleDtoa(field.default_value_double()); - case FieldDescriptor::CPPTYPE_FLOAT: - return SimpleFtoa(field.default_value_float()); + case FieldDescriptor::CPPTYPE_DOUBLE: { + double value = field.default_value_double(); + if (value == numeric_limits::infinity()) { + return "float('inf')"; + } else if (value == -numeric_limits::infinity()) { + return "float('-inf')"; + } else if (value != value) { + return "float('nan')"; + } else { + return SimpleDtoa(value); + } + } + case FieldDescriptor::CPPTYPE_FLOAT: { + float value = field.default_value_float(); + if (value == numeric_limits::infinity()) { + return "float('inf')"; + } else if (value == -numeric_limits::infinity()) { + return "float('-inf')"; + } else if (value != value) { + return "float('nan')"; + } else { + return SimpleFtoa(value); + } + } case FieldDescriptor::CPPTYPE_BOOL: return field.default_value_bool() ? "True" : "False"; case FieldDescriptor::CPPTYPE_ENUM: @@ -204,6 +239,10 @@ bool Generator::Generate(const FileDescriptor* file, StripString(&filename, ".", '/'); filename += ".py"; + FileDescriptorProto fdp; + file_->CopyTo(&fdp); + fdp.SerializeToString(&file_descriptor_serialized_); + scoped_ptr output(output_directory->Open(filename)); GOOGLE_CHECK(output.get()); @@ -211,6 +250,7 @@ bool Generator::Generate(const FileDescriptor* file, printer_ = &printer; PrintTopBoilerplate(printer_, file_, GeneratingDescriptorProto()); + PrintFileDescriptor(); PrintTopLevelEnums(); PrintTopLevelExtensions(); PrintAllNestedEnumsInFile(); @@ -224,7 +264,13 @@ bool Generator::Generate(const FileDescriptor* file, // since they need to call static RegisterExtension() methods on these // classes. FixForeignFieldsInExtensions(); - PrintServices(); + if (HasGenericServices(file)) { + PrintServices(); + } + + printer.Print( + "# @@protoc_insertion_point(module_scope)\n"); + return !printer.failed(); } @@ -238,6 +284,30 @@ void Generator::PrintImports() const { printer_->Print("\n"); } +// Prints the single file descriptor for this file. +void Generator::PrintFileDescriptor() const { + map m; + m["descriptor_name"] = kDescriptorKey; + m["name"] = file_->name(); + m["package"] = file_->package(); + const char file_descriptor_template[] = + "$descriptor_name$ = descriptor.FileDescriptor(\n" + " name='$name$',\n" + " package='$package$',\n"; + printer_->Print(m, file_descriptor_template); + printer_->Indent(); + printer_->Print( + "serialized_pb='$value$'", + "value", strings::CHexEscape(file_descriptor_serialized_)); + + // TODO(falk): Also print options and fix the message_type, enum_type, + // service and extension later in the generation. + + printer_->Outdent(); + printer_->Print(")\n"); + printer_->Print("\n"); +} + // Prints descriptors and module-level constants for all top-level // enums defined in |file|. void Generator::PrintTopLevelEnums() const { @@ -277,12 +347,13 @@ void Generator::PrintEnum(const EnumDescriptor& enum_descriptor) const { m["descriptor_name"] = ModuleLevelDescriptorName(enum_descriptor); m["name"] = enum_descriptor.name(); m["full_name"] = enum_descriptor.full_name(); - m["filename"] = enum_descriptor.name(); + m["file"] = kDescriptorKey; const char enum_descriptor_template[] = "$descriptor_name$ = descriptor.EnumDescriptor(\n" " name='$name$',\n" " full_name='$full_name$',\n" - " filename='$filename$',\n" + " filename=None,\n" + " file=$file$,\n" " values=[\n"; string options_string; enum_descriptor.options().SerializeToString(&options_string); @@ -295,9 +366,12 @@ void Generator::PrintEnum(const EnumDescriptor& enum_descriptor) const { } printer_->Outdent(); printer_->Print("],\n"); + printer_->Print("containing_type=None,\n"); printer_->Print("options=$options_value$,\n", "options_value", OptionsValue("EnumOptions", CEscape(options_string))); + EnumDescriptorProto edp; + PrintSerializedPbInterval(enum_descriptor, edp); printer_->Outdent(); printer_->Print(")\n"); printer_->Print("\n"); @@ -362,15 +436,21 @@ void Generator::PrintServiceDescriptor( map m; m["name"] = descriptor.name(); m["full_name"] = descriptor.full_name(); + m["file"] = kDescriptorKey; m["index"] = SimpleItoa(descriptor.index()); m["options_value"] = OptionsValue("ServiceOptions", options_string); const char required_function_arguments[] = "name='$name$',\n" "full_name='$full_name$',\n" + "file=$file$,\n" "index=$index$,\n" - "options=$options_value$,\n" - "methods=[\n"; + "options=$options_value$,\n"; printer_->Print(m, required_function_arguments); + + ServiceDescriptorProto sdp; + PrintSerializedPbInterval(descriptor, sdp); + + printer_->Print("methods=[\n"); for (int i = 0; i < descriptor.method_count(); ++i) { const MethodDescriptor* method = descriptor.method(i); string options_string; @@ -444,17 +524,27 @@ void Generator::PrintDescriptor(const Descriptor& message_descriptor) const { map m; m["name"] = message_descriptor.name(); m["full_name"] = message_descriptor.full_name(); - m["filename"] = message_descriptor.file()->name(); + m["file"] = kDescriptorKey; const char required_function_arguments[] = "name='$name$',\n" "full_name='$full_name$',\n" - "filename='$filename$',\n" - "containing_type=None,\n"; // TODO(robinson): Implement containing_type. + "filename=None,\n" + "file=$file$,\n" + "containing_type=None,\n"; printer_->Print(m, required_function_arguments); PrintFieldsInDescriptor(message_descriptor); PrintExtensionsInDescriptor(message_descriptor); - // TODO(robinson): implement printing of nested_types. - printer_->Print("nested_types=[], # TODO(robinson): Implement.\n"); + + // Nested types + printer_->Print("nested_types=["); + for (int i = 0; i < message_descriptor.nested_type_count(); ++i) { + const string nested_name = ModuleLevelDescriptorName( + *message_descriptor.nested_type(i)); + printer_->Print("$name$, ", "name", nested_name); + } + printer_->Print("],\n"); + + // Enum types printer_->Print("enum_types=[\n"); printer_->Indent(); for (int i = 0; i < message_descriptor.enum_type_count(); ++i) { @@ -468,8 +558,28 @@ void Generator::PrintDescriptor(const Descriptor& message_descriptor) const { string options_string; message_descriptor.options().SerializeToString(&options_string); printer_->Print( - "options=$options_value$", - "options_value", OptionsValue("MessageOptions", options_string)); + "options=$options_value$,\n" + "is_extendable=$extendable$", + "options_value", OptionsValue("MessageOptions", options_string), + "extendable", message_descriptor.extension_range_count() > 0 ? + "True" : "False"); + printer_->Print(",\n"); + + // Extension ranges + printer_->Print("extension_ranges=["); + for (int i = 0; i < message_descriptor.extension_range_count(); ++i) { + const Descriptor::ExtensionRange* range = + message_descriptor.extension_range(i); + printer_->Print("($start$, $end$), ", + "start", SimpleItoa(range->start), + "end", SimpleItoa(range->end)); + } + printer_->Print("],\n"); + + // Serialization of proto + DescriptorProto edp; + PrintSerializedPbInterval(message_descriptor, edp); + printer_->Outdent(); printer_->Print(")\n"); } @@ -511,6 +621,12 @@ void Generator::PrintMessage( m["descriptor_key"] = kDescriptorKey; m["descriptor_name"] = ModuleLevelDescriptorName(message_descriptor); printer_->Print(m, "$descriptor_key$ = $descriptor_name$\n"); + + printer_->Print( + "\n" + "# @@protoc_insertion_point(class_scope:$full_name$)\n", + "full_name", message_descriptor.full_name()); + printer_->Outdent(); } @@ -527,16 +643,27 @@ void Generator::PrintNestedMessages( // Recursively fixes foreign fields in all nested types in |descriptor|, then // sets the message_type and enum_type of all message and enum fields to point // to their respective descriptors. +// Args: +// descriptor: descriptor to print fields for. +// containing_descriptor: if descriptor is a nested type, this is its +// containing type, or NULL if this is a root/top-level type. void Generator::FixForeignFieldsInDescriptor( - const Descriptor& descriptor) const { + const Descriptor& descriptor, + const Descriptor* containing_descriptor) const { for (int i = 0; i < descriptor.nested_type_count(); ++i) { - FixForeignFieldsInDescriptor(*descriptor.nested_type(i)); + FixForeignFieldsInDescriptor(*descriptor.nested_type(i), &descriptor); } for (int i = 0; i < descriptor.field_count(); ++i) { const FieldDescriptor& field_descriptor = *descriptor.field(i); FixForeignFieldsInField(&descriptor, field_descriptor, "fields_by_name"); } + + FixContainingTypeInDescriptor(descriptor, containing_descriptor); + for (int i = 0; i < descriptor.enum_type_count(); ++i) { + const EnumDescriptor& enum_descriptor = *descriptor.enum_type(i); + FixContainingTypeInDescriptor(enum_descriptor, &descriptor); + } } // Sets any necessary message_type and enum_type attributes @@ -593,13 +720,29 @@ string Generator::FieldReferencingExpression( python_dict_name, field.name()); } +// Prints containing_type for nested descriptors or enum descriptors. +template +void Generator::FixContainingTypeInDescriptor( + const DescriptorT& descriptor, + const Descriptor* containing_descriptor) const { + if (containing_descriptor != NULL) { + const string nested_name = ModuleLevelDescriptorName(descriptor); + const string parent_name = ModuleLevelDescriptorName( + *containing_descriptor); + printer_->Print( + "$nested_name$.containing_type = $parent_name$;\n", + "nested_name", nested_name, + "parent_name", parent_name); + } +} + // Prints statements setting the message_type and enum_type fields in the // Python descriptor objects we've already output in ths file. We must // do this in a separate step due to circular references (otherwise, we'd // just set everything in the initial assignment statements). void Generator::FixForeignFieldsInDescriptors() const { for (int i = 0; i < file_->message_type_count(); ++i) { - FixForeignFieldsInDescriptor(*file_->message_type(i)); + FixForeignFieldsInDescriptor(*file_->message_type(i), NULL); } printer_->Print("\n"); } @@ -696,6 +839,7 @@ void Generator::PrintFieldDescriptor( m["type"] = SimpleItoa(field.type()); m["cpp_type"] = SimpleItoa(field.cpp_type()); m["label"] = SimpleItoa(field.label()); + m["has_default_value"] = field.has_default_value() ? "True" : "False"; m["default_value"] = StringifyDefaultValue(field); m["is_extension"] = is_extension ? "True" : "False"; m["options"] = OptionsValue("FieldOptions", options_string); @@ -703,13 +847,13 @@ void Generator::PrintFieldDescriptor( // these fields in correctly after all referenced descriptors have been // defined and/or imported (see FixForeignFieldsInDescriptors()). const char field_descriptor_decl[] = - "descriptor.FieldDescriptor(\n" - " name='$name$', full_name='$full_name$', index=$index$,\n" - " number=$number$, type=$type$, cpp_type=$cpp_type$, label=$label$,\n" - " default_value=$default_value$,\n" - " message_type=None, enum_type=None, containing_type=None,\n" - " is_extension=$is_extension$, extension_scope=None,\n" - " options=$options$)"; + "descriptor.FieldDescriptor(\n" + " name='$name$', full_name='$full_name$', index=$index$,\n" + " number=$number$, type=$type$, cpp_type=$cpp_type$, label=$label$,\n" + " has_default_value=$has_default_value$, default_value=$default_value$,\n" + " message_type=None, enum_type=None, containing_type=None,\n" + " is_extension=$is_extension$, extension_scope=None,\n" + " options=$options$)"; printer_->Print(m, field_descriptor_decl); } @@ -811,6 +955,29 @@ string Generator::ModuleLevelServiceDescriptorName( return name; } +// Prints standard constructor arguments serialized_start and serialized_end. +// Args: +// descriptor: The cpp descriptor to have a serialized reference. +// proto: A proto +// Example printer output: +// serialized_start=41, +// serialized_end=43, +// +template +void Generator::PrintSerializedPbInterval( + const DescriptorT& descriptor, DescriptorProtoT& proto) const { + descriptor.CopyTo(&proto); + string sp; + proto.SerializeToString(&sp); + int offset = file_descriptor_serialized_.find(sp); + GOOGLE_CHECK_GE(offset, 0); + + printer_->Print("serialized_start=$serialized_start$,\n" + "serialized_end=$serialized_end$,\n", + "serialized_start", SimpleItoa(offset), + "serialized_end", SimpleItoa(offset + sp.size())); +} + } // namespace python } // namespace compiler } // namespace protobuf diff --git a/src/google/protobuf/compiler/python/python_generator.h b/src/google/protobuf/compiler/python/python_generator.h index 8b99d624..43c20876 100644 --- a/src/google/protobuf/compiler/python/python_generator.h +++ b/src/google/protobuf/compiler/python/python_generator.h @@ -71,6 +71,7 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator { private: void PrintImports() const; + void PrintFileDescriptor() const; void PrintTopLevelEnums() const; void PrintAllNestedEnumsInFile() const; void PrintNestedEnums(const Descriptor& descriptor) const; @@ -97,13 +98,19 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator { void PrintNestedMessages(const Descriptor& containing_descriptor) const; void FixForeignFieldsInDescriptors() const; - void FixForeignFieldsInDescriptor(const Descriptor& descriptor) const; + void FixForeignFieldsInDescriptor( + const Descriptor& descriptor, + const Descriptor* containing_descriptor) const; void FixForeignFieldsInField(const Descriptor* containing_type, const FieldDescriptor& field, const string& python_dict_name) const; string FieldReferencingExpression(const Descriptor* containing_type, const FieldDescriptor& field, const string& python_dict_name) const; + template + void FixContainingTypeInDescriptor( + const DescriptorT& descriptor, + const Descriptor* containing_descriptor) const; void FixForeignFieldsInExtensions() const; void FixForeignFieldsInExtension( @@ -126,10 +133,15 @@ class LIBPROTOC_EXPORT Generator : public CodeGenerator { string ModuleLevelServiceDescriptorName( const ServiceDescriptor& descriptor) const; + template + void PrintSerializedPbInterval( + const DescriptorT& descriptor, DescriptorProtoT& proto) const; + // Very coarse-grained lock to ensure that Generate() is reentrant. - // Guards file_ and printer_. + // Guards file_, printer_ and file_descriptor_serialized_. mutable Mutex mutex_; mutable const FileDescriptor* file_; // Set in Generate(). Under mutex_. + mutable string file_descriptor_serialized_; mutable io::Printer* printer_; // Set in Generate(). Under mutex_. GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Generator); diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index a12e4e72..e0a95077 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -796,9 +796,10 @@ bool DescriptorPool::InternalIsFileLoaded(const string& filename) const { namespace { + EncodedDescriptorDatabase* generated_database_ = NULL; DescriptorPool* generated_pool_ = NULL; -GOOGLE_PROTOBUF_DECLARE_ONCE(generated_pool_init_); +GoogleOnceType generated_pool_init_; void DeleteGeneratedPool() { delete generated_database_; @@ -810,6 +811,7 @@ void DeleteGeneratedPool() { void InitGeneratedPool() { generated_database_ = new EncodedDescriptorDatabase; generated_pool_ = new DescriptorPool(generated_database_); + internal::OnShutdown(&DeleteGeneratedPool); } @@ -3651,17 +3653,11 @@ void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field, } // Only repeated primitive fields may be packed. - if (field->options().packed()) { - if (!field->is_repeated() || - field->type() == FieldDescriptor::TYPE_STRING || - field->type() == FieldDescriptor::TYPE_GROUP || - field->type() == FieldDescriptor::TYPE_MESSAGE || - field->type() == FieldDescriptor::TYPE_BYTES) { - AddError( - field->full_name(), proto, - DescriptorPool::ErrorCollector::TYPE, - "[packed = true] can only be specified for repeated primitive fields."); - } + if (field->options().packed() && !field->is_packable()) { + AddError( + field->full_name(), proto, + DescriptorPool::ErrorCollector::TYPE, + "[packed = true] can only be specified for repeated primitive fields."); } // Note: Default instance may not yet be initialized here, so we have to diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index 5b629a5d..7f87dd80 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -395,6 +395,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { bool is_required() const; // shorthand for label() == LABEL_REQUIRED bool is_optional() const; // shorthand for label() == LABEL_OPTIONAL bool is_repeated() const; // shorthand for label() == LABEL_REPEATED + bool is_packable() const; // shorthand for is_repeated() && + // IsTypePackable(type()) // Index of this field within the message's field array, or the file or // extension scope's extensions array. @@ -474,6 +476,9 @@ class LIBPROTOBUF_EXPORT FieldDescriptor { // Helper method to get the CppType for a particular Type. static CppType TypeToCppType(Type type); + // Return true iff [packed = true] is valid for fields of this type. + static inline bool IsTypePackable(Type field_type); + private: typedef FieldOptions OptionsType; @@ -1069,10 +1074,6 @@ class LIBPROTOBUF_EXPORT DescriptorPool { // These methods may contain hidden pitfalls and may be removed in a // future library version. - // DEPRECATED: Use of underlays can lead to many subtle gotchas. Instead, - // try to formulate what you want to do in terms of DescriptorDatabases. - // This constructor will be removed soon. - // // Create a DescriptorPool which is overlaid on top of some other pool. // If you search for a descriptor in the overlay and it is not found, the // underlay will be searched as a backup. If the underlay has its own @@ -1090,6 +1091,9 @@ class LIBPROTOBUF_EXPORT DescriptorPool { // types directly into generated_pool(): this is not allowed, and would be // bad design anyway. So, instead, you could use generated_pool() as an // underlay for a new DescriptorPool in which you add only the new file. + // + // WARNING: Use of underlays can lead to many subtle gotchas. Instead, + // try to formulate what you want to do in terms of DescriptorDatabases. explicit DescriptorPool(const DescriptorPool* underlay); // Called by generated classes at init time to add their descriptors to @@ -1294,6 +1298,10 @@ inline bool FieldDescriptor::is_repeated() const { return label() == LABEL_REPEATED; } +inline bool FieldDescriptor::is_packable() const { + return is_repeated() && IsTypePackable(type()); +} + // To save space, index() is computed by looking at the descriptor's position // in the parent's array of children. inline int FieldDescriptor::index() const { @@ -1342,6 +1350,13 @@ inline FieldDescriptor::CppType FieldDescriptor::TypeToCppType(Type type) { return kTypeToCppTypeMap[type]; } +inline bool FieldDescriptor::IsTypePackable(Type field_type) { + return (field_type != FieldDescriptor::TYPE_STRING && + field_type != FieldDescriptor::TYPE_GROUP && + field_type != FieldDescriptor::TYPE_MESSAGE && + field_type != FieldDescriptor::TYPE_BYTES); +} + inline const FileDescriptor* FileDescriptor::dependency(int index) const { return dependencies_[index]; } diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index 276c6009..f61e7cd0 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -8,6 +8,7 @@ #include #include #include +// @@protoc_insertion_point(includes) namespace google { namespace protobuf { @@ -250,11 +251,14 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { ::google::protobuf::MessageFactory::generated_factory(), sizeof(MethodDescriptorProto)); FileOptions_descriptor_ = file->message_type(8); - static const int FileOptions_offsets_[5] = { + static const int FileOptions_offsets_[8] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_package_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_outer_classname_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_multiple_files_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, optimize_for_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, cc_generic_services_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_generic_services_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, py_generic_services_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, uninterpreted_option_), }; FileOptions_reflection_ = @@ -552,43 +556,47 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "ptions\"\177\n\025MethodDescriptorProto\022\014\n\004name\030" "\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023\n\013output_type" "\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.protobu" - "f.MethodOptions\"\271\002\n\013FileOptions\022\024\n\014java_" + "f.MethodOptions\"\244\003\n\013FileOptions\022\024\n\014java_" "package\030\001 \001(\t\022\034\n\024java_outer_classname\030\010 " "\001(\t\022\"\n\023java_multiple_files\030\n \001(\010:\005false\022" "F\n\014optimize_for\030\t \001(\0162).google.protobuf." - "FileOptions.OptimizeMode:\005SPEED\022C\n\024unint" - "erpreted_option\030\347\007 \003(\0132$.google.protobuf" - ".UninterpretedOption\":\n\014OptimizeMode\022\t\n\005" - "SPEED\020\001\022\r\n\tCODE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003" - "*\t\010\350\007\020\200\200\200\200\002\"\270\001\n\016MessageOptions\022&\n\027messag" - "e_set_wire_format\030\001 \001(\010:\005false\022.\n\037no_sta" - "ndard_descriptor_accessor\030\002 \001(\010:\005false\022C" - "\n\024uninterpreted_option\030\347\007 \003(\0132$.google.p" - "rotobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"\200" - "\002\n\014FieldOptions\0222\n\005ctype\030\001 \001(\0162#.google." - "protobuf.FieldOptions.CType\022\016\n\006packed\030\002 " - "\001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005false\022\034\n\024experi" - "mental_map_key\030\t \001(\t\022C\n\024uninterpreted_op" - "tion\030\347\007 \003(\0132$.google.protobuf.Uninterpre" - "tedOption\"#\n\005CType\022\010\n\004CORD\020\001\022\020\n\014STRING_P" - "IECE\020\002*\t\010\350\007\020\200\200\200\200\002\"]\n\013EnumOptions\022C\n\024unin" - "terpreted_option\030\347\007 \003(\0132$.google.protobu" - "f.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"b\n\020Enum" - "ValueOptions\022C\n\024uninterpreted_option\030\347\007 " - "\003(\0132$.google.protobuf.UninterpretedOptio" - "n*\t\010\350\007\020\200\200\200\200\002\"`\n\016ServiceOptions\022C\n\024uninte" - "rpreted_option\030\347\007 \003(\0132$.google.protobuf." - "UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"_\n\rMethod" - "Options\022C\n\024uninterpreted_option\030\347\007 \003(\0132$" - ".google.protobuf.UninterpretedOption*\t\010\350" - "\007\020\200\200\200\200\002\"\205\002\n\023UninterpretedOption\022;\n\004name\030" - "\002 \003(\0132-.google.protobuf.UninterpretedOpt" - "ion.NamePart\022\030\n\020identifier_value\030\003 \001(\t\022\032" - "\n\022positive_int_value\030\004 \001(\004\022\032\n\022negative_i" - "nt_value\030\005 \001(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014" - "string_value\030\007 \001(\014\0323\n\010NamePart\022\021\n\tname_p" - "art\030\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010B)\n\023com.g" - "oogle.protobufB\020DescriptorProtosH\001", 3554); + "FileOptions.OptimizeMode:\005SPEED\022!\n\023cc_ge" + "neric_services\030\020 \001(\010:\004true\022#\n\025java_gener" + "ic_services\030\021 \001(\010:\004true\022!\n\023py_generic_se" + "rvices\030\022 \001(\010:\004true\022C\n\024uninterpreted_opti" + "on\030\347\007 \003(\0132$.google.protobuf.Uninterprete" + "dOption\":\n\014OptimizeMode\022\t\n\005SPEED\020\001\022\r\n\tCO" + "DE_SIZE\020\002\022\020\n\014LITE_RUNTIME\020\003*\t\010\350\007\020\200\200\200\200\002\"\270" + "\001\n\016MessageOptions\022&\n\027message_set_wire_fo" + "rmat\030\001 \001(\010:\005false\022.\n\037no_standard_descrip" + "tor_accessor\030\002 \001(\010:\005false\022C\n\024uninterpret" + "ed_option\030\347\007 \003(\0132$.google.protobuf.Unint" + "erpretedOption*\t\010\350\007\020\200\200\200\200\002\"\224\002\n\014FieldOptio" + "ns\022:\n\005ctype\030\001 \001(\0162#.google.protobuf.Fiel" + "dOptions.CType:\006STRING\022\016\n\006packed\030\002 \001(\010\022\031" + "\n\ndeprecated\030\003 \001(\010:\005false\022\034\n\024experimenta" + "l_map_key\030\t \001(\t\022C\n\024uninterpreted_option\030" + "\347\007 \003(\0132$.google.protobuf.UninterpretedOp" + "tion\"/\n\005CType\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014S" + "TRING_PIECE\020\002*\t\010\350\007\020\200\200\200\200\002\"]\n\013EnumOptions\022" + "C\n\024uninterpreted_option\030\347\007 \003(\0132$.google." + "protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"" + "b\n\020EnumValueOptions\022C\n\024uninterpreted_opt" + "ion\030\347\007 \003(\0132$.google.protobuf.Uninterpret" + "edOption*\t\010\350\007\020\200\200\200\200\002\"`\n\016ServiceOptions\022C\n" + "\024uninterpreted_option\030\347\007 \003(\0132$.google.pr" + "otobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"_\n" + "\rMethodOptions\022C\n\024uninterpreted_option\030\347" + "\007 \003(\0132$.google.protobuf.UninterpretedOpt" + "ion*\t\010\350\007\020\200\200\200\200\002\"\205\002\n\023UninterpretedOption\022;" + "\n\004name\030\002 \003(\0132-.google.protobuf.Uninterpr" + "etedOption.NamePart\022\030\n\020identifier_value\030" + "\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022\032\n\022neg" + "ative_int_value\030\005 \001(\003\022\024\n\014double_value\030\006 " + "\001(\001\022\024\n\014string_value\030\007 \001(\014\0323\n\010NamePart\022\021\n" + "\tname_part\030\001 \002(\t\022\024\n\014is_extension\030\002 \002(\010B)" + "\n\023com.google.protobufB\020DescriptorProtosH" + "\001", 3681); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/descriptor.proto", &protobuf_RegisterTypes); FileDescriptorSet::default_instance_ = new FileDescriptorSet(); @@ -645,7 +653,7 @@ const int FileDescriptorSet::kFileFieldNumber; #endif // !_MSC_VER FileDescriptorSet::FileDescriptorSet() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -653,7 +661,7 @@ void FileDescriptorSet::InitAsDefaultInstance() { } FileDescriptorSet::FileDescriptorSet(const FileDescriptorSet& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -672,6 +680,11 @@ void FileDescriptorSet::SharedDtor() { } } +void FileDescriptorSet::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* FileDescriptorSet::descriptor() { protobuf_AssignDescriptorsOnce(); return FileDescriptorSet_descriptor_; @@ -701,13 +714,14 @@ bool FileDescriptorSet::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.FileDescriptorProto file = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_file: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_file())); + } else { goto handle_uninterpreted; } - parse_file: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_file())); if (input->ExpectTag(10)) goto parse_file; if (input->ExpectAtEnd()) return true; break; @@ -731,15 +745,9 @@ bool FileDescriptorSet::MergePartialFromCodedStream( void FileDescriptorSet::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - FileDescriptorSet::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.FileDescriptorProto file = 1; for (int i = 0; i < this->file_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 1, this->file(i), output); } @@ -781,7 +789,9 @@ int FileDescriptorSet::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -857,7 +867,7 @@ const int FileDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER FileDescriptorProto::FileDescriptorProto() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -866,7 +876,7 @@ void FileDescriptorProto::InitAsDefaultInstance() { } FileDescriptorProto::FileDescriptorProto(const FileDescriptorProto& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -895,6 +905,11 @@ void FileDescriptorProto::SharedDtor() { } } +void FileDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* FileDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return FileDescriptorProto_descriptor_; @@ -943,47 +958,50 @@ bool FileDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_package; break; } // optional string package = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_package: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_package())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->package().data(), this->package().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_package: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_package())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->package().data(), this->package().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(26)) goto parse_dependency; break; } // repeated string dependency = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_dependency: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->add_dependency())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->dependency(0).data(), this->dependency(0).length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_dependency: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->add_dependency())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->dependency(0).data(), this->dependency(0).length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(26)) goto parse_dependency; if (input->ExpectTag(34)) goto parse_message_type; break; @@ -991,13 +1009,14 @@ bool FileDescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.DescriptorProto message_type = 4; case 4: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_message_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_message_type())); + } else { goto handle_uninterpreted; } - parse_message_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_message_type())); if (input->ExpectTag(34)) goto parse_message_type; if (input->ExpectTag(42)) goto parse_enum_type; break; @@ -1005,13 +1024,14 @@ bool FileDescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; case 5: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_enum_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_enum_type())); + } else { goto handle_uninterpreted; } - parse_enum_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_enum_type())); if (input->ExpectTag(42)) goto parse_enum_type; if (input->ExpectTag(50)) goto parse_service; break; @@ -1019,13 +1039,14 @@ bool FileDescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.ServiceDescriptorProto service = 6; case 6: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_service: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_service())); + } else { goto handle_uninterpreted; } - parse_service: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_service())); if (input->ExpectTag(50)) goto parse_service; if (input->ExpectTag(58)) goto parse_extension; break; @@ -1033,13 +1054,14 @@ bool FileDescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.FieldDescriptorProto extension = 7; case 7: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_extension: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_extension())); + } else { goto handle_uninterpreted; } - parse_extension: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_extension())); if (input->ExpectTag(58)) goto parse_extension; if (input->ExpectTag(66)) goto parse_options; break; @@ -1047,13 +1069,14 @@ bool FileDescriptorProto::MergePartialFromCodedStream( // optional .google.protobuf.FileOptions options = 8; case 8: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -1076,12 +1099,6 @@ bool FileDescriptorProto::MergePartialFromCodedStream( void FileDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - FileDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -1111,31 +1128,31 @@ void FileDescriptorProto::SerializeWithCachedSizes( // repeated .google.protobuf.DescriptorProto message_type = 4; for (int i = 0; i < this->message_type_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 4, this->message_type(i), output); } // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; for (int i = 0; i < this->enum_type_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 5, this->enum_type(i), output); } // repeated .google.protobuf.ServiceDescriptorProto service = 6; for (int i = 0; i < this->service_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 6, this->service(i), output); } // repeated .google.protobuf.FieldDescriptorProto extension = 7; for (int i = 0; i < this->extension_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 7, this->extension(i), output); } // optional .google.protobuf.FileOptions options = 8; if (_has_bit(7)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 8, this->options(), output); } @@ -1288,7 +1305,9 @@ int FileDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -1390,7 +1409,7 @@ const int DescriptorProto_ExtensionRange::kEndFieldNumber; #endif // !_MSC_VER DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -1398,7 +1417,7 @@ void DescriptorProto_ExtensionRange::InitAsDefaultInstance() { } DescriptorProto_ExtensionRange::DescriptorProto_ExtensionRange(const DescriptorProto_ExtensionRange& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -1419,6 +1438,11 @@ void DescriptorProto_ExtensionRange::SharedDtor() { } } +void DescriptorProto_ExtensionRange::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* DescriptorProto_ExtensionRange::descriptor() { protobuf_AssignDescriptorsOnce(); return DescriptorProto_ExtensionRange_descriptor_; @@ -1451,27 +1475,31 @@ bool DescriptorProto_ExtensionRange::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional int32 start = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &start_))); + _set_bit(0); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadInt32( - input, &start_)); - _set_bit(0); if (input->ExpectTag(16)) goto parse_end; break; } // optional int32 end = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_end: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &end_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_end: - DO_(::google::protobuf::internal::WireFormatLite::ReadInt32( - input, &end_)); - _set_bit(1); if (input->ExpectAtEnd()) return true; break; } @@ -1494,12 +1522,6 @@ bool DescriptorProto_ExtensionRange::MergePartialFromCodedStream( void DescriptorProto_ExtensionRange::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - DescriptorProto_ExtensionRange::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional int32 start = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormatLite::WriteInt32(1, this->start(), output); @@ -1559,7 +1581,9 @@ int DescriptorProto_ExtensionRange::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -1638,7 +1662,7 @@ const int DescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER DescriptorProto::DescriptorProto() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -1647,7 +1671,7 @@ void DescriptorProto::InitAsDefaultInstance() { } DescriptorProto::DescriptorProto(const DescriptorProto& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -1672,6 +1696,11 @@ void DescriptorProto::SharedDtor() { } } +void DescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* DescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return DescriptorProto_descriptor_; @@ -1715,28 +1744,30 @@ bool DescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_field; break; } // repeated .google.protobuf.FieldDescriptorProto field = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_field: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_field())); + } else { goto handle_uninterpreted; } - parse_field: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_field())); if (input->ExpectTag(18)) goto parse_field; if (input->ExpectTag(26)) goto parse_nested_type; break; @@ -1744,13 +1775,14 @@ bool DescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.DescriptorProto nested_type = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_nested_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_nested_type())); + } else { goto handle_uninterpreted; } - parse_nested_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_nested_type())); if (input->ExpectTag(26)) goto parse_nested_type; if (input->ExpectTag(34)) goto parse_enum_type; break; @@ -1758,13 +1790,14 @@ bool DescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; case 4: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_enum_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_enum_type())); + } else { goto handle_uninterpreted; } - parse_enum_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_enum_type())); if (input->ExpectTag(34)) goto parse_enum_type; if (input->ExpectTag(42)) goto parse_extension_range; break; @@ -1772,13 +1805,14 @@ bool DescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; case 5: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_extension_range: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_extension_range())); + } else { goto handle_uninterpreted; } - parse_extension_range: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_extension_range())); if (input->ExpectTag(42)) goto parse_extension_range; if (input->ExpectTag(50)) goto parse_extension; break; @@ -1786,13 +1820,14 @@ bool DescriptorProto::MergePartialFromCodedStream( // repeated .google.protobuf.FieldDescriptorProto extension = 6; case 6: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_extension: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_extension())); + } else { goto handle_uninterpreted; } - parse_extension: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_extension())); if (input->ExpectTag(50)) goto parse_extension; if (input->ExpectTag(58)) goto parse_options; break; @@ -1800,13 +1835,14 @@ bool DescriptorProto::MergePartialFromCodedStream( // optional .google.protobuf.MessageOptions options = 7; case 7: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -1829,12 +1865,6 @@ bool DescriptorProto::MergePartialFromCodedStream( void DescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - DescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -1846,37 +1876,37 @@ void DescriptorProto::SerializeWithCachedSizes( // repeated .google.protobuf.FieldDescriptorProto field = 2; for (int i = 0; i < this->field_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 2, this->field(i), output); } // repeated .google.protobuf.DescriptorProto nested_type = 3; for (int i = 0; i < this->nested_type_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 3, this->nested_type(i), output); } // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; for (int i = 0; i < this->enum_type_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 4, this->enum_type(i), output); } // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; for (int i = 0; i < this->extension_range_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 5, this->extension_range(i), output); } // repeated .google.protobuf.FieldDescriptorProto extension = 6; for (int i = 0; i < this->extension_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 6, this->extension(i), output); } // optional .google.protobuf.MessageOptions options = 7; if (_has_bit(6)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 7, this->options(), output); } @@ -2011,7 +2041,9 @@ int DescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -2154,6 +2186,7 @@ const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT32; const FieldDescriptorProto_Type FieldDescriptorProto::TYPE_SINT64; const FieldDescriptorProto_Type FieldDescriptorProto::Type_MIN; const FieldDescriptorProto_Type FieldDescriptorProto::Type_MAX; +const int FieldDescriptorProto::Type_ARRAYSIZE; #endif // _MSC_VER const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor() { protobuf_AssignDescriptorsOnce(); @@ -2176,6 +2209,7 @@ const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REQUIRED; const FieldDescriptorProto_Label FieldDescriptorProto::LABEL_REPEATED; const FieldDescriptorProto_Label FieldDescriptorProto::Label_MIN; const FieldDescriptorProto_Label FieldDescriptorProto::Label_MAX; +const int FieldDescriptorProto::Label_ARRAYSIZE; #endif // _MSC_VER const ::std::string FieldDescriptorProto::_default_name_; const ::std::string FieldDescriptorProto::_default_type_name_; @@ -2193,7 +2227,7 @@ const int FieldDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER FieldDescriptorProto::FieldDescriptorProto() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -2202,7 +2236,7 @@ void FieldDescriptorProto::InitAsDefaultInstance() { } FieldDescriptorProto::FieldDescriptorProto(const FieldDescriptorProto& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -2242,6 +2276,11 @@ void FieldDescriptorProto::SharedDtor() { } } +void FieldDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* FieldDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return FieldDescriptorProto_descriptor_; @@ -2298,62 +2337,69 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_extendee; break; } // optional string extendee = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_extendee: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_extendee())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->extendee().data(), this->extendee().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_extendee: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_extendee())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->extendee().data(), this->extendee().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(24)) goto parse_number; break; } // optional int32 number = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_number: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &number_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_number: - DO_(::google::protobuf::internal::WireFormatLite::ReadInt32( - input, &number_)); - _set_bit(1); if (input->ExpectTag(32)) goto parse_label; break; } // optional .google.protobuf.FieldDescriptorProto.Label label = 4; case 4: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - goto handle_uninterpreted; - } - parse_label: - int value; - DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value)); - if (::google::protobuf::FieldDescriptorProto_Label_IsValid(value)) { - set_label(static_cast< ::google::protobuf::FieldDescriptorProto_Label >(value)); + parse_label: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::google::protobuf::FieldDescriptorProto_Label_IsValid(value)) { + set_label(static_cast< ::google::protobuf::FieldDescriptorProto_Label >(value)); + } else { + mutable_unknown_fields()->AddVarint(4, value); + } } else { - mutable_unknown_fields()->AddVarint(4, value); + goto handle_uninterpreted; } if (input->ExpectTag(40)) goto parse_type; break; @@ -2361,17 +2407,20 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( // optional .google.protobuf.FieldDescriptorProto.Type type = 5; case 5: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - goto handle_uninterpreted; - } - parse_type: - int value; - DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value)); - if (::google::protobuf::FieldDescriptorProto_Type_IsValid(value)) { - set_type(static_cast< ::google::protobuf::FieldDescriptorProto_Type >(value)); + parse_type: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::google::protobuf::FieldDescriptorProto_Type_IsValid(value)) { + set_type(static_cast< ::google::protobuf::FieldDescriptorProto_Type >(value)); + } else { + mutable_unknown_fields()->AddVarint(5, value); + } } else { - mutable_unknown_fields()->AddVarint(5, value); + goto handle_uninterpreted; } if (input->ExpectTag(50)) goto parse_type_name; break; @@ -2379,45 +2428,48 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( // optional string type_name = 6; case 6: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_type_name: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_type_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->type_name().data(), this->type_name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_type_name: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_type_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->type_name().data(), this->type_name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(58)) goto parse_default_value; break; } // optional string default_value = 7; case 7: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_default_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_default_value())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->default_value().data(), this->default_value().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_default_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_default_value())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->default_value().data(), this->default_value().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(66)) goto parse_options; break; } // optional .google.protobuf.FieldOptions options = 8; case 8: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -2440,12 +2492,6 @@ bool FieldDescriptorProto::MergePartialFromCodedStream( void FieldDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - FieldDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -2501,7 +2547,7 @@ void FieldDescriptorProto::SerializeWithCachedSizes( // optional .google.protobuf.FieldOptions options = 8; if (_has_bit(7)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 8, this->options(), output); } @@ -2648,7 +2694,9 @@ int FieldDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -2750,7 +2798,7 @@ const int EnumDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER EnumDescriptorProto::EnumDescriptorProto() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -2759,7 +2807,7 @@ void EnumDescriptorProto::InitAsDefaultInstance() { } EnumDescriptorProto::EnumDescriptorProto(const EnumDescriptorProto& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -2784,6 +2832,11 @@ void EnumDescriptorProto::SharedDtor() { } } +void EnumDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* EnumDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return EnumDescriptorProto_descriptor_; @@ -2823,28 +2876,30 @@ bool EnumDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_value; break; } // repeated .google.protobuf.EnumValueDescriptorProto value = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_value())); + } else { goto handle_uninterpreted; } - parse_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_value())); if (input->ExpectTag(18)) goto parse_value; if (input->ExpectTag(26)) goto parse_options; break; @@ -2852,13 +2907,14 @@ bool EnumDescriptorProto::MergePartialFromCodedStream( // optional .google.protobuf.EnumOptions options = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -2881,12 +2937,6 @@ bool EnumDescriptorProto::MergePartialFromCodedStream( void EnumDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - EnumDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -2898,13 +2948,13 @@ void EnumDescriptorProto::SerializeWithCachedSizes( // repeated .google.protobuf.EnumValueDescriptorProto value = 2; for (int i = 0; i < this->value_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 2, this->value(i), output); } // optional .google.protobuf.EnumOptions options = 3; if (_has_bit(2)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 3, this->options(), output); } @@ -2979,7 +3029,9 @@ int EnumDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -3062,7 +3114,7 @@ const int EnumValueDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER EnumValueDescriptorProto::EnumValueDescriptorProto() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -3071,7 +3123,7 @@ void EnumValueDescriptorProto::InitAsDefaultInstance() { } EnumValueDescriptorProto::EnumValueDescriptorProto(const EnumValueDescriptorProto& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -3097,6 +3149,11 @@ void EnumValueDescriptorProto::SharedDtor() { } } +void EnumValueDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* EnumValueDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return EnumValueDescriptorProto_descriptor_; @@ -3136,42 +3193,46 @@ bool EnumValueDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(16)) goto parse_number; break; } // optional int32 number = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_number: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int32, ::google::protobuf::internal::WireFormatLite::TYPE_INT32>( + input, &number_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_number: - DO_(::google::protobuf::internal::WireFormatLite::ReadInt32( - input, &number_)); - _set_bit(1); if (input->ExpectTag(26)) goto parse_options; break; } // optional .google.protobuf.EnumValueOptions options = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -3194,12 +3255,6 @@ bool EnumValueDescriptorProto::MergePartialFromCodedStream( void EnumValueDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - EnumValueDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -3216,7 +3271,7 @@ void EnumValueDescriptorProto::SerializeWithCachedSizes( // optional .google.protobuf.EnumValueOptions options = 3; if (_has_bit(2)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 3, this->options(), output); } @@ -3288,7 +3343,9 @@ int EnumValueDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -3370,7 +3427,7 @@ const int ServiceDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER ServiceDescriptorProto::ServiceDescriptorProto() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -3379,7 +3436,7 @@ void ServiceDescriptorProto::InitAsDefaultInstance() { } ServiceDescriptorProto::ServiceDescriptorProto(const ServiceDescriptorProto& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -3404,6 +3461,11 @@ void ServiceDescriptorProto::SharedDtor() { } } +void ServiceDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* ServiceDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return ServiceDescriptorProto_descriptor_; @@ -3443,28 +3505,30 @@ bool ServiceDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_method; break; } // repeated .google.protobuf.MethodDescriptorProto method = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_method: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_method())); + } else { goto handle_uninterpreted; } - parse_method: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_method())); if (input->ExpectTag(18)) goto parse_method; if (input->ExpectTag(26)) goto parse_options; break; @@ -3472,13 +3536,14 @@ bool ServiceDescriptorProto::MergePartialFromCodedStream( // optional .google.protobuf.ServiceOptions options = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -3501,12 +3566,6 @@ bool ServiceDescriptorProto::MergePartialFromCodedStream( void ServiceDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - ServiceDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -3518,13 +3577,13 @@ void ServiceDescriptorProto::SerializeWithCachedSizes( // repeated .google.protobuf.MethodDescriptorProto method = 2; for (int i = 0; i < this->method_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 2, this->method(i), output); } // optional .google.protobuf.ServiceOptions options = 3; if (_has_bit(2)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 3, this->options(), output); } @@ -3599,7 +3658,9 @@ int ServiceDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -3685,7 +3746,7 @@ const int MethodDescriptorProto::kOptionsFieldNumber; #endif // !_MSC_VER MethodDescriptorProto::MethodDescriptorProto() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -3694,7 +3755,7 @@ void MethodDescriptorProto::InitAsDefaultInstance() { } MethodDescriptorProto::MethodDescriptorProto(const MethodDescriptorProto& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -3727,6 +3788,11 @@ void MethodDescriptorProto::SharedDtor() { } } +void MethodDescriptorProto::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* MethodDescriptorProto::descriptor() { protobuf_AssignDescriptorsOnce(); return MethodDescriptorProto_descriptor_; @@ -3775,60 +3841,64 @@ bool MethodDescriptorProto::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string name = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name().data(), this->name().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name().data(), this->name().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(18)) goto parse_input_type; break; } // optional string input_type = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_input_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_input_type())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->input_type().data(), this->input_type().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_input_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_input_type())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->input_type().data(), this->input_type().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(26)) goto parse_output_type; break; } // optional string output_type = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_output_type: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_output_type())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->output_type().data(), this->output_type().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_output_type: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_output_type())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->output_type().data(), this->output_type().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(34)) goto parse_options; break; } // optional .google.protobuf.MethodOptions options = 4; case 4: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_options: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, mutable_options())); + } else { goto handle_uninterpreted; } - parse_options: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, mutable_options())); if (input->ExpectAtEnd()) return true; break; } @@ -3851,12 +3921,6 @@ bool MethodDescriptorProto::MergePartialFromCodedStream( void MethodDescriptorProto::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - MethodDescriptorProto::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string name = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -3886,7 +3950,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes( // optional .google.protobuf.MethodOptions options = 4; if (_has_bit(3)) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 4, this->options(), output); } @@ -3980,7 +4044,9 @@ int MethodDescriptorProto::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -4079,6 +4145,7 @@ const FileOptions_OptimizeMode FileOptions::CODE_SIZE; const FileOptions_OptimizeMode FileOptions::LITE_RUNTIME; const FileOptions_OptimizeMode FileOptions::OptimizeMode_MIN; const FileOptions_OptimizeMode FileOptions::OptimizeMode_MAX; +const int FileOptions::OptimizeMode_ARRAYSIZE; #endif // _MSC_VER const ::std::string FileOptions::_default_java_package_; const ::std::string FileOptions::_default_java_outer_classname_; @@ -4087,11 +4154,14 @@ const int FileOptions::kJavaPackageFieldNumber; const int FileOptions::kJavaOuterClassnameFieldNumber; const int FileOptions::kJavaMultipleFilesFieldNumber; const int FileOptions::kOptimizeForFieldNumber; +const int FileOptions::kCcGenericServicesFieldNumber; +const int FileOptions::kJavaGenericServicesFieldNumber; +const int FileOptions::kPyGenericServicesFieldNumber; const int FileOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER FileOptions::FileOptions() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -4099,7 +4169,7 @@ void FileOptions::InitAsDefaultInstance() { } FileOptions::FileOptions(const FileOptions& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -4110,6 +4180,9 @@ void FileOptions::SharedCtor() { java_outer_classname_ = const_cast< ::std::string*>(&_default_java_outer_classname_); java_multiple_files_ = false; optimize_for_ = 1; + cc_generic_services_ = true; + java_generic_services_ = true; + py_generic_services_ = true; ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -4128,6 +4201,11 @@ void FileOptions::SharedDtor() { } } +void FileOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* FileOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return FileOptions_descriptor_; @@ -4158,6 +4236,9 @@ void FileOptions::Clear() { } java_multiple_files_ = false; optimize_for_ = 1; + cc_generic_services_ = true; + java_generic_services_ = true; + py_generic_services_ = true; } uninterpreted_option_.Clear(); ::memset(_has_bits_, 0, sizeof(_has_bits_)); @@ -4172,48 +4253,53 @@ bool FileOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional string java_package = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_java_package())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->java_package().data(), this->java_package().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_java_package())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->java_package().data(), this->java_package().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(66)) goto parse_java_outer_classname; break; } // optional string java_outer_classname = 8; case 8: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_java_outer_classname: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_java_outer_classname())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->java_outer_classname().data(), this->java_outer_classname().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_java_outer_classname: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_java_outer_classname())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->java_outer_classname().data(), this->java_outer_classname().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(72)) goto parse_optimize_for; break; } // optional .google.protobuf.FileOptions.OptimizeMode optimize_for = 9 [default = SPEED]; case 9: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - goto handle_uninterpreted; - } - parse_optimize_for: - int value; - DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value)); - if (::google::protobuf::FileOptions_OptimizeMode_IsValid(value)) { - set_optimize_for(static_cast< ::google::protobuf::FileOptions_OptimizeMode >(value)); + parse_optimize_for: + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::google::protobuf::FileOptions_OptimizeMode_IsValid(value)) { + set_optimize_for(static_cast< ::google::protobuf::FileOptions_OptimizeMode >(value)); + } else { + mutable_unknown_fields()->AddVarint(9, value); + } } else { - mutable_unknown_fields()->AddVarint(9, value); + goto handle_uninterpreted; } if (input->ExpectTag(80)) goto parse_java_multiple_files; break; @@ -4221,27 +4307,78 @@ bool FileOptions::MergePartialFromCodedStream( // optional bool java_multiple_files = 10 [default = false]; case 10: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_java_multiple_files: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &java_multiple_files_))); + _set_bit(2); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(128)) goto parse_cc_generic_services; + break; + } + + // optional bool cc_generic_services = 16 [default = true]; + case 16: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_cc_generic_services: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &cc_generic_services_))); + _set_bit(4); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(136)) goto parse_java_generic_services; + break; + } + + // optional bool java_generic_services = 17 [default = true]; + case 17: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_java_generic_services: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &java_generic_services_))); + _set_bit(5); + } else { + goto handle_uninterpreted; + } + if (input->ExpectTag(144)) goto parse_py_generic_services; + break; + } + + // optional bool py_generic_services = 18 [default = true]; + case 18: { + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == + ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_py_generic_services: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &py_generic_services_))); + _set_bit(6); + } else { goto handle_uninterpreted; } - parse_java_multiple_files: - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &java_multiple_files_)); - _set_bit(2); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; break; } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -4270,12 +4407,6 @@ bool FileOptions::MergePartialFromCodedStream( void FileOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - FileOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional string java_package = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -4305,9 +4436,24 @@ void FileOptions::SerializeWithCachedSizes( ::google::protobuf::internal::WireFormatLite::WriteBool(10, this->java_multiple_files(), output); } + // optional bool cc_generic_services = 16 [default = true]; + if (_has_bit(4)) { + ::google::protobuf::internal::WireFormatLite::WriteBool(16, this->cc_generic_services(), output); + } + + // optional bool java_generic_services = 17 [default = true]; + if (_has_bit(5)) { + ::google::protobuf::internal::WireFormatLite::WriteBool(17, this->java_generic_services(), output); + } + + // optional bool py_generic_services = 18 [default = true]; + if (_has_bit(6)) { + ::google::protobuf::internal::WireFormatLite::WriteBool(18, this->py_generic_services(), output); + } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -4354,6 +4500,21 @@ void FileOptions::SerializeWithCachedSizes( target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(10, this->java_multiple_files(), target); } + // optional bool cc_generic_services = 16 [default = true]; + if (_has_bit(4)) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(16, this->cc_generic_services(), target); + } + + // optional bool java_generic_services = 17 [default = true]; + if (_has_bit(5)) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(17, this->java_generic_services(), target); + } + + // optional bool py_generic_services = 18 [default = true]; + if (_has_bit(6)) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(18, this->py_generic_services(), target); + } + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { target = ::google::protobuf::internal::WireFormatLite:: @@ -4401,6 +4562,21 @@ int FileOptions::ByteSize() const { ::google::protobuf::internal::WireFormatLite::EnumSize(this->optimize_for()); } + // optional bool cc_generic_services = 16 [default = true]; + if (has_cc_generic_services()) { + total_size += 2 + 1; + } + + // optional bool java_generic_services = 17 [default = true]; + if (has_java_generic_services()) { + total_size += 2 + 1; + } + + // optional bool py_generic_services = 18 [default = true]; + if (has_py_generic_services()) { + total_size += 2 + 1; + } + } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; total_size += 2 * this->uninterpreted_option_size(); @@ -4417,7 +4593,9 @@ int FileOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -4449,6 +4627,15 @@ void FileOptions::MergeFrom(const FileOptions& from) { if (from._has_bit(3)) { set_optimize_for(from.optimize_for()); } + if (from._has_bit(4)) { + set_cc_generic_services(from.cc_generic_services()); + } + if (from._has_bit(5)) { + set_java_generic_services(from.java_generic_services()); + } + if (from._has_bit(6)) { + set_py_generic_services(from.py_generic_services()); + } } _extensions_.MergeFrom(from._extensions_); mutable_unknown_fields()->MergeFrom(from.unknown_fields()); @@ -4481,6 +4668,9 @@ void FileOptions::Swap(FileOptions* other) { std::swap(java_outer_classname_, other->java_outer_classname_); std::swap(java_multiple_files_, other->java_multiple_files_); std::swap(optimize_for_, other->optimize_for_); + std::swap(cc_generic_services_, other->cc_generic_services_); + std::swap(java_generic_services_, other->java_generic_services_); + std::swap(py_generic_services_, other->py_generic_services_); uninterpreted_option_.Swap(&other->uninterpreted_option_); std::swap(_has_bits_[0], other->_has_bits_[0]); _unknown_fields_.Swap(&other->_unknown_fields_); @@ -4507,7 +4697,7 @@ const int MessageOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER MessageOptions::MessageOptions() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -4515,7 +4705,7 @@ void MessageOptions::InitAsDefaultInstance() { } MessageOptions::MessageOptions(const MessageOptions& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -4536,6 +4726,11 @@ void MessageOptions::SharedDtor() { } } +void MessageOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* MessageOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return MessageOptions_descriptor_; @@ -4570,40 +4765,45 @@ bool MessageOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // optional bool message_set_wire_format = 1 [default = false]; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &message_set_wire_format_))); + _set_bit(0); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &message_set_wire_format_)); - _set_bit(0); if (input->ExpectTag(16)) goto parse_no_standard_descriptor_accessor; break; } // optional bool no_standard_descriptor_accessor = 2 [default = false]; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_no_standard_descriptor_accessor: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &no_standard_descriptor_accessor_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_no_standard_descriptor_accessor: - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &no_standard_descriptor_accessor_)); - _set_bit(1); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; break; } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -4632,12 +4832,6 @@ bool MessageOptions::MergePartialFromCodedStream( void MessageOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - MessageOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // optional bool message_set_wire_format = 1 [default = false]; if (_has_bit(0)) { ::google::protobuf::internal::WireFormatLite::WriteBool(1, this->message_set_wire_format(), output); @@ -4650,7 +4844,7 @@ void MessageOptions::SerializeWithCachedSizes( // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -4724,7 +4918,9 @@ int MessageOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -4805,6 +5001,7 @@ const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor() { } bool FieldOptions_CType_IsValid(int value) { switch(value) { + case 0: case 1: case 2: return true; @@ -4814,10 +5011,12 @@ bool FieldOptions_CType_IsValid(int value) { } #ifndef _MSC_VER +const FieldOptions_CType FieldOptions::STRING; const FieldOptions_CType FieldOptions::CORD; const FieldOptions_CType FieldOptions::STRING_PIECE; const FieldOptions_CType FieldOptions::CType_MIN; const FieldOptions_CType FieldOptions::CType_MAX; +const int FieldOptions::CType_ARRAYSIZE; #endif // _MSC_VER const ::std::string FieldOptions::_default_experimental_map_key_; #ifndef _MSC_VER @@ -4829,7 +5028,7 @@ const int FieldOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER FieldOptions::FieldOptions() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -4837,14 +5036,14 @@ void FieldOptions::InitAsDefaultInstance() { } FieldOptions::FieldOptions(const FieldOptions& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } void FieldOptions::SharedCtor() { _cached_size_ = 0; - ctype_ = 1; + ctype_ = 0; packed_ = false; deprecated_ = false; experimental_map_key_ = const_cast< ::std::string*>(&_default_experimental_map_key_); @@ -4863,6 +5062,11 @@ void FieldOptions::SharedDtor() { } } +void FieldOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* FieldOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return FieldOptions_descriptor_; @@ -4881,7 +5085,7 @@ FieldOptions* FieldOptions::New() const { void FieldOptions::Clear() { _extensions_.Clear(); if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - ctype_ = 1; + ctype_ = 0; packed_ = false; deprecated_ = false; if (_has_bit(3)) { @@ -4901,18 +5105,21 @@ bool FieldOptions::MergePartialFromCodedStream( ::google::protobuf::uint32 tag; while ((tag = input->ReadTag()) != 0) { switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { - // optional .google.protobuf.FieldOptions.CType ctype = 1; + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { - goto handle_uninterpreted; - } - int value; - DO_(::google::protobuf::internal::WireFormatLite::ReadEnum(input, &value)); - if (::google::protobuf::FieldOptions_CType_IsValid(value)) { - set_ctype(static_cast< ::google::protobuf::FieldOptions_CType >(value)); + int value; + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, ::google::protobuf::internal::WireFormatLite::TYPE_ENUM>( + input, &value))); + if (::google::protobuf::FieldOptions_CType_IsValid(value)) { + set_ctype(static_cast< ::google::protobuf::FieldOptions_CType >(value)); + } else { + mutable_unknown_fields()->AddVarint(1, value); + } } else { - mutable_unknown_fields()->AddVarint(1, value); + goto handle_uninterpreted; } if (input->ExpectTag(16)) goto parse_packed; break; @@ -4920,57 +5127,63 @@ bool FieldOptions::MergePartialFromCodedStream( // optional bool packed = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_packed: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &packed_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_packed: - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &packed_)); - _set_bit(1); if (input->ExpectTag(24)) goto parse_deprecated; break; } // optional bool deprecated = 3 [default = false]; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_deprecated: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &deprecated_))); + _set_bit(2); + } else { goto handle_uninterpreted; } - parse_deprecated: - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &deprecated_)); - _set_bit(2); if (input->ExpectTag(74)) goto parse_experimental_map_key; break; } // optional string experimental_map_key = 9; case 9: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_experimental_map_key: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_experimental_map_key())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->experimental_map_key().data(), this->experimental_map_key().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_experimental_map_key: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_experimental_map_key())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->experimental_map_key().data(), this->experimental_map_key().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; break; } // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -4999,13 +5212,7 @@ bool FieldOptions::MergePartialFromCodedStream( void FieldOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - FieldOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - - // optional .google.protobuf.FieldOptions.CType ctype = 1; + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; if (_has_bit(0)) { ::google::protobuf::internal::WireFormatLite::WriteEnum( 1, this->ctype(), output); @@ -5032,7 +5239,7 @@ void FieldOptions::SerializeWithCachedSizes( // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -5048,7 +5255,7 @@ void FieldOptions::SerializeWithCachedSizes( ::google::protobuf::uint8* FieldOptions::SerializeWithCachedSizesToArray( ::google::protobuf::uint8* target) const { - // optional .google.protobuf.FieldOptions.CType ctype = 1; + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; if (_has_bit(0)) { target = ::google::protobuf::internal::WireFormatLite::WriteEnumToArray( 1, this->ctype(), target); @@ -5096,7 +5303,7 @@ int FieldOptions::ByteSize() const { int total_size = 0; if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) { - // optional .google.protobuf.FieldOptions.CType ctype = 1; + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; if (has_ctype()) { total_size += 1 + ::google::protobuf::internal::WireFormatLite::EnumSize(this->ctype()); @@ -5135,7 +5342,9 @@ int FieldOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -5223,7 +5432,7 @@ const int EnumOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER EnumOptions::EnumOptions() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -5231,7 +5440,7 @@ void EnumOptions::InitAsDefaultInstance() { } EnumOptions::EnumOptions(const EnumOptions& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -5250,6 +5459,11 @@ void EnumOptions::SharedDtor() { } } +void EnumOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* EnumOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return EnumOptions_descriptor_; @@ -5280,13 +5494,14 @@ bool EnumOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -5315,15 +5530,9 @@ bool EnumOptions::MergePartialFromCodedStream( void EnumOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - EnumOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -5375,7 +5584,9 @@ int EnumOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -5445,7 +5656,7 @@ const int EnumValueOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER EnumValueOptions::EnumValueOptions() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -5453,7 +5664,7 @@ void EnumValueOptions::InitAsDefaultInstance() { } EnumValueOptions::EnumValueOptions(const EnumValueOptions& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -5472,6 +5683,11 @@ void EnumValueOptions::SharedDtor() { } } +void EnumValueOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* EnumValueOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return EnumValueOptions_descriptor_; @@ -5502,13 +5718,14 @@ bool EnumValueOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -5537,15 +5754,9 @@ bool EnumValueOptions::MergePartialFromCodedStream( void EnumValueOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - EnumValueOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -5597,7 +5808,9 @@ int EnumValueOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -5667,7 +5880,7 @@ const int ServiceOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER ServiceOptions::ServiceOptions() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -5675,7 +5888,7 @@ void ServiceOptions::InitAsDefaultInstance() { } ServiceOptions::ServiceOptions(const ServiceOptions& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -5694,6 +5907,11 @@ void ServiceOptions::SharedDtor() { } } +void ServiceOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* ServiceOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return ServiceOptions_descriptor_; @@ -5724,13 +5942,14 @@ bool ServiceOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -5759,15 +5978,9 @@ bool ServiceOptions::MergePartialFromCodedStream( void ServiceOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - ServiceOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -5819,7 +6032,9 @@ int ServiceOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -5889,7 +6104,7 @@ const int MethodOptions::kUninterpretedOptionFieldNumber; #endif // !_MSC_VER MethodOptions::MethodOptions() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -5897,7 +6112,7 @@ void MethodOptions::InitAsDefaultInstance() { } MethodOptions::MethodOptions(const MethodOptions& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -5916,6 +6131,11 @@ void MethodOptions::SharedDtor() { } } +void MethodOptions::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* MethodOptions::descriptor() { protobuf_AssignDescriptorsOnce(); return MethodOptions_descriptor_; @@ -5946,13 +6166,14 @@ bool MethodOptions::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; case 999: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_uninterpreted_option: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_uninterpreted_option())); + } else { goto handle_uninterpreted; } - parse_uninterpreted_option: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_uninterpreted_option())); if (input->ExpectTag(7994)) goto parse_uninterpreted_option; if (input->ExpectAtEnd()) return true; break; @@ -5981,15 +6202,9 @@ bool MethodOptions::MergePartialFromCodedStream( void MethodOptions::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - MethodOptions::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; for (int i = 0; i < this->uninterpreted_option_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 999, this->uninterpreted_option(i), output); } @@ -6041,7 +6256,9 @@ int MethodOptions::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -6113,7 +6330,7 @@ const int UninterpretedOption_NamePart::kIsExtensionFieldNumber; #endif // !_MSC_VER UninterpretedOption_NamePart::UninterpretedOption_NamePart() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -6121,7 +6338,7 @@ void UninterpretedOption_NamePart::InitAsDefaultInstance() { } UninterpretedOption_NamePart::UninterpretedOption_NamePart(const UninterpretedOption_NamePart& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -6145,6 +6362,11 @@ void UninterpretedOption_NamePart::SharedDtor() { } } +void UninterpretedOption_NamePart::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* UninterpretedOption_NamePart::descriptor() { protobuf_AssignDescriptorsOnce(); return UninterpretedOption_NamePart_descriptor_; @@ -6181,29 +6403,32 @@ bool UninterpretedOption_NamePart::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // required string name_part = 1; case 1: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_name_part())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->name_part().data(), this->name_part().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_name_part())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->name_part().data(), this->name_part().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(16)) goto parse_is_extension; break; } // required bool is_extension = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_is_extension: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &is_extension_))); + _set_bit(1); + } else { goto handle_uninterpreted; } - parse_is_extension: - DO_(::google::protobuf::internal::WireFormatLite::ReadBool( - input, &is_extension_)); - _set_bit(1); if (input->ExpectAtEnd()) return true; break; } @@ -6226,12 +6451,6 @@ bool UninterpretedOption_NamePart::MergePartialFromCodedStream( void UninterpretedOption_NamePart::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - UninterpretedOption_NamePart::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // required string name_part = 1; if (_has_bit(0)) { ::google::protobuf::internal::WireFormat::VerifyUTF8String( @@ -6298,7 +6517,9 @@ int UninterpretedOption_NamePart::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -6378,7 +6599,7 @@ const int UninterpretedOption::kStringValueFieldNumber; #endif // !_MSC_VER UninterpretedOption::UninterpretedOption() - : Message() { + : ::google::protobuf::Message() { SharedCtor(); } @@ -6386,7 +6607,7 @@ void UninterpretedOption::InitAsDefaultInstance() { } UninterpretedOption::UninterpretedOption(const UninterpretedOption& from) - : Message() { + : ::google::protobuf::Message() { SharedCtor(); MergeFrom(from); } @@ -6416,6 +6637,11 @@ void UninterpretedOption::SharedDtor() { } } +void UninterpretedOption::SetCachedSize(int size) const { + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); + _cached_size_ = size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); +} const ::google::protobuf::Descriptor* UninterpretedOption::descriptor() { protobuf_AssignDescriptorsOnce(); return UninterpretedOption_descriptor_; @@ -6460,13 +6686,14 @@ bool UninterpretedOption::MergePartialFromCodedStream( switch (::google::protobuf::internal::WireFormatLite::GetTagFieldNumber(tag)) { // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; case 2: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_name: + DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( + input, add_name())); + } else { goto handle_uninterpreted; } - parse_name: - DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual( - input, add_name())); if (input->ExpectTag(18)) goto parse_name; if (input->ExpectTag(26)) goto parse_identifier_value; break; @@ -6474,71 +6701,79 @@ bool UninterpretedOption::MergePartialFromCodedStream( // optional string identifier_value = 3; case 3: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_identifier_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadString( + input, this->mutable_identifier_value())); + ::google::protobuf::internal::WireFormat::VerifyUTF8String( + this->identifier_value().data(), this->identifier_value().length(), + ::google::protobuf::internal::WireFormat::PARSE); + } else { goto handle_uninterpreted; } - parse_identifier_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadString( - input, this->mutable_identifier_value())); - ::google::protobuf::internal::WireFormat::VerifyUTF8String( - this->identifier_value().data(), this->identifier_value().length(), - ::google::protobuf::internal::WireFormat::PARSE); if (input->ExpectTag(32)) goto parse_positive_int_value; break; } // optional uint64 positive_int_value = 4; case 4: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_positive_int_value: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::uint64, ::google::protobuf::internal::WireFormatLite::TYPE_UINT64>( + input, &positive_int_value_))); + _set_bit(2); + } else { goto handle_uninterpreted; } - parse_positive_int_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadUInt64( - input, &positive_int_value_)); - _set_bit(2); if (input->ExpectTag(40)) goto parse_negative_int_value; break; } // optional int64 negative_int_value = 5; case 5: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_VARINT) { + parse_negative_int_value: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + ::google::protobuf::int64, ::google::protobuf::internal::WireFormatLite::TYPE_INT64>( + input, &negative_int_value_))); + _set_bit(3); + } else { goto handle_uninterpreted; } - parse_negative_int_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadInt64( - input, &negative_int_value_)); - _set_bit(3); if (input->ExpectTag(49)) goto parse_double_value; break; } // optional double double_value = 6; case 6: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_FIXED64) { + parse_double_value: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + double, ::google::protobuf::internal::WireFormatLite::TYPE_DOUBLE>( + input, &double_value_))); + _set_bit(4); + } else { goto handle_uninterpreted; } - parse_double_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadDouble( - input, &double_value_)); - _set_bit(4); if (input->ExpectTag(58)) goto parse_string_value; break; } // optional bytes string_value = 7; case 7: { - if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) != + if (::google::protobuf::internal::WireFormatLite::GetTagWireType(tag) == ::google::protobuf::internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + parse_string_value: + DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( + input, this->mutable_string_value())); + } else { goto handle_uninterpreted; } - parse_string_value: - DO_(::google::protobuf::internal::WireFormatLite::ReadBytes( - input, this->mutable_string_value())); if (input->ExpectAtEnd()) return true; break; } @@ -6561,15 +6796,9 @@ bool UninterpretedOption::MergePartialFromCodedStream( void UninterpretedOption::SerializeWithCachedSizes( ::google::protobuf::io::CodedOutputStream* output) const { - ::google::protobuf::uint8* raw_buffer = output->GetDirectBufferForNBytesAndAdvance(_cached_size_); - if (raw_buffer != NULL) { - UninterpretedOption::SerializeWithCachedSizesToArray(raw_buffer); - return; - } - // repeated .google.protobuf.UninterpretedOption.NamePart name = 2; for (int i = 0; i < this->name_size(); i++) { - ::google::protobuf::internal::WireFormatLite::WriteMessageNoVirtual( + ::google::protobuf::internal::WireFormatLite::WriteMessageMaybeToArray( 2, this->name(i), output); } @@ -6708,7 +6937,9 @@ int UninterpretedOption::ByteSize() const { ::google::protobuf::internal::WireFormat::ComputeUnknownFieldsSize( unknown_fields()); } + GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN(); _cached_size_ = total_size; + GOOGLE_SAFE_CONCURRENT_WRITES_END(); return total_size; } @@ -6790,5 +7021,9 @@ void UninterpretedOption::Swap(UninterpretedOption* other) { } +// @@protoc_insertion_point(namespace_scope) + } // namespace protobuf } // namespace google + +// @@protoc_insertion_point(global_scope) diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index 4bf7369f..7df3ae16 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -1,4 +1,5 @@ // Generated by the protocol buffer compiler. DO NOT EDIT! +// source: google/protobuf/descriptor.proto #ifndef PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED #define PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED @@ -22,6 +23,7 @@ #include #include #include +// @@protoc_insertion_point(includes) namespace google { namespace protobuf { @@ -73,6 +75,7 @@ enum FieldDescriptorProto_Type { LIBPROTOBUF_EXPORT bool FieldDescriptorProto_Type_IsValid(int value); const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MIN = FieldDescriptorProto_Type_TYPE_DOUBLE; const FieldDescriptorProto_Type FieldDescriptorProto_Type_Type_MAX = FieldDescriptorProto_Type_TYPE_SINT64; +const int FieldDescriptorProto_Type_Type_ARRAYSIZE = FieldDescriptorProto_Type_Type_MAX + 1; LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Type_descriptor(); inline const ::std::string& FieldDescriptorProto_Type_Name(FieldDescriptorProto_Type value) { @@ -92,6 +95,7 @@ enum FieldDescriptorProto_Label { LIBPROTOBUF_EXPORT bool FieldDescriptorProto_Label_IsValid(int value); const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MIN = FieldDescriptorProto_Label_LABEL_OPTIONAL; const FieldDescriptorProto_Label FieldDescriptorProto_Label_Label_MAX = FieldDescriptorProto_Label_LABEL_REPEATED; +const int FieldDescriptorProto_Label_Label_ARRAYSIZE = FieldDescriptorProto_Label_Label_MAX + 1; LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldDescriptorProto_Label_descriptor(); inline const ::std::string& FieldDescriptorProto_Label_Name(FieldDescriptorProto_Label value) { @@ -111,6 +115,7 @@ enum FileOptions_OptimizeMode { LIBPROTOBUF_EXPORT bool FileOptions_OptimizeMode_IsValid(int value); const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MIN = FileOptions_OptimizeMode_SPEED; const FileOptions_OptimizeMode FileOptions_OptimizeMode_OptimizeMode_MAX = FileOptions_OptimizeMode_LITE_RUNTIME; +const int FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE = FileOptions_OptimizeMode_OptimizeMode_MAX + 1; LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FileOptions_OptimizeMode_descriptor(); inline const ::std::string& FileOptions_OptimizeMode_Name(FileOptions_OptimizeMode value) { @@ -123,12 +128,14 @@ inline bool FileOptions_OptimizeMode_Parse( FileOptions_OptimizeMode_descriptor(), name, value); } enum FieldOptions_CType { + FieldOptions_CType_STRING = 0, FieldOptions_CType_CORD = 1, FieldOptions_CType_STRING_PIECE = 2 }; LIBPROTOBUF_EXPORT bool FieldOptions_CType_IsValid(int value); -const FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_CORD; +const FieldOptions_CType FieldOptions_CType_CType_MIN = FieldOptions_CType_STRING; const FieldOptions_CType FieldOptions_CType_CType_MAX = FieldOptions_CType_STRING_PIECE; +const int FieldOptions_CType_CType_ARRAYSIZE = FieldOptions_CType_CType_MAX + 1; LIBPROTOBUF_EXPORT const ::google::protobuf::EnumDescriptor* FieldOptions_CType_descriptor(); inline const ::std::string& FieldOptions_CType_Name(FieldOptions_CType value) { @@ -164,6 +171,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message static const ::google::protobuf::Descriptor* descriptor(); static const FileDescriptorSet& default_instance(); + void Swap(FileDescriptorSet* other); // implements Message ---------------------------------------------- @@ -186,7 +194,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -199,12 +207,15 @@ class LIBPROTOBUF_EXPORT FileDescriptorSet : public ::google::protobuf::Message inline int file_size() const; inline void clear_file(); static const int kFileFieldNumber = 1; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& file() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* mutable_file(); inline const ::google::protobuf::FileDescriptorProto& file(int index) const; inline ::google::protobuf::FileDescriptorProto* mutable_file(int index); inline ::google::protobuf::FileDescriptorProto* add_file(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& + file() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* + mutable_file(); + // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorSet) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -254,6 +265,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag static const ::google::protobuf::Descriptor* descriptor(); static const FileDescriptorProto& default_instance(); + void Swap(FileDescriptorProto* other); // implements Message ---------------------------------------------- @@ -276,7 +288,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -309,8 +321,6 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag inline int dependency_size() const; inline void clear_dependency(); static const int kDependencyFieldNumber = 3; - inline const ::google::protobuf::RepeatedPtrField< ::std::string>& dependency() const; - inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_dependency(); inline const ::std::string& dependency(int index) const; inline ::std::string* mutable_dependency(int index); inline void set_dependency(int index, const ::std::string& value); @@ -320,46 +330,56 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag inline void add_dependency(const ::std::string& value); inline void add_dependency(const char* value); inline void add_dependency(const char* value, size_t size); + inline const ::google::protobuf::RepeatedPtrField< ::std::string>& dependency() const; + inline ::google::protobuf::RepeatedPtrField< ::std::string>* mutable_dependency(); // repeated .google.protobuf.DescriptorProto message_type = 4; inline int message_type_size() const; inline void clear_message_type(); static const int kMessageTypeFieldNumber = 4; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& message_type() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* mutable_message_type(); inline const ::google::protobuf::DescriptorProto& message_type(int index) const; inline ::google::protobuf::DescriptorProto* mutable_message_type(int index); inline ::google::protobuf::DescriptorProto* add_message_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& + message_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* + mutable_message_type(); // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; inline int enum_type_size() const; inline void clear_enum_type(); static const int kEnumTypeFieldNumber = 5; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& enum_type() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* mutable_enum_type(); inline const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const; inline ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index); inline ::google::protobuf::EnumDescriptorProto* add_enum_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& + enum_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* + mutable_enum_type(); // repeated .google.protobuf.ServiceDescriptorProto service = 6; inline int service_size() const; inline void clear_service(); static const int kServiceFieldNumber = 6; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& service() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* mutable_service(); inline const ::google::protobuf::ServiceDescriptorProto& service(int index) const; inline ::google::protobuf::ServiceDescriptorProto* mutable_service(int index); inline ::google::protobuf::ServiceDescriptorProto* add_service(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& + service() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* + mutable_service(); // repeated .google.protobuf.FieldDescriptorProto extension = 7; inline int extension_size() const; inline void clear_extension(); static const int kExtensionFieldNumber = 7; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& extension() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_extension(); inline const ::google::protobuf::FieldDescriptorProto& extension(int index) const; inline ::google::protobuf::FieldDescriptorProto* mutable_extension(int index); inline ::google::protobuf::FieldDescriptorProto* add_extension(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + extension() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* + mutable_extension(); // optional .google.protobuf.FileOptions options = 8; inline bool has_options() const; @@ -368,6 +388,7 @@ class LIBPROTOBUF_EXPORT FileDescriptorProto : public ::google::protobuf::Messag inline const ::google::protobuf::FileOptions& options() const; inline ::google::protobuf::FileOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.FileDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -426,6 +447,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto static const ::google::protobuf::Descriptor* descriptor(); static const DescriptorProto_ExtensionRange& default_instance(); + void Swap(DescriptorProto_ExtensionRange* other); // implements Message ---------------------------------------------- @@ -448,7 +470,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -471,6 +493,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto_ExtensionRange : public ::google::proto inline ::google::protobuf::int32 end() const; inline void set_end(::google::protobuf::int32 value); + // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto.ExtensionRange) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -521,6 +544,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const DescriptorProto& default_instance(); + void Swap(DescriptorProto* other); // implements Message ---------------------------------------------- @@ -543,7 +567,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -568,51 +592,61 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { inline int field_size() const; inline void clear_field(); static const int kFieldFieldNumber = 2; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& field() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_field(); inline const ::google::protobuf::FieldDescriptorProto& field(int index) const; inline ::google::protobuf::FieldDescriptorProto* mutable_field(int index); inline ::google::protobuf::FieldDescriptorProto* add_field(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + field() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* + mutable_field(); // repeated .google.protobuf.FieldDescriptorProto extension = 6; inline int extension_size() const; inline void clear_extension(); static const int kExtensionFieldNumber = 6; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& extension() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* mutable_extension(); inline const ::google::protobuf::FieldDescriptorProto& extension(int index) const; inline ::google::protobuf::FieldDescriptorProto* mutable_extension(int index); inline ::google::protobuf::FieldDescriptorProto* add_extension(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& + extension() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* + mutable_extension(); // repeated .google.protobuf.DescriptorProto nested_type = 3; inline int nested_type_size() const; inline void clear_nested_type(); static const int kNestedTypeFieldNumber = 3; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& nested_type() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* mutable_nested_type(); inline const ::google::protobuf::DescriptorProto& nested_type(int index) const; inline ::google::protobuf::DescriptorProto* mutable_nested_type(int index); inline ::google::protobuf::DescriptorProto* add_nested_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& + nested_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* + mutable_nested_type(); // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; inline int enum_type_size() const; inline void clear_enum_type(); static const int kEnumTypeFieldNumber = 4; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& enum_type() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* mutable_enum_type(); inline const ::google::protobuf::EnumDescriptorProto& enum_type(int index) const; inline ::google::protobuf::EnumDescriptorProto* mutable_enum_type(int index); inline ::google::protobuf::EnumDescriptorProto* add_enum_type(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& + enum_type() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* + mutable_enum_type(); // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; inline int extension_range_size() const; inline void clear_extension_range(); static const int kExtensionRangeFieldNumber = 5; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& extension_range() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* mutable_extension_range(); inline const ::google::protobuf::DescriptorProto_ExtensionRange& extension_range(int index) const; inline ::google::protobuf::DescriptorProto_ExtensionRange* mutable_extension_range(int index); inline ::google::protobuf::DescriptorProto_ExtensionRange* add_extension_range(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& + extension_range() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* + mutable_extension_range(); // optional .google.protobuf.MessageOptions options = 7; inline bool has_options() const; @@ -621,6 +655,7 @@ class LIBPROTOBUF_EXPORT DescriptorProto : public ::google::protobuf::Message { inline const ::google::protobuf::MessageOptions& options() const; inline ::google::protobuf::MessageOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.DescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -677,6 +712,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa static const ::google::protobuf::Descriptor* descriptor(); static const FieldDescriptorProto& default_instance(); + void Swap(FieldDescriptorProto* other); // implements Message ---------------------------------------------- @@ -699,7 +735,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -732,6 +768,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa FieldDescriptorProto_Type_Type_MIN; static const Type Type_MAX = FieldDescriptorProto_Type_Type_MAX; + static const int Type_ARRAYSIZE = + FieldDescriptorProto_Type_Type_ARRAYSIZE; static inline const ::google::protobuf::EnumDescriptor* Type_descriptor() { return FieldDescriptorProto_Type_descriptor(); @@ -755,6 +793,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa FieldDescriptorProto_Label_Label_MIN; static const Label Label_MAX = FieldDescriptorProto_Label_Label_MAX; + static const int Label_ARRAYSIZE = + FieldDescriptorProto_Label_Label_ARRAYSIZE; static inline const ::google::protobuf::EnumDescriptor* Label_descriptor() { return FieldDescriptorProto_Label_descriptor(); @@ -837,6 +877,7 @@ class LIBPROTOBUF_EXPORT FieldDescriptorProto : public ::google::protobuf::Messa inline const ::google::protobuf::FieldOptions& options() const; inline ::google::protobuf::FieldOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.FieldDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -897,6 +938,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag static const ::google::protobuf::Descriptor* descriptor(); static const EnumDescriptorProto& default_instance(); + void Swap(EnumDescriptorProto* other); // implements Message ---------------------------------------------- @@ -919,7 +961,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -942,11 +984,13 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag inline int value_size() const; inline void clear_value(); static const int kValueFieldNumber = 2; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& value() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* mutable_value(); inline const ::google::protobuf::EnumValueDescriptorProto& value(int index) const; inline ::google::protobuf::EnumValueDescriptorProto* mutable_value(int index); inline ::google::protobuf::EnumValueDescriptorProto* add_value(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& + value() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* + mutable_value(); // optional .google.protobuf.EnumOptions options = 3; inline bool has_options() const; @@ -955,6 +999,7 @@ class LIBPROTOBUF_EXPORT EnumDescriptorProto : public ::google::protobuf::Messag inline const ::google::protobuf::EnumOptions& options() const; inline ::google::protobuf::EnumOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.EnumDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -1007,6 +1052,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M static const ::google::protobuf::Descriptor* descriptor(); static const EnumValueDescriptorProto& default_instance(); + void Swap(EnumValueDescriptorProto* other); // implements Message ---------------------------------------------- @@ -1029,7 +1075,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1062,6 +1108,7 @@ class LIBPROTOBUF_EXPORT EnumValueDescriptorProto : public ::google::protobuf::M inline const ::google::protobuf::EnumValueOptions& options() const; inline ::google::protobuf::EnumValueOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -1114,6 +1161,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes static const ::google::protobuf::Descriptor* descriptor(); static const ServiceDescriptorProto& default_instance(); + void Swap(ServiceDescriptorProto* other); // implements Message ---------------------------------------------- @@ -1136,7 +1184,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1159,11 +1207,13 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes inline int method_size() const; inline void clear_method(); static const int kMethodFieldNumber = 2; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& method() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* mutable_method(); inline const ::google::protobuf::MethodDescriptorProto& method(int index) const; inline ::google::protobuf::MethodDescriptorProto* mutable_method(int index); inline ::google::protobuf::MethodDescriptorProto* add_method(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& + method() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* + mutable_method(); // optional .google.protobuf.ServiceOptions options = 3; inline bool has_options() const; @@ -1172,6 +1222,7 @@ class LIBPROTOBUF_EXPORT ServiceDescriptorProto : public ::google::protobuf::Mes inline const ::google::protobuf::ServiceOptions& options() const; inline ::google::protobuf::ServiceOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.ServiceDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -1224,6 +1275,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess static const ::google::protobuf::Descriptor* descriptor(); static const MethodDescriptorProto& default_instance(); + void Swap(MethodDescriptorProto* other); // implements Message ---------------------------------------------- @@ -1246,7 +1298,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1292,6 +1344,7 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess inline const ::google::protobuf::MethodOptions& options() const; inline ::google::protobuf::MethodOptions* mutable_options(); + // @@protoc_insertion_point(class_scope:google.protobuf.MethodDescriptorProto) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -1347,6 +1400,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const FileOptions& default_instance(); + void Swap(FileOptions* other); // implements Message ---------------------------------------------- @@ -1369,7 +1423,7 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1387,6 +1441,8 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { FileOptions_OptimizeMode_OptimizeMode_MIN; static const OptimizeMode OptimizeMode_MAX = FileOptions_OptimizeMode_OptimizeMode_MAX; + static const int OptimizeMode_ARRAYSIZE = + FileOptions_OptimizeMode_OptimizeMode_ARRAYSIZE; static inline const ::google::protobuf::EnumDescriptor* OptimizeMode_descriptor() { return FileOptions_OptimizeMode_descriptor(); @@ -1435,17 +1491,41 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { inline ::google::protobuf::FileOptions_OptimizeMode optimize_for() const; inline void set_optimize_for(::google::protobuf::FileOptions_OptimizeMode value); + // optional bool cc_generic_services = 16 [default = true]; + inline bool has_cc_generic_services() const; + inline void clear_cc_generic_services(); + static const int kCcGenericServicesFieldNumber = 16; + inline bool cc_generic_services() const; + inline void set_cc_generic_services(bool value); + + // optional bool java_generic_services = 17 [default = true]; + inline bool has_java_generic_services() const; + inline void clear_java_generic_services(); + static const int kJavaGenericServicesFieldNumber = 17; + inline bool java_generic_services() const; + inline void set_java_generic_services(bool value); + + // optional bool py_generic_services = 18 [default = true]; + inline bool has_py_generic_services() const; + inline void clear_py_generic_services(); + static const int kPyGenericServicesFieldNumber = 18; + inline bool py_generic_services() const; + inline void set_py_generic_services(bool value); + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FileOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.FileOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1457,12 +1537,15 @@ class LIBPROTOBUF_EXPORT FileOptions : public ::google::protobuf::Message { static const ::std::string _default_java_outer_classname_; bool java_multiple_files_; int optimize_for_; + bool cc_generic_services_; + bool java_generic_services_; + bool py_generic_services_; ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_; friend void LIBPROTOBUF_EXPORT protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto(); friend void protobuf_ShutdownFile_google_2fprotobuf_2fdescriptor_2eproto(); - ::google::protobuf::uint32 _has_bits_[(5 + 31) / 32]; + ::google::protobuf::uint32 _has_bits_[(8 + 31) / 32]; // WHY DOES & HAVE LOWER PRECEDENCE THAN != !? inline bool _has_bit(int index) const { @@ -1502,6 +1585,7 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const MessageOptions& default_instance(); + void Swap(MessageOptions* other); // implements Message ---------------------------------------------- @@ -1524,7 +1608,7 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1551,13 +1635,16 @@ class LIBPROTOBUF_EXPORT MessageOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MessageOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.MessageOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1610,6 +1697,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const FieldOptions& default_instance(); + void Swap(FieldOptions* other); // implements Message ---------------------------------------------- @@ -1632,7 +1720,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1640,6 +1728,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { // nested types ---------------------------------------------------- typedef FieldOptions_CType CType; + static const CType STRING = FieldOptions_CType_STRING; static const CType CORD = FieldOptions_CType_CORD; static const CType STRING_PIECE = FieldOptions_CType_STRING_PIECE; static inline bool CType_IsValid(int value) { @@ -1649,6 +1738,8 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { FieldOptions_CType_CType_MIN; static const CType CType_MAX = FieldOptions_CType_CType_MAX; + static const int CType_ARRAYSIZE = + FieldOptions_CType_CType_ARRAYSIZE; static inline const ::google::protobuf::EnumDescriptor* CType_descriptor() { return FieldOptions_CType_descriptor(); @@ -1663,7 +1754,7 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { // accessors ------------------------------------------------------- - // optional .google.protobuf.FieldOptions.CType ctype = 1; + // optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; inline bool has_ctype() const; inline void clear_ctype(); static const int kCtypeFieldNumber = 1; @@ -1698,13 +1789,16 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(FieldOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.FieldOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1760,6 +1854,7 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const EnumOptions& default_instance(); + void Swap(EnumOptions* other); // implements Message ---------------------------------------------- @@ -1782,7 +1877,7 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1795,13 +1890,16 @@ class LIBPROTOBUF_EXPORT EnumOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.EnumOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1852,6 +1950,7 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const EnumValueOptions& default_instance(); + void Swap(EnumValueOptions* other); // implements Message ---------------------------------------------- @@ -1874,7 +1973,7 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1887,13 +1986,16 @@ class LIBPROTOBUF_EXPORT EnumValueOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(EnumValueOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.EnumValueOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -1944,6 +2046,7 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const ServiceOptions& default_instance(); + void Swap(ServiceOptions* other); // implements Message ---------------------------------------------- @@ -1966,7 +2069,7 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -1979,13 +2082,16 @@ class LIBPROTOBUF_EXPORT ServiceOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(ServiceOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.ServiceOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -2036,6 +2142,7 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message { static const ::google::protobuf::Descriptor* descriptor(); static const MethodOptions& default_instance(); + void Swap(MethodOptions* other); // implements Message ---------------------------------------------- @@ -2058,7 +2165,7 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message { private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -2071,13 +2178,16 @@ class LIBPROTOBUF_EXPORT MethodOptions : public ::google::protobuf::Message { inline int uninterpreted_option_size() const; inline void clear_uninterpreted_option(); static const int kUninterpretedOptionFieldNumber = 999; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& uninterpreted_option() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* mutable_uninterpreted_option(); inline const ::google::protobuf::UninterpretedOption& uninterpreted_option(int index) const; inline ::google::protobuf::UninterpretedOption* mutable_uninterpreted_option(int index); inline ::google::protobuf::UninterpretedOption* add_uninterpreted_option(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& + uninterpreted_option() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* + mutable_uninterpreted_option(); GOOGLE_PROTOBUF_EXTENSION_ACCESSORS(MethodOptions) + // @@protoc_insertion_point(class_scope:google.protobuf.MethodOptions) private: ::google::protobuf::internal::ExtensionSet _extensions_; ::google::protobuf::UnknownFieldSet _unknown_fields_; @@ -2128,6 +2238,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu static const ::google::protobuf::Descriptor* descriptor(); static const UninterpretedOption_NamePart& default_instance(); + void Swap(UninterpretedOption_NamePart* other); // implements Message ---------------------------------------------- @@ -2150,7 +2261,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -2176,6 +2287,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption_NamePart : public ::google::protobu inline bool is_extension() const; inline void set_is_extension(bool value); + // @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption.NamePart) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -2227,6 +2339,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag static const ::google::protobuf::Descriptor* descriptor(); static const UninterpretedOption& default_instance(); + void Swap(UninterpretedOption* other); // implements Message ---------------------------------------------- @@ -2249,7 +2362,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag private: void SharedCtor(); void SharedDtor(); - void SetCachedSize(int size) const { _cached_size_ = size; } + void SetCachedSize(int size) const; public: ::google::protobuf::Metadata GetMetadata() const; @@ -2264,11 +2377,13 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag inline int name_size() const; inline void clear_name(); static const int kNameFieldNumber = 2; - inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& name() const; - inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* mutable_name(); inline const ::google::protobuf::UninterpretedOption_NamePart& name(int index) const; inline ::google::protobuf::UninterpretedOption_NamePart* mutable_name(int index); inline ::google::protobuf::UninterpretedOption_NamePart* add_name(); + inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& + name() const; + inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* + mutable_name(); // optional string identifier_value = 3; inline bool has_identifier_value() const; @@ -2311,6 +2426,7 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag inline void set_string_value(const void* value, size_t size); inline ::std::string* mutable_string_value(); + // @@protoc_insertion_point(class_scope:google.protobuf.UninterpretedOption) private: ::google::protobuf::UnknownFieldSet _unknown_fields_; mutable int _cached_size_; @@ -2346,9 +2462,6 @@ class LIBPROTOBUF_EXPORT UninterpretedOption : public ::google::protobuf::Messag // =================================================================== -// =================================================================== - - // =================================================================== // FileDescriptorSet @@ -2360,14 +2473,6 @@ inline int FileDescriptorSet::file_size() const { inline void FileDescriptorSet::clear_file() { file_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& -FileDescriptorSet::file() const { - return file_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* -FileDescriptorSet::mutable_file() { - return &file_; -} inline const ::google::protobuf::FileDescriptorProto& FileDescriptorSet::file(int index) const { return file_.Get(index); } @@ -2377,6 +2482,14 @@ inline ::google::protobuf::FileDescriptorProto* FileDescriptorSet::mutable_file( inline ::google::protobuf::FileDescriptorProto* FileDescriptorSet::add_file() { return file_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >& +FileDescriptorSet::file() const { + return file_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FileDescriptorProto >* +FileDescriptorSet::mutable_file() { + return &file_; +} // ------------------------------------------------------------------- @@ -2473,14 +2586,6 @@ inline int FileDescriptorProto::dependency_size() const { inline void FileDescriptorProto::clear_dependency() { dependency_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::std::string>& -FileDescriptorProto::dependency() const { - return dependency_; -} -inline ::google::protobuf::RepeatedPtrField< ::std::string>* -FileDescriptorProto::mutable_dependency() { - return &dependency_; -} inline const ::std::string& FileDescriptorProto::dependency(int index) const { return dependency_.Get(index); } @@ -2509,6 +2614,14 @@ inline void FileDescriptorProto::add_dependency(const char* value) { inline void FileDescriptorProto::add_dependency(const char* value, size_t size) { dependency_.Add()->assign(reinterpret_cast(value), size); } +inline const ::google::protobuf::RepeatedPtrField< ::std::string>& +FileDescriptorProto::dependency() const { + return dependency_; +} +inline ::google::protobuf::RepeatedPtrField< ::std::string>* +FileDescriptorProto::mutable_dependency() { + return &dependency_; +} // repeated .google.protobuf.DescriptorProto message_type = 4; inline int FileDescriptorProto::message_type_size() const { @@ -2517,14 +2630,6 @@ inline int FileDescriptorProto::message_type_size() const { inline void FileDescriptorProto::clear_message_type() { message_type_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& -FileDescriptorProto::message_type() const { - return message_type_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* -FileDescriptorProto::mutable_message_type() { - return &message_type_; -} inline const ::google::protobuf::DescriptorProto& FileDescriptorProto::message_type(int index) const { return message_type_.Get(index); } @@ -2534,6 +2639,14 @@ inline ::google::protobuf::DescriptorProto* FileDescriptorProto::mutable_message inline ::google::protobuf::DescriptorProto* FileDescriptorProto::add_message_type() { return message_type_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& +FileDescriptorProto::message_type() const { + return message_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* +FileDescriptorProto::mutable_message_type() { + return &message_type_; +} // repeated .google.protobuf.EnumDescriptorProto enum_type = 5; inline int FileDescriptorProto::enum_type_size() const { @@ -2542,14 +2655,6 @@ inline int FileDescriptorProto::enum_type_size() const { inline void FileDescriptorProto::clear_enum_type() { enum_type_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& -FileDescriptorProto::enum_type() const { - return enum_type_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* -FileDescriptorProto::mutable_enum_type() { - return &enum_type_; -} inline const ::google::protobuf::EnumDescriptorProto& FileDescriptorProto::enum_type(int index) const { return enum_type_.Get(index); } @@ -2559,6 +2664,14 @@ inline ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::mutable_enu inline ::google::protobuf::EnumDescriptorProto* FileDescriptorProto::add_enum_type() { return enum_type_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& +FileDescriptorProto::enum_type() const { + return enum_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* +FileDescriptorProto::mutable_enum_type() { + return &enum_type_; +} // repeated .google.protobuf.ServiceDescriptorProto service = 6; inline int FileDescriptorProto::service_size() const { @@ -2567,14 +2680,6 @@ inline int FileDescriptorProto::service_size() const { inline void FileDescriptorProto::clear_service() { service_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& -FileDescriptorProto::service() const { - return service_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* -FileDescriptorProto::mutable_service() { - return &service_; -} inline const ::google::protobuf::ServiceDescriptorProto& FileDescriptorProto::service(int index) const { return service_.Get(index); } @@ -2584,6 +2689,14 @@ inline ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::mutable_ inline ::google::protobuf::ServiceDescriptorProto* FileDescriptorProto::add_service() { return service_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >& +FileDescriptorProto::service() const { + return service_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::ServiceDescriptorProto >* +FileDescriptorProto::mutable_service() { + return &service_; +} // repeated .google.protobuf.FieldDescriptorProto extension = 7; inline int FileDescriptorProto::extension_size() const { @@ -2592,14 +2705,6 @@ inline int FileDescriptorProto::extension_size() const { inline void FileDescriptorProto::clear_extension() { extension_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& -FileDescriptorProto::extension() const { - return extension_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* -FileDescriptorProto::mutable_extension() { - return &extension_; -} inline const ::google::protobuf::FieldDescriptorProto& FileDescriptorProto::extension(int index) const { return extension_.Get(index); } @@ -2609,6 +2714,14 @@ inline ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::mutable_ex inline ::google::protobuf::FieldDescriptorProto* FileDescriptorProto::add_extension() { return extension_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +FileDescriptorProto::extension() const { + return extension_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +FileDescriptorProto::mutable_extension() { + return &extension_; +} // optional .google.protobuf.FileOptions options = 8; inline bool FileDescriptorProto::has_options() const { @@ -2716,14 +2829,6 @@ inline int DescriptorProto::field_size() const { inline void DescriptorProto::clear_field() { field_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& -DescriptorProto::field() const { - return field_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* -DescriptorProto::mutable_field() { - return &field_; -} inline const ::google::protobuf::FieldDescriptorProto& DescriptorProto::field(int index) const { return field_.Get(index); } @@ -2733,6 +2838,14 @@ inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_field( inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_field() { return field_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::field() const { + return field_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +DescriptorProto::mutable_field() { + return &field_; +} // repeated .google.protobuf.FieldDescriptorProto extension = 6; inline int DescriptorProto::extension_size() const { @@ -2741,14 +2854,6 @@ inline int DescriptorProto::extension_size() const { inline void DescriptorProto::clear_extension() { extension_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& -DescriptorProto::extension() const { - return extension_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* -DescriptorProto::mutable_extension() { - return &extension_; -} inline const ::google::protobuf::FieldDescriptorProto& DescriptorProto::extension(int index) const { return extension_.Get(index); } @@ -2758,6 +2863,14 @@ inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::mutable_extens inline ::google::protobuf::FieldDescriptorProto* DescriptorProto::add_extension() { return extension_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >& +DescriptorProto::extension() const { + return extension_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::FieldDescriptorProto >* +DescriptorProto::mutable_extension() { + return &extension_; +} // repeated .google.protobuf.DescriptorProto nested_type = 3; inline int DescriptorProto::nested_type_size() const { @@ -2766,14 +2879,6 @@ inline int DescriptorProto::nested_type_size() const { inline void DescriptorProto::clear_nested_type() { nested_type_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& -DescriptorProto::nested_type() const { - return nested_type_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* -DescriptorProto::mutable_nested_type() { - return &nested_type_; -} inline const ::google::protobuf::DescriptorProto& DescriptorProto::nested_type(int index) const { return nested_type_.Get(index); } @@ -2783,6 +2888,14 @@ inline ::google::protobuf::DescriptorProto* DescriptorProto::mutable_nested_type inline ::google::protobuf::DescriptorProto* DescriptorProto::add_nested_type() { return nested_type_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >& +DescriptorProto::nested_type() const { + return nested_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto >* +DescriptorProto::mutable_nested_type() { + return &nested_type_; +} // repeated .google.protobuf.EnumDescriptorProto enum_type = 4; inline int DescriptorProto::enum_type_size() const { @@ -2791,14 +2904,6 @@ inline int DescriptorProto::enum_type_size() const { inline void DescriptorProto::clear_enum_type() { enum_type_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& -DescriptorProto::enum_type() const { - return enum_type_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* -DescriptorProto::mutable_enum_type() { - return &enum_type_; -} inline const ::google::protobuf::EnumDescriptorProto& DescriptorProto::enum_type(int index) const { return enum_type_.Get(index); } @@ -2808,6 +2913,14 @@ inline ::google::protobuf::EnumDescriptorProto* DescriptorProto::mutable_enum_ty inline ::google::protobuf::EnumDescriptorProto* DescriptorProto::add_enum_type() { return enum_type_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >& +DescriptorProto::enum_type() const { + return enum_type_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumDescriptorProto >* +DescriptorProto::mutable_enum_type() { + return &enum_type_; +} // repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5; inline int DescriptorProto::extension_range_size() const { @@ -2816,14 +2929,6 @@ inline int DescriptorProto::extension_range_size() const { inline void DescriptorProto::clear_extension_range() { extension_range_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& -DescriptorProto::extension_range() const { - return extension_range_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* -DescriptorProto::mutable_extension_range() { - return &extension_range_; -} inline const ::google::protobuf::DescriptorProto_ExtensionRange& DescriptorProto::extension_range(int index) const { return extension_range_.Get(index); } @@ -2833,6 +2938,14 @@ inline ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::muta inline ::google::protobuf::DescriptorProto_ExtensionRange* DescriptorProto::add_extension_range() { return extension_range_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >& +DescriptorProto::extension_range() const { + return extension_range_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::DescriptorProto_ExtensionRange >* +DescriptorProto::mutable_extension_range() { + return &extension_range_; +} // optional .google.protobuf.MessageOptions options = 7; inline bool DescriptorProto::has_options() const { @@ -3143,14 +3256,6 @@ inline int EnumDescriptorProto::value_size() const { inline void EnumDescriptorProto::clear_value() { value_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& -EnumDescriptorProto::value() const { - return value_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* -EnumDescriptorProto::mutable_value() { - return &value_; -} inline const ::google::protobuf::EnumValueDescriptorProto& EnumDescriptorProto::value(int index) const { return value_.Get(index); } @@ -3160,6 +3265,14 @@ inline ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::mutabl inline ::google::protobuf::EnumValueDescriptorProto* EnumDescriptorProto::add_value() { return value_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >& +EnumDescriptorProto::value() const { + return value_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::EnumValueDescriptorProto >* +EnumDescriptorProto::mutable_value() { + return &value_; +} // optional .google.protobuf.EnumOptions options = 3; inline bool EnumDescriptorProto::has_options() const { @@ -3310,14 +3423,6 @@ inline int ServiceDescriptorProto::method_size() const { inline void ServiceDescriptorProto::clear_method() { method_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& -ServiceDescriptorProto::method() const { - return method_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* -ServiceDescriptorProto::mutable_method() { - return &method_; -} inline const ::google::protobuf::MethodDescriptorProto& ServiceDescriptorProto::method(int index) const { return method_.Get(index); } @@ -3327,6 +3432,14 @@ inline ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::mutabl inline ::google::protobuf::MethodDescriptorProto* ServiceDescriptorProto::add_method() { return method_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >& +ServiceDescriptorProto::method() const { + return method_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::MethodDescriptorProto >* +ServiceDescriptorProto::mutable_method() { + return &method_; +} // optional .google.protobuf.ServiceOptions options = 3; inline bool ServiceDescriptorProto::has_options() const { @@ -3613,6 +3726,54 @@ inline void FileOptions::set_optimize_for(::google::protobuf::FileOptions_Optimi optimize_for_ = value; } +// optional bool cc_generic_services = 16 [default = true]; +inline bool FileOptions::has_cc_generic_services() const { + return _has_bit(4); +} +inline void FileOptions::clear_cc_generic_services() { + cc_generic_services_ = true; + _clear_bit(4); +} +inline bool FileOptions::cc_generic_services() const { + return cc_generic_services_; +} +inline void FileOptions::set_cc_generic_services(bool value) { + _set_bit(4); + cc_generic_services_ = value; +} + +// optional bool java_generic_services = 17 [default = true]; +inline bool FileOptions::has_java_generic_services() const { + return _has_bit(5); +} +inline void FileOptions::clear_java_generic_services() { + java_generic_services_ = true; + _clear_bit(5); +} +inline bool FileOptions::java_generic_services() const { + return java_generic_services_; +} +inline void FileOptions::set_java_generic_services(bool value) { + _set_bit(5); + java_generic_services_ = value; +} + +// optional bool py_generic_services = 18 [default = true]; +inline bool FileOptions::has_py_generic_services() const { + return _has_bit(6); +} +inline void FileOptions::clear_py_generic_services() { + py_generic_services_ = true; + _clear_bit(6); +} +inline bool FileOptions::py_generic_services() const { + return py_generic_services_; +} +inline void FileOptions::set_py_generic_services(bool value) { + _set_bit(6); + py_generic_services_ = value; +} + // repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999; inline int FileOptions::uninterpreted_option_size() const { return uninterpreted_option_.size(); @@ -3620,14 +3781,6 @@ inline int FileOptions::uninterpreted_option_size() const { inline void FileOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -FileOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -FileOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& FileOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3637,6 +3790,14 @@ inline ::google::protobuf::UninterpretedOption* FileOptions::mutable_uninterpret inline ::google::protobuf::UninterpretedOption* FileOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +FileOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +FileOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -3681,14 +3842,6 @@ inline int MessageOptions::uninterpreted_option_size() const { inline void MessageOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -MessageOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -MessageOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& MessageOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3698,17 +3851,25 @@ inline ::google::protobuf::UninterpretedOption* MessageOptions::mutable_uninterp inline ::google::protobuf::UninterpretedOption* MessageOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +MessageOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +MessageOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- // FieldOptions -// optional .google.protobuf.FieldOptions.CType ctype = 1; +// optional .google.protobuf.FieldOptions.CType ctype = 1 [default = STRING]; inline bool FieldOptions::has_ctype() const { return _has_bit(0); } inline void FieldOptions::clear_ctype() { - ctype_ = 1; + ctype_ = 0; _clear_bit(0); } inline ::google::protobuf::FieldOptions_CType FieldOptions::ctype() const { @@ -3801,14 +3962,6 @@ inline int FieldOptions::uninterpreted_option_size() const { inline void FieldOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -FieldOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -FieldOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& FieldOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3818,6 +3971,14 @@ inline ::google::protobuf::UninterpretedOption* FieldOptions::mutable_uninterpre inline ::google::protobuf::UninterpretedOption* FieldOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +FieldOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +FieldOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -3830,14 +3991,6 @@ inline int EnumOptions::uninterpreted_option_size() const { inline void EnumOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -EnumOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -EnumOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& EnumOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3847,6 +4000,14 @@ inline ::google::protobuf::UninterpretedOption* EnumOptions::mutable_uninterpret inline ::google::protobuf::UninterpretedOption* EnumOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +EnumOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +EnumOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -3859,14 +4020,6 @@ inline int EnumValueOptions::uninterpreted_option_size() const { inline void EnumValueOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -EnumValueOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -EnumValueOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& EnumValueOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3876,6 +4029,14 @@ inline ::google::protobuf::UninterpretedOption* EnumValueOptions::mutable_uninte inline ::google::protobuf::UninterpretedOption* EnumValueOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +EnumValueOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +EnumValueOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -3888,14 +4049,6 @@ inline int ServiceOptions::uninterpreted_option_size() const { inline void ServiceOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -ServiceOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -ServiceOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& ServiceOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3905,6 +4058,14 @@ inline ::google::protobuf::UninterpretedOption* ServiceOptions::mutable_uninterp inline ::google::protobuf::UninterpretedOption* ServiceOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +ServiceOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +ServiceOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -3917,14 +4078,6 @@ inline int MethodOptions::uninterpreted_option_size() const { inline void MethodOptions::clear_uninterpreted_option() { uninterpreted_option_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& -MethodOptions::uninterpreted_option() const { - return uninterpreted_option_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* -MethodOptions::mutable_uninterpreted_option() { - return &uninterpreted_option_; -} inline const ::google::protobuf::UninterpretedOption& MethodOptions::uninterpreted_option(int index) const { return uninterpreted_option_.Get(index); } @@ -3934,6 +4087,14 @@ inline ::google::protobuf::UninterpretedOption* MethodOptions::mutable_uninterpr inline ::google::protobuf::UninterpretedOption* MethodOptions::add_uninterpreted_option() { return uninterpreted_option_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >& +MethodOptions::uninterpreted_option() const { + return uninterpreted_option_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption >* +MethodOptions::mutable_uninterpreted_option() { + return &uninterpreted_option_; +} // ------------------------------------------------------------------- @@ -4008,14 +4169,6 @@ inline int UninterpretedOption::name_size() const { inline void UninterpretedOption::clear_name() { name_.Clear(); } -inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& -UninterpretedOption::name() const { - return name_; -} -inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* -UninterpretedOption::mutable_name() { - return &name_; -} inline const ::google::protobuf::UninterpretedOption_NamePart& UninterpretedOption::name(int index) const { return name_.Get(index); } @@ -4025,6 +4178,14 @@ inline ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::mu inline ::google::protobuf::UninterpretedOption_NamePart* UninterpretedOption::add_name() { return name_.Add(); } +inline const ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >& +UninterpretedOption::name() const { + return name_; +} +inline ::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption_NamePart >* +UninterpretedOption::mutable_name() { + return &name_; +} // optional string identifier_value = 3; inline bool UninterpretedOption::has_identifier_value() const { @@ -4159,6 +4320,8 @@ inline ::std::string* UninterpretedOption::mutable_string_value() { } +// @@protoc_insertion_point(namespace_scope) + } // namespace protobuf } // namespace google @@ -4187,4 +4350,6 @@ inline const EnumDescriptor* GetEnumDescriptor< ::google::protobuf::FieldOptions } // namespace protobuf #endif // SWIG +// @@protoc_insertion_point(global_scope) + #endif // PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto index 4db88a82..cc04aa8e 100644 --- a/src/google/protobuf/descriptor.proto +++ b/src/google/protobuf/descriptor.proto @@ -256,6 +256,22 @@ message FileOptions { + + // Should generic services be generated in each language? "Generic" services + // are not specific to any particular RPC system. They are generated by the + // main code generators in each language (without additional plugins). + // Generic services were the only kind of service generation supported by + // early versions of proto2. + // + // Generic services are now considered deprecated in favor of using plugins + // that generate code specific to your particular RPC system. If you are + // using such a plugin, set these to false. In the future, we may change + // the default to false, so if you explicitly want generic services, you + // should explicitly set these to true. + optional bool cc_generic_services = 16 [default=true]; + optional bool java_generic_services = 17 [default=true]; + optional bool py_generic_services = 18 [default=true]; + // The parser stores options it doesn't recognize here. See above. repeated UninterpretedOption uninterpreted_option = 999; @@ -301,8 +317,11 @@ message FieldOptions { // representation of the field than it normally would. See the specific // options below. This option is not yet implemented in the open source // release -- sorry, we'll try to include it in a future version! - optional CType ctype = 1; + optional CType ctype = 1 [default = STRING]; enum CType { + // Default mode. + STRING = 0; + CORD = 1; STRING_PIECE = 2; @@ -313,6 +332,7 @@ message FieldOptions { // a single length-delimited blob. optional bool packed = 2; + // Is this field deprecated? // Depending on the target platform, this can emit Deprecated annotations // for accessors, or it will be completely ignored; in the very least, this diff --git a/src/google/protobuf/descriptor_database.cc b/src/google/protobuf/descriptor_database.cc index 6ea674d1..95708d94 100644 --- a/src/google/protobuf/descriptor_database.cc +++ b/src/google/protobuf/descriptor_database.cc @@ -37,6 +37,7 @@ #include #include +#include #include #include #include @@ -336,6 +337,35 @@ bool EncodedDescriptorDatabase::FindFileContainingSymbol( return MaybeParse(index_.FindSymbol(symbol_name), output); } +bool EncodedDescriptorDatabase::FindNameOfFileContainingSymbol( + const string& symbol_name, + string* output) { + pair encoded_file = index_.FindSymbol(symbol_name); + if (encoded_file.first == NULL) return false; + + // Optimization: The name should be the first field in the encoded message. + // Try to just read it directly. + io::CodedInputStream input(reinterpret_cast(encoded_file.first), + encoded_file.second); + + const uint32 kNameTag = internal::WireFormatLite::MakeTag( + FileDescriptorProto::kNameFieldNumber, + internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + + if (input.ReadTag() == kNameTag) { + // Success! + return internal::WireFormatLite::ReadString(&input, output); + } else { + // Slow path. Parse whole message. + FileDescriptorProto file_proto; + if (!file_proto.ParseFromArray(encoded_file.first, encoded_file.second)) { + return false; + } + *output = file_proto.name(); + return true; + } +} + bool EncodedDescriptorDatabase::FindFileContainingExtension( const string& containing_type, int field_number, diff --git a/src/google/protobuf/descriptor_database.h b/src/google/protobuf/descriptor_database.h index c23ab75f..f32b1db9 100644 --- a/src/google/protobuf/descriptor_database.h +++ b/src/google/protobuf/descriptor_database.h @@ -280,6 +280,10 @@ class LIBPROTOBUF_EXPORT EncodedDescriptorDatabase : public DescriptorDatabase { // need to keep it around. bool AddCopy(const void* encoded_file_descriptor, int size); + // Like FindFileContainingSymbol but returns only the name of the file. + bool FindNameOfFileContainingSymbol(const string& symbol_name, + string* output); + // implements DescriptorDatabase ----------------------------------- bool FindFileByName(const string& filename, FileDescriptorProto* output); diff --git a/src/google/protobuf/descriptor_database_unittest.cc b/src/google/protobuf/descriptor_database_unittest.cc index 33de1348..ac72ddcd 100644 --- a/src/google/protobuf/descriptor_database_unittest.cc +++ b/src/google/protobuf/descriptor_database_unittest.cc @@ -480,6 +480,40 @@ INSTANTIATE_TEST_CASE_P(Pool, DescriptorDatabaseTest, #endif // GTEST_HAS_PARAM_TEST +TEST(EncodedDescriptorDatabaseExtraTest, FindNameOfFileContainingSymbol) { + // Create two files, one of which is in two parts. + FileDescriptorProto file1, file2a, file2b; + file1.set_name("foo.proto"); + file1.set_package("foo"); + file1.add_message_type()->set_name("Foo"); + file2a.set_name("bar.proto"); + file2b.set_package("bar"); + file2b.add_message_type()->set_name("Bar"); + + // Normal serialization allows our optimization to kick in. + string data1 = file1.SerializeAsString(); + + // Force out-of-order serialization to test slow path. + string data2 = file2b.SerializeAsString() + file2a.SerializeAsString(); + + // Create EncodedDescriptorDatabase containing both files. + EncodedDescriptorDatabase db; + db.Add(data1.data(), data1.size()); + db.Add(data2.data(), data2.size()); + + // Test! + string filename; + EXPECT_TRUE(db.FindNameOfFileContainingSymbol("foo.Foo", &filename)); + EXPECT_EQ("foo.proto", filename); + EXPECT_TRUE(db.FindNameOfFileContainingSymbol("foo.Foo.Blah", &filename)); + EXPECT_EQ("foo.proto", filename); + EXPECT_TRUE(db.FindNameOfFileContainingSymbol("bar.Bar", &filename)); + EXPECT_EQ("bar.proto", filename); + EXPECT_FALSE(db.FindNameOfFileContainingSymbol("foo", &filename)); + EXPECT_FALSE(db.FindNameOfFileContainingSymbol("bar", &filename)); + EXPECT_FALSE(db.FindNameOfFileContainingSymbol("baz.Baz", &filename)); +} + // =================================================================== class MergedDescriptorDatabaseTest : public testing::Test { diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc index 8fcfba3e..ec2c8152 100644 --- a/src/google/protobuf/descriptor_unittest.cc +++ b/src/google/protobuf/descriptor_unittest.cc @@ -3948,6 +3948,9 @@ TEST_F(DatabaseBackedPoolTest, DoesntFallbackOnWrongType) { EXPECT_EQ(0, call_counter.call_count_); } +// =================================================================== + + } // namespace descriptor_unittest } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc index f8b5b4ea..c711a2da 100644 --- a/src/google/protobuf/dynamic_message.cc +++ b/src/google/protobuf/dynamic_message.cc @@ -106,7 +106,11 @@ int FieldSpaceUsed(const FieldDescriptor* field) { case FD::CPPTYPE_MESSAGE: return sizeof(RepeatedPtrField); case FD::CPPTYPE_STRING: - return sizeof(RepeatedPtrField); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return sizeof(RepeatedPtrField); + } break; } } else { @@ -122,7 +126,11 @@ int FieldSpaceUsed(const FieldDescriptor* field) { case FD::CPPTYPE_MESSAGE: return sizeof(Message*); case FD::CPPTYPE_STRING: - return sizeof(string*); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return sizeof(string*); + } break; } } @@ -262,19 +270,24 @@ DynamicMessage::DynamicMessage(const TypeInfo* type_info) break; case FieldDescriptor::CPPTYPE_STRING: - if (!field->is_repeated()) { - if (is_prototype()) { - new(field_ptr) const string*(&field->default_value_string()); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + if (!field->is_repeated()) { + if (is_prototype()) { + new(field_ptr) const string*(&field->default_value_string()); + } else { + string* default_value = + *reinterpret_cast( + type_info_->prototype->OffsetToPointer( + type_info_->offsets[i])); + new(field_ptr) string*(default_value); + } } else { - string* default_value = - *reinterpret_cast( - type_info_->prototype->OffsetToPointer( - type_info_->offsets[i])); - new(field_ptr) string*(default_value); + new(field_ptr) RepeatedPtrField(); } - } else { - new(field_ptr) RepeatedPtrField(); - } + break; + } break; case FieldDescriptor::CPPTYPE_MESSAGE: { @@ -329,8 +342,13 @@ DynamicMessage::~DynamicMessage() { #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_STRING: - reinterpret_cast*>(field_ptr) - ->~RepeatedPtrField(); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + reinterpret_cast*>(field_ptr) + ->~RepeatedPtrField(); + break; + } break; case FieldDescriptor::CPPTYPE_MESSAGE: @@ -340,10 +358,16 @@ DynamicMessage::~DynamicMessage() { } } else if (field->cpp_type() == FieldDescriptor::CPPTYPE_STRING) { - string* ptr = *reinterpret_cast(field_ptr); - if (ptr != &field->default_value_string()) { - delete ptr; + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: { + string* ptr = *reinterpret_cast(field_ptr); + if (ptr != &field->default_value_string()) { + delete ptr; + } + break; } + } } else if ((field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) && !is_prototype()) { Message* message = *reinterpret_cast(field_ptr); @@ -373,7 +397,7 @@ void DynamicMessage::CrossLinkPrototypes() { // For singular fields, the field is just a pointer which should // point to the prototype. *reinterpret_cast(field_ptr) = - factory->GetPrototype(field->message_type()); + factory->GetPrototypeNoLock(field->message_type()); } } } @@ -410,11 +434,13 @@ struct DynamicMessageFactory::PrototypeMap { }; DynamicMessageFactory::DynamicMessageFactory() - : pool_(NULL), prototypes_(new PrototypeMap) { + : pool_(NULL), delegate_to_generated_factory_(false), + prototypes_(new PrototypeMap) { } DynamicMessageFactory::DynamicMessageFactory(const DescriptorPool* pool) - : pool_(pool), prototypes_(new PrototypeMap) { + : pool_(pool), delegate_to_generated_factory_(false), + prototypes_(new PrototypeMap) { } DynamicMessageFactory::~DynamicMessageFactory() { @@ -424,8 +450,18 @@ DynamicMessageFactory::~DynamicMessageFactory() { } } - const Message* DynamicMessageFactory::GetPrototype(const Descriptor* type) { + MutexLock lock(&prototypes_mutex_); + return GetPrototypeNoLock(type); +} + +const Message* DynamicMessageFactory::GetPrototypeNoLock( + const Descriptor* type) { + if (delegate_to_generated_factory_ && + type->file()->pool() == DescriptorPool::generated_pool()) { + return MessageFactory::generated_factory()->GetPrototype(type); + } + const DynamicMessage::TypeInfo** target = &prototypes_->map_[type]; if (*target != NULL) { // Already exists. diff --git a/src/google/protobuf/dynamic_message.h b/src/google/protobuf/dynamic_message.h index f38d3b09..81dd2c63 100644 --- a/src/google/protobuf/dynamic_message.h +++ b/src/google/protobuf/dynamic_message.h @@ -73,9 +73,25 @@ class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory { // Construct a DynamicMessageFactory that will search for extensions in // the given DescriptorPool. + // + // DEPRECATED: Use CodedInputStream::SetExtensionRegistry() to tell the + // parser to look for extensions in an alternate pool. However, note that + // this is almost never what you want to do. Almost all users should use + // the zero-arg constructor. DynamicMessageFactory(const DescriptorPool* pool); + ~DynamicMessageFactory(); + // Call this to tell the DynamicMessageFactory that if it is given a + // Descriptor d for which: + // d->file()->pool() == DescriptorPool::generated_pool(), + // then it should delegate to MessageFactory::generated_factory() instead + // of constructing a dynamic implementation of the message. In theory there + // is no down side to doing this, so it may become the default in the future. + void SetDelegateToGeneratedFactory(bool enable) { + delegate_to_generated_factory_ = enable; + } + // implements MessageFactory --------------------------------------- // Given a Descriptor, constructs the default (prototype) Message of that @@ -92,14 +108,12 @@ class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory { // The given descriptor must outlive the returned message, and hence must // outlive the DynamicMessageFactory. // - // Note that while GetPrototype() is idempotent, it is not const. This - // implies that it is not thread-safe to call GetPrototype() on the same - // DynamicMessageFactory in two different threads simultaneously. However, - // the returned objects are just as thread-safe as any other Message. + // The method is thread-safe. const Message* GetPrototype(const Descriptor* type); private: const DescriptorPool* pool_; + bool delegate_to_generated_factory_; // This struct just contains a hash_map. We can't #include from // this header due to hacks needed for hash_map portability in the open source @@ -108,6 +122,10 @@ class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory { // headers may only #include other public headers. struct PrototypeMap; scoped_ptr prototypes_; + mutable Mutex prototypes_mutex_; + + friend class DynamicMessage; + const Message* GetPrototypeNoLock(const Descriptor* type); GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(DynamicMessageFactory); }; @@ -116,4 +134,3 @@ class LIBPROTOBUF_EXPORT DynamicMessageFactory : public MessageFactory { } // namespace google #endif // GOOGLE_PROTOBUF_DYNAMIC_MESSAGE_H__ - diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc index 4d5eb6cc..b1ffb0f5 100644 --- a/src/google/protobuf/extension_set.cc +++ b/src/google/protobuf/extension_set.cc @@ -59,24 +59,10 @@ inline WireFormatLite::CppType cpp_type(FieldType type) { } // Registry stuff. -struct ExtensionInfo { - inline ExtensionInfo(FieldType type, bool is_repeated, bool is_packed) - : type(type), is_repeated(is_repeated), is_packed(is_packed) {} - - FieldType type; - bool is_repeated; - bool is_packed; - - union { - ExtensionSet::EnumValidityFunc* enum_is_valid; - const MessageLite* message_prototype; - }; -}; - typedef hash_map, ExtensionInfo> ExtensionRegistry; ExtensionRegistry* registry_ = NULL; -GOOGLE_PROTOBUF_DECLARE_ONCE(registry_init_); +GoogleOnceType registry_init_; void DeleteRegistry() { delete registry_; @@ -110,6 +96,19 @@ const ExtensionInfo* FindRegisteredExtension( } // namespace +ExtensionFinder::~ExtensionFinder() {} + +bool GeneratedExtensionFinder::Find(int number, ExtensionInfo* output) { + const ExtensionInfo* extension = + FindRegisteredExtension(containing_type_, number); + if (extension == NULL) { + return false; + } else { + *output = *extension; + return true; + } +} + void ExtensionSet::RegisterExtension(const MessageLite* containing_type, int number, FieldType type, bool is_repeated, bool is_packed) { @@ -120,13 +119,18 @@ void ExtensionSet::RegisterExtension(const MessageLite* containing_type, Register(containing_type, number, info); } +static bool CallNoArgValidityFunc(const void* arg, int number) { + return reinterpret_cast(arg)(number); +} + void ExtensionSet::RegisterEnumExtension(const MessageLite* containing_type, int number, FieldType type, bool is_repeated, bool is_packed, EnumValidityFunc* is_valid) { GOOGLE_CHECK_EQ(type, WireFormatLite::TYPE_ENUM); ExtensionInfo info(type, is_repeated, is_packed); - info.enum_is_valid = is_valid; + info.enum_is_valid = CallNoArgValidityFunc; + info.enum_is_valid_arg = reinterpret_cast(is_valid); Register(containing_type, number, info); } @@ -211,9 +215,10 @@ LOWERCASE ExtensionSet::Get##CAMELCASE(int number, \ } \ \ void ExtensionSet::Set##CAMELCASE(int number, FieldType type, \ - LOWERCASE value) { \ + LOWERCASE value, \ + const FieldDescriptor* descriptor) { \ Extension* extension; \ - if (MaybeNewExtension(number, &extension)) { \ + if (MaybeNewExtension(number, descriptor, &extension)) { \ extension->type = type; \ GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_##UPPERCASE); \ extension->is_repeated = false; \ @@ -240,9 +245,10 @@ void ExtensionSet::SetRepeated##CAMELCASE( \ } \ \ void ExtensionSet::Add##CAMELCASE(int number, FieldType type, \ - bool packed, LOWERCASE value) { \ + bool packed, LOWERCASE value, \ + const FieldDescriptor* descriptor) { \ Extension* extension; \ - if (MaybeNewExtension(number, &extension)) { \ + if (MaybeNewExtension(number, descriptor, &extension)) { \ extension->type = type; \ GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_##UPPERCASE); \ extension->is_repeated = true; \ @@ -279,9 +285,10 @@ int ExtensionSet::GetEnum(int number, int default_value) const { } } -void ExtensionSet::SetEnum(int number, FieldType type, int value) { +void ExtensionSet::SetEnum(int number, FieldType type, int value, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM); extension->is_repeated = false; @@ -307,9 +314,10 @@ void ExtensionSet::SetRepeatedEnum(int number, int index, int value) { } void ExtensionSet::AddEnum(int number, FieldType type, - bool packed, int value) { + bool packed, int value, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_ENUM); extension->is_repeated = true; @@ -337,9 +345,10 @@ const string& ExtensionSet::GetString(int number, } } -string* ExtensionSet::MutableString(int number, FieldType type) { +string* ExtensionSet::MutableString(int number, FieldType type, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING); extension->is_repeated = false; @@ -365,9 +374,10 @@ string* ExtensionSet::MutableRepeatedString(int number, int index) { return iter->second.repeated_string_value->Mutable(index); } -string* ExtensionSet::AddString(int number, FieldType type) { +string* ExtensionSet::AddString(int number, FieldType type, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_STRING); extension->is_repeated = true; @@ -400,9 +410,10 @@ const MessageLite& ExtensionSet::GetMessage( // MessageFactory* factory) const MessageLite* ExtensionSet::MutableMessage(int number, FieldType type, - const MessageLite& prototype) { + const MessageLite& prototype, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); extension->is_repeated = false; @@ -435,9 +446,10 @@ MessageLite* ExtensionSet::MutableRepeatedMessage(int number, int index) { } MessageLite* ExtensionSet::AddMessage(int number, FieldType type, - const MessageLite& prototype) { + const MessageLite& prototype, + const FieldDescriptor* descriptor) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { + if (MaybeNewExtension(number, descriptor, &extension)) { extension->type = type; GOOGLE_DCHECK_EQ(cpp_type(extension->type), WireFormatLite::CPPTYPE_MESSAGE); extension->is_repeated = true; @@ -563,7 +575,8 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) { if (other_extension.is_repeated) { Extension* extension; - bool is_new = MaybeNewExtension(iter->first, &extension); + bool is_new = MaybeNewExtension(iter->first, other_extension.descriptor, + &extension); if (is_new) { // Extension did not already exist in set. extension->type = other_extension.type; @@ -622,7 +635,8 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE, CAMELCASE) \ case WireFormatLite::CPPTYPE_##UPPERCASE: \ Set##CAMELCASE(iter->first, other_extension.type, \ - other_extension.LOWERCASE##_value); \ + other_extension.LOWERCASE##_value, \ + other_extension.descriptor); \ break; HANDLE_TYPE( INT32, int32, Int32); @@ -636,11 +650,13 @@ void ExtensionSet::MergeFrom(const ExtensionSet& other) { #undef HANDLE_TYPE case WireFormatLite::CPPTYPE_STRING: SetString(iter->first, other_extension.type, - *other_extension.string_value); + *other_extension.string_value, + other_extension.descriptor); break; case WireFormatLite::CPPTYPE_MESSAGE: MutableMessage(iter->first, other_extension.type, - *other_extension.message_value) + *other_extension.message_value, + other_extension.descriptor) ->CheckTypeAndMergeFrom(*other_extension.message_value); break; } @@ -678,64 +694,66 @@ bool ExtensionSet::IsInitialized() const { } bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, - const MessageLite* containing_type, + ExtensionFinder* extension_finder, FieldSkipper* field_skipper) { int number = WireFormatLite::GetTagFieldNumber(tag); WireFormatLite::WireType wire_type = WireFormatLite::GetTagWireType(tag); - const ExtensionInfo* extension = - FindRegisteredExtension(containing_type, number); - + ExtensionInfo extension; bool is_unknown; - if (extension == NULL) { + if (!extension_finder->Find(number, &extension)) { is_unknown = true; - } else if (extension->is_packed) { + } else if (extension.is_packed) { is_unknown = (wire_type != WireFormatLite::WIRETYPE_LENGTH_DELIMITED); } else { WireFormatLite::WireType expected_wire_type = - WireFormatLite::WireTypeForFieldType(real_type(extension->type)); + WireFormatLite::WireTypeForFieldType(real_type(extension.type)); is_unknown = (wire_type != expected_wire_type); } if (is_unknown) { field_skipper->SkipField(input, tag); - } else if (extension->is_packed) { + } else if (extension.is_packed) { uint32 size; if (!input->ReadVarint32(&size)) return false; io::CodedInputStream::Limit limit = input->PushLimit(size); - switch (extension->type) { -#define HANDLE_TYPE(UPPERCASE, CAMELCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ + switch (extension.type) { +#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ case WireFormatLite::TYPE_##UPPERCASE: \ while (input->BytesUntilLimit() > 0) { \ CPP_LOWERCASE value; \ - if (!WireFormatLite::Read##CAMELCASE(input, &value)) return false; \ + if (!WireFormatLite::ReadPrimitive< \ + CPP_LOWERCASE, WireFormatLite::TYPE_##UPPERCASE>( \ + input, &value)) return false; \ Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \ - true, value); \ + true, value, extension.descriptor); \ } \ break - HANDLE_TYPE( INT32, Int32, Int32, int32); - HANDLE_TYPE( INT64, Int64, Int64, int64); - HANDLE_TYPE( UINT32, UInt32, UInt32, uint32); - HANDLE_TYPE( UINT64, UInt64, UInt64, uint64); - HANDLE_TYPE( SINT32, SInt32, Int32, int32); - HANDLE_TYPE( SINT64, SInt64, Int64, int64); - HANDLE_TYPE( FIXED32, Fixed32, UInt32, uint32); - HANDLE_TYPE( FIXED64, Fixed64, UInt64, uint64); - HANDLE_TYPE(SFIXED32, SFixed32, Int32, int32); - HANDLE_TYPE(SFIXED64, SFixed64, Int64, int64); - HANDLE_TYPE( FLOAT, Float, Float, float); - HANDLE_TYPE( DOUBLE, Double, Double, double); - HANDLE_TYPE( BOOL, Bool, Bool, bool); + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, Int32, int32); + HANDLE_TYPE( SINT64, Int64, int64); + HANDLE_TYPE( FIXED32, UInt32, uint32); + HANDLE_TYPE( FIXED64, UInt64, uint64); + HANDLE_TYPE(SFIXED32, Int32, int32); + HANDLE_TYPE(SFIXED64, Int64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); #undef HANDLE_TYPE case WireFormatLite::TYPE_ENUM: while (input->BytesUntilLimit() > 0) { int value; - if (!WireFormatLite::ReadEnum(input, &value)) return false; - if (extension->enum_is_valid(value)) { - AddEnum(number, WireFormatLite::TYPE_ENUM, true, value); + if (!WireFormatLite::ReadPrimitive( + input, &value)) return false; + if (extension.enum_is_valid(extension.enum_is_valid_arg, value)) { + AddEnum(number, WireFormatLite::TYPE_ENUM, true, value, + extension.descriptor); } } break; @@ -750,81 +768,89 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, input->PopLimit(limit); } else { - switch (extension->type) { -#define HANDLE_TYPE(UPPERCASE, CAMELCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ + switch (extension.type) { +#define HANDLE_TYPE(UPPERCASE, CPP_CAMELCASE, CPP_LOWERCASE) \ case WireFormatLite::TYPE_##UPPERCASE: { \ CPP_LOWERCASE value; \ - if (!WireFormatLite::Read##CAMELCASE(input, &value)) return false; \ - if (extension->is_repeated) { \ + if (!WireFormatLite::ReadPrimitive< \ + CPP_LOWERCASE, WireFormatLite::TYPE_##UPPERCASE>( \ + input, &value)) return false; \ + if (extension.is_repeated) { \ Add##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, \ - false, value); \ + false, value, extension.descriptor); \ } else { \ - Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value); \ + Set##CPP_CAMELCASE(number, WireFormatLite::TYPE_##UPPERCASE, value, \ + extension.descriptor); \ } \ } break - HANDLE_TYPE( INT32, Int32, Int32, int32); - HANDLE_TYPE( INT64, Int64, Int64, int64); - HANDLE_TYPE( UINT32, UInt32, UInt32, uint32); - HANDLE_TYPE( UINT64, UInt64, UInt64, uint64); - HANDLE_TYPE( SINT32, SInt32, Int32, int32); - HANDLE_TYPE( SINT64, SInt64, Int64, int64); - HANDLE_TYPE( FIXED32, Fixed32, UInt32, uint32); - HANDLE_TYPE( FIXED64, Fixed64, UInt64, uint64); - HANDLE_TYPE(SFIXED32, SFixed32, Int32, int32); - HANDLE_TYPE(SFIXED64, SFixed64, Int64, int64); - HANDLE_TYPE( FLOAT, Float, Float, float); - HANDLE_TYPE( DOUBLE, Double, Double, double); - HANDLE_TYPE( BOOL, Bool, Bool, bool); + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, Int32, int32); + HANDLE_TYPE( SINT64, Int64, int64); + HANDLE_TYPE( FIXED32, UInt32, uint32); + HANDLE_TYPE( FIXED64, UInt64, uint64); + HANDLE_TYPE(SFIXED32, Int32, int32); + HANDLE_TYPE(SFIXED64, Int64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); #undef HANDLE_TYPE case WireFormatLite::TYPE_ENUM: { int value; - if (!WireFormatLite::ReadEnum(input, &value)) return false; + if (!WireFormatLite::ReadPrimitive( + input, &value)) return false; - if (!extension->enum_is_valid(value)) { + if (!extension.enum_is_valid(extension.enum_is_valid_arg, value)) { // Invalid value. Treat as unknown. field_skipper->SkipUnknownEnum(number, value); - } else if (extension->is_repeated) { - AddEnum(number, WireFormatLite::TYPE_ENUM, false, value); + } else if (extension.is_repeated) { + AddEnum(number, WireFormatLite::TYPE_ENUM, false, value, + extension.descriptor); } else { - SetEnum(number, WireFormatLite::TYPE_ENUM, value); + SetEnum(number, WireFormatLite::TYPE_ENUM, value, + extension.descriptor); } break; } case WireFormatLite::TYPE_STRING: { - string* value = extension->is_repeated ? - AddString(number, WireFormatLite::TYPE_STRING) : - MutableString(number, WireFormatLite::TYPE_STRING); + string* value = extension.is_repeated ? + AddString(number, WireFormatLite::TYPE_STRING, extension.descriptor) : + MutableString(number, WireFormatLite::TYPE_STRING, + extension.descriptor); if (!WireFormatLite::ReadString(input, value)) return false; break; } case WireFormatLite::TYPE_BYTES: { - string* value = extension->is_repeated ? - AddString(number, WireFormatLite::TYPE_STRING) : - MutableString(number, WireFormatLite::TYPE_STRING); + string* value = extension.is_repeated ? + AddString(number, WireFormatLite::TYPE_STRING, extension.descriptor) : + MutableString(number, WireFormatLite::TYPE_STRING, + extension.descriptor); if (!WireFormatLite::ReadBytes(input, value)) return false; break; } case WireFormatLite::TYPE_GROUP: { - MessageLite* value = extension->is_repeated ? + MessageLite* value = extension.is_repeated ? AddMessage(number, WireFormatLite::TYPE_GROUP, - *extension->message_prototype) : + *extension.message_prototype, extension.descriptor) : MutableMessage(number, WireFormatLite::TYPE_GROUP, - *extension->message_prototype); + *extension.message_prototype, extension.descriptor); if (!WireFormatLite::ReadGroup(number, input, value)) return false; break; } case WireFormatLite::TYPE_MESSAGE: { - MessageLite* value = extension->is_repeated ? + MessageLite* value = extension.is_repeated ? AddMessage(number, WireFormatLite::TYPE_MESSAGE, - *extension->message_prototype) : + *extension.message_prototype, extension.descriptor) : MutableMessage(number, WireFormatLite::TYPE_MESSAGE, - *extension->message_prototype); + *extension.message_prototype, extension.descriptor); if (!WireFormatLite::ReadMessage(input, value)) return false; break; } @@ -837,7 +863,8 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, const MessageLite* containing_type) { FieldSkipper skipper; - return ParseField(tag, input, containing_type, &skipper); + GeneratedExtensionFinder finder(containing_type); + return ParseField(tag, input, &finder, &skipper); } // Defined in extension_set_heavy.cc. @@ -846,7 +873,7 @@ bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, // UnknownFieldSet* unknown_fields) bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, - const MessageLite* containing_type, + ExtensionFinder* extension_finder, FieldSkipper* field_skipper) { while (true) { uint32 tag = input->ReadTag(); @@ -854,12 +881,12 @@ bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, case 0: return true; case WireFormatLite::kMessageSetItemStartTag: - if (!ParseMessageSetItem(input, containing_type, field_skipper)) { + if (!ParseMessageSetItem(input, extension_finder, field_skipper)) { return false; } break; default: - if (!ParseField(tag, input, containing_type, field_skipper)) { + if (!ParseField(tag, input, extension_finder, field_skipper)) { return false; } break; @@ -870,7 +897,8 @@ bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, const MessageLite* containing_type) { FieldSkipper skipper; - return ParseMessageSet(input, containing_type, &skipper); + GeneratedExtensionFinder finder(containing_type); + return ParseMessageSet(input, &finder, &skipper); } // Defined in extension_set_heavy.cc. @@ -879,7 +907,7 @@ bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, // UnknownFieldSet* unknown_fields); bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input, - const MessageLite* containing_type, + ExtensionFinder* extension_finder, FieldSkipper* field_skipper) { // TODO(kenton): It would be nice to share code between this and // WireFormatLite::ParseAndMergeMessageSetItem(), but I think the @@ -919,7 +947,7 @@ bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input, reinterpret_cast(message_data.data()), message_data.size()); if (!ParseField(fake_tag, &sub_input, - containing_type, field_skipper)) { + extension_finder, field_skipper)) { return false; } message_data.clear(); @@ -939,7 +967,7 @@ bool ExtensionSet::ParseMessageSetItem(io::CodedInputStream* input, } else { // Already saw type_id, so we can parse this directly. if (!ParseField(fake_tag, input, - containing_type, field_skipper)) { + extension_finder, field_skipper)) { return false; } } @@ -969,26 +997,6 @@ void ExtensionSet::SerializeWithCachedSizes( } } -uint8* ExtensionSet::SerializeWithCachedSizesToArray( - int start_field_number, int end_field_number, - uint8* target) const { - // For now, just create an array output stream around the target and dispatch - // to SerializeWithCachedSizes(). Give the array output stream kint32max - // bytes; we will certainly write less than that. It is up to the caller to - // ensure that the buffer has sufficient space. - int written_bytes; - { - io::ArrayOutputStream array_stream(target, kint32max); - io::CodedOutputStream output_stream(&array_stream); - SerializeWithCachedSizes(start_field_number, - end_field_number, - &output_stream); - written_bytes = output_stream.ByteCount(); - GOOGLE_DCHECK(!output_stream.HadError()); - } - return target + written_bytes; -} - void ExtensionSet::SerializeMessageSetWithCachedSizes( io::CodedOutputStream* output) const { map::const_iterator iter; @@ -997,23 +1005,6 @@ void ExtensionSet::SerializeMessageSetWithCachedSizes( } } -uint8* ExtensionSet::SerializeMessageSetWithCachedSizesToArray( - uint8* target) const { - // For now, just create an array output stream around the target and dispatch - // to SerializeWithCachedSizes(). Give the array output stream kint32max - // bytes; we will certainly write less than that. It is up to the caller to - // ensure that the buffer has sufficient space. - int written_bytes; - { - io::ArrayOutputStream array_stream(target, kint32max); - io::CodedOutputStream output_stream(&array_stream); - SerializeMessageSetWithCachedSizes(&output_stream); - written_bytes = output_stream.ByteCount(); - GOOGLE_DCHECK(!output_stream.HadError()); - } - return target + written_bytes; -} - int ExtensionSet::ByteSize() const { int total_size = 0; @@ -1039,10 +1030,13 @@ int ExtensionSet::MessageSetByteSize() const { // Defined in extension_set_heavy.cc. // int ExtensionSet::SpaceUsedExcludingSelf() const -bool ExtensionSet::MaybeNewExtension(int number, Extension** result) { +bool ExtensionSet::MaybeNewExtension(int number, + const FieldDescriptor* descriptor, + Extension** result) { pair::iterator, bool> insert_result = extensions_.insert(make_pair(number, Extension())); *result = &insert_result.first->second; + (*result)->descriptor = descriptor; return insert_result.second; } @@ -1206,20 +1200,20 @@ void ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizes( if (is_cleared) return; // Start group. - output->WriteVarint32(WireFormatLite::kMessageSetItemStartTag); + output->WriteTag(WireFormatLite::kMessageSetItemStartTag); // Write type ID. - output->WriteVarint32(WireFormatLite::kMessageSetTypeIdTag); - output->WriteVarint32(number); - + WireFormatLite::WriteUInt32(WireFormatLite::kMessageSetTypeIdNumber, + number, + output); // Write message. - output->WriteVarint32(WireFormatLite::kMessageSetMessageTag); - - output->WriteVarint32(message_value->GetCachedSize()); - message_value->SerializeWithCachedSizes(output); + WireFormatLite::WriteMessageMaybeToArray( + WireFormatLite::kMessageSetMessageNumber, + *message_value, + output); // End group. - output->WriteVarint32(WireFormatLite::kMessageSetItemEndTag); + output->WriteTag(WireFormatLite::kMessageSetItemEndTag); } int ExtensionSet::Extension::ByteSize(int number) const { diff --git a/src/google/protobuf/extension_set.h b/src/google/protobuf/extension_set.h index e5ac277e..b1a55338 100644 --- a/src/google/protobuf/extension_set.h +++ b/src/google/protobuf/extension_set.h @@ -53,6 +53,7 @@ namespace protobuf { class FieldDescriptor; // descriptor.h class DescriptorPool; // descriptor.h class MessageLite; // message_lite.h + class Message; // message.h class MessageFactory; // message.h class UnknownFieldSet; // unknown_field_set.h namespace io { @@ -76,6 +77,84 @@ namespace internal { // ExtensionSet::Extension small. typedef uint8 FieldType; +// A function which, given an integer value, returns true if the number +// matches one of the defined values for the corresponding enum type. This +// is used with RegisterEnumExtension, below. +typedef bool EnumValidityFunc(int number); + +// Version of the above which takes an argument. This is needed to deal with +// extensions that are not compiled in. +typedef bool EnumValidityFuncWithArg(const void* arg, int number); + +// Information about a registered extension. +struct ExtensionInfo { + inline ExtensionInfo() {} + inline ExtensionInfo(FieldType type, bool is_repeated, bool is_packed) + : type(type), is_repeated(is_repeated), is_packed(is_packed), + descriptor(NULL) {} + + FieldType type; + bool is_repeated; + bool is_packed; + + union { + struct { + EnumValidityFuncWithArg* enum_is_valid; + const void* enum_is_valid_arg; + }; + const MessageLite* message_prototype; + }; + + // The descriptor for this extension, if one exists and is known. May be + // NULL. Must not be NULL if the descriptor for the extension does not + // live in the same pool as the descriptor for the containing type. + const FieldDescriptor* descriptor; +}; + +// Abstract interface for an object which looks up extension definitions. Used +// when parsing. +class LIBPROTOBUF_EXPORT ExtensionFinder { + public: + virtual ~ExtensionFinder(); + + // Find the extension with the given containing type and number. + virtual bool Find(int number, ExtensionInfo* output) = 0; +}; + +// Implementation of ExtensionFinder which finds extensions defined in .proto +// files which have been compiled into the binary. +class LIBPROTOBUF_EXPORT GeneratedExtensionFinder : public ExtensionFinder { + public: + GeneratedExtensionFinder(const MessageLite* containing_type) + : containing_type_(containing_type) {} + virtual ~GeneratedExtensionFinder() {} + + // Returns true and fills in *output if found, otherwise returns false. + virtual bool Find(int number, ExtensionInfo* output); + + private: + const MessageLite* containing_type_; +}; + +// Implementation of ExtensionFinder which finds extensions in a given +// DescriptorPool, using the given MessageFactory to construct sub-objects. +// This class is implemented in extension_set_heavy.cc. +class LIBPROTOBUF_EXPORT DescriptorPoolExtensionFinder : public ExtensionFinder { + public: + DescriptorPoolExtensionFinder(const DescriptorPool* pool, + MessageFactory* factory, + const Descriptor* containing_type) + : pool_(pool), factory_(factory), containing_type_(containing_type) {} + virtual ~DescriptorPoolExtensionFinder() {} + + virtual bool Find(int number, ExtensionInfo* output); + + private: + const DescriptorPool* pool_; + MessageFactory* factory_; + const Descriptor* containing_type_; +}; + // This is an internal helper class intended for use within the protocol buffer // library and generated classes. Clients should not use it directly. Instead, // use the generated accessors such as GetExtension() of the class being @@ -92,11 +171,6 @@ class LIBPROTOBUF_EXPORT ExtensionSet { ExtensionSet(); ~ExtensionSet(); - // A function which, given an integer value, returns true if the number - // matches one of the defined values for the corresponding enum type. This - // is used with RegisterEnumExtension, below. - typedef bool EnumValidityFunc(int number); - // These are called at startup by protocol-compiler-generated code to // register known extensions. The registrations are used by ParseField() // to look up extensions for parsed field numbers. Note that dynamic parsing @@ -117,11 +191,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // ================================================================= // Add all fields which are currently present to the given vector. This - // is useful to implement Reflection::ListFields(). The FieldDescriptors - // are looked up by number from the given pool. - // - // TODO(kenton): Looking up each field by number is somewhat unfortunate. - // Is there a better way? + // is useful to implement Reflection::ListFields(). void AppendToList(const Descriptor* containing_type, const DescriptorPool* pool, vector* output) const; @@ -176,21 +246,25 @@ class LIBPROTOBUF_EXPORT ExtensionSet { const MessageLite& GetMessage(int number, const Descriptor* message_type, MessageFactory* factory) const; - void SetInt32 (int number, FieldType type, int32 value); - void SetInt64 (int number, FieldType type, int64 value); - void SetUInt32(int number, FieldType type, uint32 value); - void SetUInt64(int number, FieldType type, uint64 value); - void SetFloat (int number, FieldType type, float value); - void SetDouble(int number, FieldType type, double value); - void SetBool (int number, FieldType type, bool value); - void SetEnum (int number, FieldType type, int value); - void SetString(int number, FieldType type, const string& value); - string * MutableString (int number, FieldType type); - MessageLite* MutableMessage(int number, FieldType type, - const MessageLite& prototype); + // |descriptor| may be NULL so long as it is known that the descriptor for + // the extension lives in the same pool as the descriptor for the containing + // type. +#define desc const FieldDescriptor* descriptor // avoid line wrapping + void SetInt32 (int number, FieldType type, int32 value, desc); + void SetInt64 (int number, FieldType type, int64 value, desc); + void SetUInt32(int number, FieldType type, uint32 value, desc); + void SetUInt64(int number, FieldType type, uint64 value, desc); + void SetFloat (int number, FieldType type, float value, desc); + void SetDouble(int number, FieldType type, double value, desc); + void SetBool (int number, FieldType type, bool value, desc); + void SetEnum (int number, FieldType type, int value, desc); + void SetString(int number, FieldType type, const string& value, desc); + string * MutableString (int number, FieldType type, desc); MessageLite* MutableMessage(int number, FieldType type, - const Descriptor* message_type, + const MessageLite& prototype, desc); + MessageLite* MutableMessage(const FieldDescriptor* decsriptor, MessageFactory* factory); +#undef desc // repeated fields ------------------------------------------------- @@ -217,21 +291,22 @@ class LIBPROTOBUF_EXPORT ExtensionSet { string * MutableRepeatedString (int number, int index); MessageLite* MutableRepeatedMessage(int number, int index); - void AddInt32 (int number, FieldType type, bool packed, int32 value); - void AddInt64 (int number, FieldType type, bool packed, int64 value); - void AddUInt32(int number, FieldType type, bool packed, uint32 value); - void AddUInt64(int number, FieldType type, bool packed, uint64 value); - void AddFloat (int number, FieldType type, bool packed, float value); - void AddDouble(int number, FieldType type, bool packed, double value); - void AddBool (int number, FieldType type, bool packed, bool value); - void AddEnum (int number, FieldType type, bool packed, int value); - void AddString(int number, FieldType type, const string& value); - string * AddString (int number, FieldType type); +#define desc const FieldDescriptor* descriptor // avoid line wrapping + void AddInt32 (int number, FieldType type, bool packed, int32 value, desc); + void AddInt64 (int number, FieldType type, bool packed, int64 value, desc); + void AddUInt32(int number, FieldType type, bool packed, uint32 value, desc); + void AddUInt64(int number, FieldType type, bool packed, uint64 value, desc); + void AddFloat (int number, FieldType type, bool packed, float value, desc); + void AddDouble(int number, FieldType type, bool packed, double value, desc); + void AddBool (int number, FieldType type, bool packed, bool value, desc); + void AddEnum (int number, FieldType type, bool packed, int value, desc); + void AddString(int number, FieldType type, const string& value, desc); + string * AddString (int number, FieldType type, desc); MessageLite* AddMessage(int number, FieldType type, - const MessageLite& prototype); - MessageLite* AddMessage(int number, FieldType type, - const Descriptor* message_type, + const MessageLite& prototype, desc); + MessageLite* AddMessage(const FieldDescriptor* descriptor, MessageFactory* factory); +#undef desc void RemoveLast(int number); void SwapElements(int number, int index1, int index2); @@ -257,7 +332,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // methods of ExtensionSet, this only works for generated message types -- // it looks up extensions registered using RegisterExtension(). bool ParseField(uint32 tag, io::CodedInputStream* input, - const MessageLite* containing_type, + ExtensionFinder* extension_finder, FieldSkipper* field_skipper); // Specific versions for lite or full messages (constructs the appropriate @@ -265,13 +340,13 @@ class LIBPROTOBUF_EXPORT ExtensionSet { bool ParseField(uint32 tag, io::CodedInputStream* input, const MessageLite* containing_type); bool ParseField(uint32 tag, io::CodedInputStream* input, - const MessageLite* containing_type, + const Message* containing_type, UnknownFieldSet* unknown_fields); // Parse an entire message in MessageSet format. Such messages have no // fields, only extensions. bool ParseMessageSet(io::CodedInputStream* input, - const MessageLite* containing_type, + ExtensionFinder* extension_finder, FieldSkipper* field_skipper); // Specific versions for lite or full messages (constructs the appropriate @@ -279,7 +354,7 @@ class LIBPROTOBUF_EXPORT ExtensionSet { bool ParseMessageSet(io::CodedInputStream* input, const MessageLite* containing_type); bool ParseMessageSet(io::CodedInputStream* input, - const MessageLite* containing_type, + const Message* containing_type, UnknownFieldSet* unknown_fields); // Write all extension fields with field numbers in the range @@ -359,6 +434,11 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // For repeated types, this indicates if the [packed=true] option is set. bool is_packed; + // The descriptor for this extension, if one exists and is known. May be + // NULL. Must not be NULL if the descriptor for the extension does not + // live in the same pool as the descriptor for the containing type. + const FieldDescriptor* descriptor; + // For packed fields, the size of the packed data is recorded here when // ByteSize() is called then used during serialization. // TODO(kenton): Use atomic when C++ supports it. @@ -368,9 +448,15 @@ class LIBPROTOBUF_EXPORT ExtensionSet { void SerializeFieldWithCachedSizes( int number, io::CodedOutputStream* output) const; + uint8* SerializeFieldWithCachedSizesToArray( + int number, + uint8* target) const; void SerializeMessageSetItemWithCachedSizes( int number, io::CodedOutputStream* output) const; + uint8* SerializeMessageSetItemWithCachedSizesToArray( + int number, + uint8* target) const; int ByteSize(int number) const; int MessageSetItemByteSize(int number) const; void Clear(); @@ -381,14 +467,16 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // Gets the extension with the given number, creating it if it does not // already exist. Returns true if the extension did not already exist. - bool MaybeNewExtension(int number, Extension** result); + bool MaybeNewExtension(int number, const FieldDescriptor* descriptor, + Extension** result); // Parse a single MessageSet item -- called just after the item group start // tag has been read. bool ParseMessageSetItem(io::CodedInputStream* input, - const MessageLite* containing_type, + ExtensionFinder* extension_finder, FieldSkipper* field_skipper); + // Hack: RepeatedPtrFieldBase declares ExtensionSet as a friend. This // friendship should automatically extend to ExtensionSet::Extension, but // unfortunately some older compilers (e.g. GCC 3.4.4) do not implement this @@ -412,16 +500,18 @@ class LIBPROTOBUF_EXPORT ExtensionSet { // These are just for convenience... inline void ExtensionSet::SetString(int number, FieldType type, - const string& value) { - MutableString(number, type)->assign(value); + const string& value, + const FieldDescriptor* descriptor) { + MutableString(number, type, descriptor)->assign(value); } inline void ExtensionSet::SetRepeatedString(int number, int index, const string& value) { MutableRepeatedString(number, index)->assign(value); } inline void ExtensionSet::AddString(int number, FieldType type, - const string& value) { - AddString(number, type)->assign(value); + const string& value, + const FieldDescriptor* descriptor) { + AddString(number, type, descriptor)->assign(value); } // =================================================================== @@ -502,7 +592,7 @@ template<> inline TYPE PrimitiveTypeTraits::Get( \ } \ template<> inline void PrimitiveTypeTraits::Set( \ int number, FieldType field_type, TYPE value, ExtensionSet* set) { \ - set->Set##METHOD(number, field_type, value); \ + set->Set##METHOD(number, field_type, value, NULL); \ } \ \ template<> inline TYPE RepeatedPrimitiveTypeTraits::Get( \ @@ -516,7 +606,7 @@ template<> inline void RepeatedPrimitiveTypeTraits::Set( \ template<> inline void RepeatedPrimitiveTypeTraits::Add( \ int number, FieldType field_type, bool is_packed, \ TYPE value, ExtensionSet* set) { \ - set->Add##METHOD(number, field_type, is_packed, value); \ + set->Add##METHOD(number, field_type, is_packed, value, NULL); \ } PROTOBUF_DEFINE_PRIMITIVE_TYPE( int32, Int32) @@ -544,11 +634,11 @@ class LIBPROTOBUF_EXPORT StringTypeTraits { } static inline void Set(int number, FieldType field_type, const string& value, ExtensionSet* set) { - set->SetString(number, field_type, value); + set->SetString(number, field_type, value, NULL); } static inline string* Mutable(int number, FieldType field_type, ExtensionSet* set) { - return set->MutableString(number, field_type); + return set->MutableString(number, field_type, NULL); } }; @@ -571,11 +661,11 @@ class LIBPROTOBUF_EXPORT RepeatedStringTypeTraits { static inline void Add(int number, FieldType field_type, bool /*is_packed*/, const string& value, ExtensionSet* set) { - set->AddString(number, field_type, value); + set->AddString(number, field_type, value, NULL); } static inline string* Add(int number, FieldType field_type, ExtensionSet* set) { - return set->AddString(number, field_type); + return set->AddString(number, field_type, NULL); } }; @@ -596,7 +686,7 @@ class EnumTypeTraits { static inline void Set(int number, FieldType field_type, ConstType value, ExtensionSet* set) { GOOGLE_DCHECK(IsValid(value)); - set->SetEnum(number, field_type, value); + set->SetEnum(number, field_type, value, NULL); } }; @@ -616,7 +706,7 @@ class RepeatedEnumTypeTraits { static inline void Add(int number, FieldType field_type, bool is_packed, ConstType value, ExtensionSet* set) { GOOGLE_DCHECK(IsValid(value)); - set->AddEnum(number, field_type, is_packed, value); + set->AddEnum(number, field_type, is_packed, value, NULL); } }; @@ -640,7 +730,7 @@ class MessageTypeTraits { static inline MutableType Mutable(int number, FieldType field_type, ExtensionSet* set) { return static_cast( - set->MutableMessage(number, field_type, Type::default_instance())); + set->MutableMessage(number, field_type, Type::default_instance(), NULL)); } }; @@ -659,7 +749,7 @@ class RepeatedMessageTypeTraits { static inline MutableType Add(int number, FieldType field_type, ExtensionSet* set) { return static_cast( - set->AddMessage(number, field_type, Type::default_instance())); + set->AddMessage(number, field_type, Type::default_instance(), NULL)); } }; diff --git a/src/google/protobuf/extension_set_heavy.cc b/src/google/protobuf/extension_set_heavy.cc index 8555f6f8..426ec5f4 100644 --- a/src/google/protobuf/extension_set_heavy.cc +++ b/src/google/protobuf/extension_set_heavy.cc @@ -40,6 +40,7 @@ #include #include #include +#include namespace google { namespace protobuf { @@ -58,12 +59,26 @@ void ExtensionSet::AppendToList(const Descriptor* containing_type, } if (has) { - output->push_back( - pool->FindExtensionByNumber(containing_type, iter->first)); + // TODO(kenton): Looking up each field by number is somewhat unfortunate. + // Is there a better way? The problem is that descriptors are lazily- + // initialized, so they might not even be constructed until + // AppendToList() is called. + + if (iter->second.descriptor == NULL) { + output->push_back(pool->FindExtensionByNumber( + containing_type, iter->first)); + } else { + output->push_back(iter->second.descriptor); + } } } } +inline FieldDescriptor::Type real_type(FieldType type) { + GOOGLE_DCHECK(type > 0 && type <= FieldDescriptor::MAX_TYPE); + return static_cast(type); +} + inline FieldDescriptor::CppType cpp_type(FieldType type) { return FieldDescriptor::TypeToCppType( static_cast(type)); @@ -88,16 +103,16 @@ const MessageLite& ExtensionSet::GetMessage(int number, } } -MessageLite* ExtensionSet::MutableMessage(int number, FieldType type, - const Descriptor* message_type, +MessageLite* ExtensionSet::MutableMessage(const FieldDescriptor* descriptor, MessageFactory* factory) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { - extension->type = type; + if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) { + extension->type = descriptor->type(); GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); extension->is_repeated = false; extension->is_packed = false; - const MessageLite* prototype = factory->GetPrototype(message_type); + const MessageLite* prototype = + factory->GetPrototype(descriptor->message_type()); GOOGLE_CHECK(prototype != NULL); extension->message_value = prototype->New(); } else { @@ -107,12 +122,11 @@ MessageLite* ExtensionSet::MutableMessage(int number, FieldType type, return extension->message_value; } -MessageLite* ExtensionSet::AddMessage(int number, FieldType type, - const Descriptor* message_type, +MessageLite* ExtensionSet::AddMessage(const FieldDescriptor* descriptor, MessageFactory* factory) { Extension* extension; - if (MaybeNewExtension(number, &extension)) { - extension->type = type; + if (MaybeNewExtension(descriptor->number(), descriptor, &extension)) { + extension->type = descriptor->type(); GOOGLE_DCHECK_EQ(cpp_type(extension->type), FieldDescriptor::CPPTYPE_MESSAGE); extension->is_repeated = true; extension->repeated_message_value = @@ -128,7 +142,7 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type, if (result == NULL) { const MessageLite* prototype; if (extension->repeated_message_value->size() == 0) { - prototype = factory->GetPrototype(message_type); + prototype = factory->GetPrototype(descriptor->message_type()); GOOGLE_CHECK(prototype != NULL); } else { prototype = &extension->repeated_message_value->Get(0); @@ -139,18 +153,64 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type, return result; } +static bool ValidateEnumUsingDescriptor(const void* arg, int number) { + return reinterpret_cast(arg) + ->FindValueByNumber(number) != NULL; +} + +bool DescriptorPoolExtensionFinder::Find(int number, ExtensionInfo* output) { + const FieldDescriptor* extension = + pool_->FindExtensionByNumber(containing_type_, number); + if (extension == NULL) { + return false; + } else { + output->type = extension->type(); + output->is_repeated = extension->is_repeated(); + output->is_packed = extension->options().packed(); + output->descriptor = extension; + if (extension->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + output->message_prototype = + factory_->GetPrototype(extension->message_type()); + GOOGLE_CHECK(output->message_prototype != NULL) + << "Extension factory's GetPrototype() returned NULL for extension: " + << extension->full_name(); + } else if (extension->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + output->enum_is_valid = ValidateEnumUsingDescriptor; + output->enum_is_valid_arg = extension->enum_type(); + } + + return true; + } +} + bool ExtensionSet::ParseField(uint32 tag, io::CodedInputStream* input, - const MessageLite* containing_type, + const Message* containing_type, UnknownFieldSet* unknown_fields) { UnknownFieldSetFieldSkipper skipper(unknown_fields); - return ParseField(tag, input, containing_type, &skipper); + if (input->GetExtensionPool() == NULL) { + GeneratedExtensionFinder finder(containing_type); + return ParseField(tag, input, &finder, &skipper); + } else { + DescriptorPoolExtensionFinder finder(input->GetExtensionPool(), + input->GetExtensionFactory(), + containing_type->GetDescriptor()); + return ParseField(tag, input, &finder, &skipper); + } } bool ExtensionSet::ParseMessageSet(io::CodedInputStream* input, - const MessageLite* containing_type, + const Message* containing_type, UnknownFieldSet* unknown_fields) { UnknownFieldSetFieldSkipper skipper(unknown_fields); - return ParseMessageSet(input, containing_type, &skipper); + if (input->GetExtensionPool() == NULL) { + GeneratedExtensionFinder finder(containing_type); + return ParseMessageSet(input, &finder, &skipper); + } else { + DescriptorPoolExtensionFinder finder(input->GetExtensionPool(), + input->GetExtensionFactory(), + containing_type->GetDescriptor()); + return ParseMessageSet(input, &finder, &skipper); + } } int ExtensionSet::SpaceUsedExcludingSelf() const { @@ -175,7 +235,7 @@ int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { if (is_repeated) { switch (cpp_type(type)) { #define HANDLE_TYPE(UPPERCASE, LOWERCASE) \ - case WireFormatLite::CPPTYPE_##UPPERCASE: \ + case FieldDescriptor::CPPTYPE_##UPPERCASE: \ total_size += sizeof(*repeated_##LOWERCASE##_value) + \ repeated_##LOWERCASE##_value->SpaceUsedExcludingSelf();\ break @@ -189,8 +249,9 @@ int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { HANDLE_TYPE( BOOL, bool); HANDLE_TYPE( ENUM, enum); HANDLE_TYPE( STRING, string); +#undef HANDLE_TYPE - case WireFormatLite::CPPTYPE_MESSAGE: + case FieldDescriptor::CPPTYPE_MESSAGE: // repeated_message_value is actually a RepeatedPtrField, // but MessageLite has no SpaceUsed(), so we must directly call // RepeatedPtrFieldBase::SpaceUsedExcludingSelf() with a different type @@ -201,11 +262,11 @@ int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { } } else { switch (cpp_type(type)) { - case WireFormatLite::CPPTYPE_STRING: + case FieldDescriptor::CPPTYPE_STRING: total_size += sizeof(*string_value) + StringSpaceUsedExcludingSelf(*string_value); break; - case WireFormatLite::CPPTYPE_MESSAGE: + case FieldDescriptor::CPPTYPE_MESSAGE: total_size += down_cast(message_value)->SpaceUsed(); break; default: @@ -216,6 +277,162 @@ int ExtensionSet::Extension::SpaceUsedExcludingSelf() const { return total_size; } +// The Serialize*ToArray methods are only needed in the heavy library, as +// the lite library only generates SerializeWithCachedSizes. +uint8* ExtensionSet::SerializeWithCachedSizesToArray( + int start_field_number, int end_field_number, + uint8* target) const { + map::const_iterator iter; + for (iter = extensions_.lower_bound(start_field_number); + iter != extensions_.end() && iter->first < end_field_number; + ++iter) { + target = iter->second.SerializeFieldWithCachedSizesToArray(iter->first, + target); + } + return target; +} + +uint8* ExtensionSet::SerializeMessageSetWithCachedSizesToArray( + uint8* target) const { + map::const_iterator iter; + for (iter = extensions_.begin(); iter != extensions_.end(); ++iter) { + target = iter->second.SerializeMessageSetItemWithCachedSizesToArray( + iter->first, target); + } + return target; +} + +uint8* ExtensionSet::Extension::SerializeFieldWithCachedSizesToArray( + int number, uint8* target) const { + if (is_repeated) { + if (is_packed) { + if (cached_size == 0) return target; + + target = WireFormatLite::WriteTagToArray(number, + WireFormatLite::WIRETYPE_LENGTH_DELIMITED, target); + target = WireFormatLite::WriteInt32NoTagToArray(cached_size, target); + + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + target = WireFormatLite::Write##CAMELCASE##NoTagToArray( \ + repeated_##LOWERCASE##_value->Get(i), target); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); + HANDLE_TYPE( ENUM, Enum, enum); +#undef HANDLE_TYPE + + case WireFormatLite::TYPE_STRING: + case WireFormatLite::TYPE_BYTES: + case WireFormatLite::TYPE_GROUP: + case WireFormatLite::TYPE_MESSAGE: + GOOGLE_LOG(FATAL) << "Non-primitive types can't be packed."; + break; + } + } else { + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, LOWERCASE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + for (int i = 0; i < repeated_##LOWERCASE##_value->size(); i++) { \ + target = WireFormatLite::Write##CAMELCASE##ToArray(number, \ + repeated_##LOWERCASE##_value->Get(i), target); \ + } \ + break + + HANDLE_TYPE( INT32, Int32, int32); + HANDLE_TYPE( INT64, Int64, int64); + HANDLE_TYPE( UINT32, UInt32, uint32); + HANDLE_TYPE( UINT64, UInt64, uint64); + HANDLE_TYPE( SINT32, SInt32, int32); + HANDLE_TYPE( SINT64, SInt64, int64); + HANDLE_TYPE( FIXED32, Fixed32, uint32); + HANDLE_TYPE( FIXED64, Fixed64, uint64); + HANDLE_TYPE(SFIXED32, SFixed32, int32); + HANDLE_TYPE(SFIXED64, SFixed64, int64); + HANDLE_TYPE( FLOAT, Float, float); + HANDLE_TYPE( DOUBLE, Double, double); + HANDLE_TYPE( BOOL, Bool, bool); + HANDLE_TYPE( STRING, String, string); + HANDLE_TYPE( BYTES, Bytes, string); + HANDLE_TYPE( ENUM, Enum, enum); + HANDLE_TYPE( GROUP, Group, message); + HANDLE_TYPE( MESSAGE, Message, message); +#undef HANDLE_TYPE + } + } + } else if (!is_cleared) { + switch (real_type(type)) { +#define HANDLE_TYPE(UPPERCASE, CAMELCASE, VALUE) \ + case FieldDescriptor::TYPE_##UPPERCASE: \ + target = WireFormatLite::Write##CAMELCASE##ToArray( \ + number, VALUE, target); \ + break + + HANDLE_TYPE( INT32, Int32, int32_value); + HANDLE_TYPE( INT64, Int64, int64_value); + HANDLE_TYPE( UINT32, UInt32, uint32_value); + HANDLE_TYPE( UINT64, UInt64, uint64_value); + HANDLE_TYPE( SINT32, SInt32, int32_value); + HANDLE_TYPE( SINT64, SInt64, int64_value); + HANDLE_TYPE( FIXED32, Fixed32, uint32_value); + HANDLE_TYPE( FIXED64, Fixed64, uint64_value); + HANDLE_TYPE(SFIXED32, SFixed32, int32_value); + HANDLE_TYPE(SFIXED64, SFixed64, int64_value); + HANDLE_TYPE( FLOAT, Float, float_value); + HANDLE_TYPE( DOUBLE, Double, double_value); + HANDLE_TYPE( BOOL, Bool, bool_value); + HANDLE_TYPE( STRING, String, *string_value); + HANDLE_TYPE( BYTES, Bytes, *string_value); + HANDLE_TYPE( ENUM, Enum, enum_value); + HANDLE_TYPE( GROUP, Group, *message_value); + HANDLE_TYPE( MESSAGE, Message, *message_value); +#undef HANDLE_TYPE + } + } + return target; +} + +uint8* ExtensionSet::Extension::SerializeMessageSetItemWithCachedSizesToArray( + int number, + uint8* target) const { + if (type != WireFormatLite::TYPE_MESSAGE || is_repeated) { + // Not a valid MessageSet extension, but serialize it the normal way. + GOOGLE_LOG(WARNING) << "Invalid message set extension."; + return SerializeFieldWithCachedSizesToArray(number, target); + } + + if (is_cleared) return target; + + // Start group. + target = io::CodedOutputStream::WriteTagToArray( + WireFormatLite::kMessageSetItemStartTag, target); + // Write type ID. + target = WireFormatLite::WriteUInt32ToArray( + WireFormatLite::kMessageSetTypeIdNumber, number, target); + // Write message. + target = WireFormatLite::WriteMessageToArray( + WireFormatLite::kMessageSetMessageNumber, *message_value, target); + // End group. + target = io::CodedOutputStream::WriteTagToArray( + WireFormatLite::kMessageSetItemEndTag, target); + return target; +} + } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc index 327aee02..000f846c 100644 --- a/src/google/protobuf/extension_set_unittest.cc +++ b/src/google/protobuf/extension_set_unittest.cc @@ -35,10 +35,15 @@ #include #include #include +#include +#include +#include +#include #include #include #include +#include #include #include #include @@ -477,6 +482,160 @@ TEST(ExtensionSetTest, InvalidEnumDeath) { #endif // GTEST_HAS_DEATH_TEST +TEST(ExtensionSetTest, DynamicExtensions) { + // Test adding a dynamic extension to a compiled-in message object. + + FileDescriptorProto dynamic_proto; + dynamic_proto.set_name("dynamic_extensions_test.proto"); + dynamic_proto.add_dependency( + unittest::TestAllExtensions::descriptor()->file()->name()); + dynamic_proto.set_package("dynamic_extensions"); + + // Copy the fields and nested types from TestDynamicExtensions into our new + // proto, converting the fields into extensions. + const Descriptor* template_descriptor = + unittest::TestDynamicExtensions::descriptor(); + DescriptorProto template_descriptor_proto; + template_descriptor->CopyTo(&template_descriptor_proto); + dynamic_proto.mutable_message_type()->MergeFrom( + template_descriptor_proto.nested_type()); + dynamic_proto.mutable_enum_type()->MergeFrom( + template_descriptor_proto.enum_type()); + dynamic_proto.mutable_extension()->MergeFrom( + template_descriptor_proto.field()); + + // For each extension that we added... + for (int i = 0; i < dynamic_proto.extension_size(); i++) { + // Set its extendee to TestAllExtensions. + FieldDescriptorProto* extension = dynamic_proto.mutable_extension(i); + extension->set_extendee( + unittest::TestAllExtensions::descriptor()->full_name()); + + // If the field refers to one of the types nested in TestDynamicExtensions, + // make it refer to the type in our dynamic proto instead. + string prefix = "." + template_descriptor->full_name() + "."; + if (extension->has_type_name()) { + string* type_name = extension->mutable_type_name(); + if (HasPrefixString(*type_name, prefix)) { + type_name->replace(0, prefix.size(), ".dynamic_extensions."); + } + } + } + + // Now build the file, using the generated pool as an underlay. + DescriptorPool dynamic_pool(DescriptorPool::generated_pool()); + const FileDescriptor* file = dynamic_pool.BuildFile(dynamic_proto); + ASSERT_TRUE(file != NULL); + DynamicMessageFactory dynamic_factory(&dynamic_pool); + dynamic_factory.SetDelegateToGeneratedFactory(true); + + // Construct a message that we can parse with the extensions we defined. + // Since the extensions were based off of the fields of TestDynamicExtensions, + // we can use that message to create this test message. + string data; + { + unittest::TestDynamicExtensions message; + message.set_scalar_extension(123); + message.set_enum_extension(unittest::FOREIGN_BAR); + message.set_dynamic_enum_extension( + unittest::TestDynamicExtensions::DYNAMIC_BAZ); + message.mutable_message_extension()->set_c(456); + message.mutable_dynamic_message_extension()->set_dynamic_field(789); + message.add_repeated_extension("foo"); + message.add_repeated_extension("bar"); + message.add_packed_extension(12); + message.add_packed_extension(-34); + message.add_packed_extension(56); + message.add_packed_extension(-78); + + // Also add some unknown fields. + + // An unknown enum value (for a known field). + message.mutable_unknown_fields()->AddVarint( + unittest::TestDynamicExtensions::kDynamicEnumExtensionFieldNumber, + 12345); + // A regular unknown field. + message.mutable_unknown_fields()->AddLengthDelimited(54321, "unknown"); + + message.SerializeToString(&data); + } + + // Now we can parse this using our dynamic extension definitions... + unittest::TestAllExtensions message; + { + io::ArrayInputStream raw_input(data.data(), data.size()); + io::CodedInputStream input(&raw_input); + input.SetExtensionRegistry(&dynamic_pool, &dynamic_factory); + ASSERT_TRUE(message.ParseFromCodedStream(&input)); + ASSERT_TRUE(input.ConsumedEntireMessage()); + } + + // Can we print it? + EXPECT_EQ( + "[dynamic_extensions.scalar_extension]: 123\n" + "[dynamic_extensions.enum_extension]: FOREIGN_BAR\n" + "[dynamic_extensions.dynamic_enum_extension]: DYNAMIC_BAZ\n" + "[dynamic_extensions.message_extension] {\n" + " c: 456\n" + "}\n" + "[dynamic_extensions.dynamic_message_extension] {\n" + " dynamic_field: 789\n" + "}\n" + "[dynamic_extensions.repeated_extension]: \"foo\"\n" + "[dynamic_extensions.repeated_extension]: \"bar\"\n" + "[dynamic_extensions.packed_extension]: 12\n" + "[dynamic_extensions.packed_extension]: -34\n" + "[dynamic_extensions.packed_extension]: 56\n" + "[dynamic_extensions.packed_extension]: -78\n" + "2002: 12345\n" + "54321: \"unknown\"\n", + message.DebugString()); + + // Can we serialize it? + // (Don't use EXPECT_EQ because we don't want to dump raw binary data to the + // terminal on failure.) + EXPECT_TRUE(message.SerializeAsString() == data); + + // What if we parse using the reflection-based parser? + { + unittest::TestAllExtensions message2; + io::ArrayInputStream raw_input(data.data(), data.size()); + io::CodedInputStream input(&raw_input); + input.SetExtensionRegistry(&dynamic_pool, &dynamic_factory); + ASSERT_TRUE(WireFormat::ParseAndMergePartial(&input, &message2)); + ASSERT_TRUE(input.ConsumedEntireMessage()); + EXPECT_EQ(message.DebugString(), message2.DebugString()); + } + + // Are the embedded generated types actually using the generated objects? + { + const FieldDescriptor* message_extension = + file->FindExtensionByName("message_extension"); + ASSERT_TRUE(message_extension != NULL); + const Message& sub_message = + message.GetReflection()->GetMessage(message, message_extension); + const unittest::ForeignMessage* typed_sub_message = + dynamic_cast(&sub_message); + ASSERT_TRUE(typed_sub_message != NULL); + EXPECT_EQ(456, typed_sub_message->c()); + } + + // What does GetMessage() return for the embedded dynamic type if it isn't + // present? + { + const FieldDescriptor* dynamic_message_extension = + file->FindExtensionByName("dynamic_message_extension"); + ASSERT_TRUE(dynamic_message_extension != NULL); + const Message& parent = unittest::TestAllExtensions::default_instance(); + const Message& sub_message = + parent.GetReflection()->GetMessage(parent, dynamic_message_extension, + &dynamic_factory); + const Message* prototype = + dynamic_factory.GetPrototype(dynamic_message_extension->message_type()); + EXPECT_EQ(prototype, &sub_message); + } +} + } // namespace } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index e04b93cc..0f065ff2 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -239,8 +239,13 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const { #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_STRING: - total_size += GetRaw >(message, field) - .SpaceUsedExcludingSelf(); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + total_size += GetRaw >(message, field) + .SpaceUsedExcludingSelf(); + break; + } break; case FieldDescriptor::CPPTYPE_MESSAGE: @@ -265,18 +270,24 @@ int GeneratedMessageReflection::SpaceUsed(const Message& message) const { break; case FieldDescriptor::CPPTYPE_STRING: { - const string* ptr = GetField(message, field); - - // Initially, the string points to the default value stored in - // the prototype. Only count the string if it has been changed - // from the default value. - const string* default_ptr = DefaultRaw(field); - - if (ptr != default_ptr) { - // string fields are represented by just a pointer, so also - // include sizeof(string) as well. - total_size += sizeof(*ptr) + StringSpaceUsedExcludingSelf(*ptr); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: { + const string* ptr = GetField(message, field); + + // Initially, the string points to the default value stored in + // the prototype. Only count the string if it has been changed + // from the default value. + const string* default_ptr = DefaultRaw(field); + + if (ptr != default_ptr) { + // string fields are represented by just a pointer, so also + // include sizeof(string) as well. + total_size += sizeof(*ptr) + StringSpaceUsedExcludingSelf(*ptr); + } + break; } + } break; } @@ -376,8 +387,13 @@ void GeneratedMessageReflection::Swap( #undef SWAP_VALUES case FieldDescriptor::CPPTYPE_STRING: - std::swap(*MutableRaw(message1, field), - *MutableRaw(message2, field)); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + std::swap(*MutableRaw(message1, field), + *MutableRaw(message2, field)); + break; + } break; default: @@ -473,15 +489,20 @@ void GeneratedMessageReflection::ClearField( break; case FieldDescriptor::CPPTYPE_STRING: { - const string* default_ptr = DefaultRaw(field); - string** value = MutableRaw(message, field); - if (*value != default_ptr) { - if (field->has_default_value()) { - (*value)->assign(field->default_value_string()); - } else { - (*value)->clear(); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + const string* default_ptr = DefaultRaw(field); + string** value = MutableRaw(message, field); + if (*value != default_ptr) { + if (field->has_default_value()) { + (*value)->assign(field->default_value_string()); + } else { + (*value)->clear(); + } } - } + break; + } break; } @@ -508,7 +529,12 @@ void GeneratedMessageReflection::ClearField( #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_STRING: { - MutableRaw >(message, field)->Clear(); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + MutableRaw >(message, field)->Clear(); + break; + } break; } @@ -549,7 +575,12 @@ void GeneratedMessageReflection::RemoveLast( #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_STRING: - MutableRaw >(message, field)->RemoveLast(); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + MutableRaw >(message, field)->RemoveLast(); + break; + } break; case FieldDescriptor::CPPTYPE_MESSAGE: @@ -658,7 +689,7 @@ void GeneratedMessageReflection::ListFields( USAGE_CHECK_ALL(Set##TYPENAME, SINGULAR, CPPTYPE); \ if (field->is_extension()) { \ return MutableExtensionSet(message)->Set##TYPENAME( \ - field->number(), field->type(), value); \ + field->number(), field->type(), value, field); \ } else { \ SetField(message, field, value); \ } \ @@ -694,7 +725,8 @@ void GeneratedMessageReflection::ListFields( USAGE_CHECK_ALL(Add##TYPENAME, REPEATED, CPPTYPE); \ if (field->is_extension()) { \ MutableExtensionSet(message)->Add##TYPENAME( \ - field->number(), field->type(), field->options().packed(), value); \ + field->number(), field->type(), field->options().packed(), value, \ + field); \ } else { \ AddField(message, field, value); \ } \ @@ -718,7 +750,14 @@ string GeneratedMessageReflection::GetString( return GetExtensionSet(message).GetString(field->number(), field->default_value_string()); } else { - return *GetField(message, field); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return *GetField(message, field); + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return kEmptyString; // Make compiler happy. } } @@ -730,7 +769,14 @@ const string& GeneratedMessageReflection::GetStringReference( return GetExtensionSet(message).GetString(field->number(), field->default_value_string()); } else { - return *GetField(message, field); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return *GetField(message, field); + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return kEmptyString; // Make compiler happy. } } @@ -741,13 +787,19 @@ void GeneratedMessageReflection::SetString( USAGE_CHECK_ALL(SetString, SINGULAR, STRING); if (field->is_extension()) { return MutableExtensionSet(message)->SetString(field->number(), - field->type(), value); + field->type(), value, field); } else { - string** ptr = MutableField(message, field); - if (*ptr == DefaultRaw(field)) { - *ptr = new string(value); - } else { - (*ptr)->assign(value); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: { + string** ptr = MutableField(message, field); + if (*ptr == DefaultRaw(field)) { + *ptr = new string(value); + } else { + (*ptr)->assign(value); + } + break; + } } } } @@ -759,7 +811,14 @@ string GeneratedMessageReflection::GetRepeatedString( if (field->is_extension()) { return GetExtensionSet(message).GetRepeatedString(field->number(), index); } else { - return GetRepeatedPtrField(message, field, index); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return GetRepeatedPtrField(message, field, index); + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return kEmptyString; // Make compiler happy. } } @@ -770,7 +829,14 @@ const string& GeneratedMessageReflection::GetRepeatedStringReference( if (field->is_extension()) { return GetExtensionSet(message).GetRepeatedString(field->number(), index); } else { - return GetRepeatedPtrField(message, field, index); + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + return GetRepeatedPtrField(message, field, index); + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return kEmptyString; // Make compiler happy. } } @@ -783,7 +849,12 @@ void GeneratedMessageReflection::SetRepeatedString( MutableExtensionSet(message)->SetRepeatedString( field->number(), index, value); } else { - *MutableRepeatedField(message, field, index) = value; + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + *MutableRepeatedField(message, field, index) = value; + break; + } } } @@ -794,9 +865,14 @@ void GeneratedMessageReflection::AddString( USAGE_CHECK_ALL(AddString, REPEATED, STRING); if (field->is_extension()) { MutableExtensionSet(message)->AddString(field->number(), - field->type(), value); + field->type(), value, field); } else { - *AddField(message, field) = value; + switch (field->options().ctype()) { + default: // TODO(kenton): Support other string reps. + case FieldOptions::STRING: + *AddField(message, field) = value; + break; + } } } @@ -828,7 +904,7 @@ void GeneratedMessageReflection::SetEnum( if (field->is_extension()) { MutableExtensionSet(message)->SetEnum(field->number(), field->type(), - value->number()); + value->number(), field); } else { SetField(message, field, value->number()); } @@ -874,7 +950,7 @@ void GeneratedMessageReflection::AddEnum( if (field->is_extension()) { MutableExtensionSet(message)->AddEnum(field->number(), field->type(), field->options().packed(), - value->number()); + value->number(), field); } else { AddField(message, field, value->number()); } @@ -883,14 +959,15 @@ void GeneratedMessageReflection::AddEnum( // ------------------------------------------------------------------- const Message& GeneratedMessageReflection::GetMessage( - const Message& message, const FieldDescriptor* field) const { + const Message& message, const FieldDescriptor* field, + MessageFactory* factory) const { USAGE_CHECK_ALL(GetMessage, SINGULAR, MESSAGE); if (field->is_extension()) { return static_cast( - GetExtensionSet(message).GetMessage(field->number(), - field->message_type(), - message_factory_)); + GetExtensionSet(message).GetMessage( + field->number(), field->message_type(), + factory == NULL ? message_factory_ : factory)); } else { const Message* result = GetRaw(message, field); if (result == NULL) { @@ -901,15 +978,14 @@ const Message& GeneratedMessageReflection::GetMessage( } Message* GeneratedMessageReflection::MutableMessage( - Message* message, const FieldDescriptor* field) const { + Message* message, const FieldDescriptor* field, + MessageFactory* factory) const { USAGE_CHECK_ALL(MutableMessage, SINGULAR, MESSAGE); if (field->is_extension()) { return static_cast( - MutableExtensionSet(message)->MutableMessage(field->number(), - field->type(), - field->message_type(), - message_factory_)); + MutableExtensionSet(message)->MutableMessage(field, + factory == NULL ? message_factory_ : factory)); } else { Message** result = MutableField(message, field); if (*result == NULL) { @@ -948,15 +1024,15 @@ Message* GeneratedMessageReflection::MutableRepeatedMessage( } Message* GeneratedMessageReflection::AddMessage( - Message* message, const FieldDescriptor* field) const { + Message* message, const FieldDescriptor* field, + MessageFactory* factory) const { USAGE_CHECK_ALL(AddMessage, REPEATED, MESSAGE); + if (factory == NULL) factory = message_factory_; + if (field->is_extension()) { return static_cast( - MutableExtensionSet(message)->AddMessage(field->number(), - field->type(), - field->message_type(), - message_factory_)); + MutableExtensionSet(message)->AddMessage(field, factory)); } else { // We can't use AddField() because RepeatedPtrFieldBase doesn't // know how to allocate one. @@ -967,7 +1043,7 @@ Message* GeneratedMessageReflection::AddMessage( // We must allocate a new object. const Message* prototype; if (repeated->size() == 0) { - prototype = message_factory_->GetPrototype(field->message_type()); + prototype = factory->GetPrototype(field->message_type()); } else { prototype = &repeated->Get >(0); } @@ -1110,7 +1186,7 @@ inline Type* GeneratedMessageReflection::MutableField( } template -inline Type GeneratedMessageReflection::GetRepeatedField( +inline const Type& GeneratedMessageReflection::GetRepeatedField( const Message& message, const FieldDescriptor* field, int index) const { return GetRaw >(message, field).Get(index); } @@ -1138,7 +1214,7 @@ inline Type* GeneratedMessageReflection::MutableRepeatedField( template inline void GeneratedMessageReflection::AddField( - Message* message, const FieldDescriptor* field, Type value) const { + Message* message, const FieldDescriptor* field, const Type& value) const { MutableRaw >(message, field)->Add(value); } diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h index d0b5b43b..b545fa1a 100644 --- a/src/google/protobuf/generated_message_reflection.h +++ b/src/google/protobuf/generated_message_reflection.h @@ -169,7 +169,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const EnumValueDescriptor* GetEnum(const Message& message, const FieldDescriptor* field) const; const Message& GetMessage(const Message& message, - const FieldDescriptor* field) const; + const FieldDescriptor* field, + MessageFactory* factory = NULL) const; void SetInt32 (Message* message, const FieldDescriptor* field, int32 value) const; @@ -190,7 +191,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const string& value) const; void SetEnum (Message* message, const FieldDescriptor* field, const EnumValueDescriptor* value) const; - Message* MutableMessage(Message* message, const FieldDescriptor* field) const; + Message* MutableMessage(Message* message, const FieldDescriptor* field, + MessageFactory* factory = NULL) const; int32 GetRepeatedInt32 (const Message& message, const FieldDescriptor* field, int index) const; @@ -262,7 +264,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { void AddEnum(Message* message, const FieldDescriptor* field, const EnumValueDescriptor* value) const; - Message* AddMessage(Message* message, const FieldDescriptor* field) const; + Message* AddMessage(Message* message, const FieldDescriptor* field, + MessageFactory* factory = NULL) const; const FieldDescriptor* FindKnownExtensionByName(const string& name) const; const FieldDescriptor* FindKnownExtensionByNumber(int number) const; @@ -314,9 +317,9 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { inline Type* MutableField(Message* message, const FieldDescriptor* field) const; template - inline Type GetRepeatedField(const Message& message, - const FieldDescriptor* field, - int index) const; + inline const Type& GetRepeatedField(const Message& message, + const FieldDescriptor* field, + int index) const; template inline const Type& GetRepeatedPtrField(const Message& message, const FieldDescriptor* field, @@ -331,7 +334,7 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { int index) const; template inline void AddField(Message* message, - const FieldDescriptor* field, Type value) const; + const FieldDescriptor* field, const Type& value) const; template inline Type* AddField(Message* message, const FieldDescriptor* field) const; diff --git a/src/google/protobuf/generated_message_util.cc b/src/google/protobuf/generated_message_util.cc index 9470bb08..7ac015d0 100644 --- a/src/google/protobuf/generated_message_util.cc +++ b/src/google/protobuf/generated_message_util.cc @@ -34,10 +34,19 @@ #include +#include + namespace google { namespace protobuf { namespace internal { +double Infinity() { + return std::numeric_limits::infinity(); +} +double NaN() { + return std::numeric_limits::quiet_NaN(); +} + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/generated_message_util.h b/src/google/protobuf/generated_message_util.h index 80dd028e..f306a2f1 100644 --- a/src/google/protobuf/generated_message_util.h +++ b/src/google/protobuf/generated_message_util.h @@ -42,22 +42,34 @@ namespace google { +namespace protobuf { + namespace io { + class CodedInputStream; // coded_stream.h + } +} + namespace protobuf { namespace internal { // Annotation for the compiler to emit a deprecation message if a field marked -// with option 'deprecated=true' is used in the code. +// with option 'deprecated=true' is used in the code, or for other things in +// generated code which are deprecated. // // For internal use in the pb.cc files, deprecation warnings are suppressed // there. #undef DEPRECATED_PROTOBUF_FIELD #if !defined(INTERNAL_SUPPRESS_PROTOBUF_FIELD_DEPRECATION) -# define DEPRECATED_PROTOBUF_FIELD GOOGLE_ATTRIBUTE_DEPRECATED +# define PROTOBUF_DEPRECATED GOOGLE_ATTRIBUTE_DEPRECATED #else -# define DEPRECATED_PROTOBUF_FIELD +# define PROTOBUF_DEPRECATED #endif +// Constants for special floating point values. +double Infinity(); +double NaN(); + + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc index e17a4775..6a91a13d 100644 --- a/src/google/protobuf/io/coded_stream.cc +++ b/src/google/protobuf/io/coded_stream.cc @@ -38,9 +38,9 @@ // will not cross the end of the buffer, since we can avoid a lot // of branching in this case. -#include +#include +#include #include -#include #include #include #include @@ -52,11 +52,6 @@ namespace io { namespace { -static const int kDefaultTotalBytesLimit = 64 << 20; // 64MB - -static const int kDefaultTotalBytesWarningThreshold = 32 << 20; // 32MB -static const int kDefaultRecursionLimit = 64; - static const int kMaxVarintBytes = 10; static const int kMaxVarint32Bytes = 5; @@ -65,72 +60,28 @@ static const int kMaxVarint32Bytes = 5; // CodedInputStream ================================================== -CodedInputStream::CodedInputStream(ZeroCopyInputStream* input) - : input_(input), - buffer_(NULL), - buffer_size_(0), - total_bytes_read_(0), - overflow_bytes_(0), - last_tag_(0), - legitimate_message_end_(false), - aliasing_enabled_(false), - current_limit_(INT_MAX), - buffer_size_after_limit_(0), - total_bytes_limit_(kDefaultTotalBytesLimit), - total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), - recursion_depth_(0), - recursion_limit_(kDefaultRecursionLimit) { - // Eagerly Refresh() so buffer space is immediately available. - Refresh(); -} - -CodedInputStream::CodedInputStream(const uint8* buffer, int size) - : input_(NULL), - buffer_(buffer), - buffer_size_(size), - total_bytes_read_(size), - overflow_bytes_(0), - last_tag_(0), - legitimate_message_end_(false), - aliasing_enabled_(false), - current_limit_(size), - buffer_size_after_limit_(0), - total_bytes_limit_(kDefaultTotalBytesLimit), - total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), - recursion_depth_(0), - recursion_limit_(kDefaultRecursionLimit) { - // Note that setting current_limit_ == size is important to prevent some - // code paths from trying to access input_ and segfaulting. -} - -CodedInputStream::~CodedInputStream() { - if (input_ != NULL) { - BackUpInputToCurrentPosition(); - } -} - void CodedInputStream::BackUpInputToCurrentPosition() { - int backup_bytes = buffer_size_ + buffer_size_after_limit_ + overflow_bytes_; + int backup_bytes = BufferSize() + buffer_size_after_limit_ + overflow_bytes_; if (backup_bytes > 0) { input_->BackUp(backup_bytes); // total_bytes_read_ doesn't include overflow_bytes_. - total_bytes_read_ -= buffer_size_ + buffer_size_after_limit_; - buffer_size_ = 0; + total_bytes_read_ -= BufferSize() + buffer_size_after_limit_; + buffer_end_ = buffer_; buffer_size_after_limit_ = 0; overflow_bytes_ = 0; } } inline void CodedInputStream::RecomputeBufferLimits() { - buffer_size_ += buffer_size_after_limit_; + buffer_end_ += buffer_size_after_limit_; int closest_limit = min(current_limit_, total_bytes_limit_); if (closest_limit < total_bytes_read_) { // The limit position is in the current buffer. We must adjust // the buffer size accordingly. buffer_size_after_limit_ = total_bytes_read_ - closest_limit; - buffer_size_ -= buffer_size_after_limit_; + buffer_end_ -= buffer_size_after_limit_; } else { buffer_size_after_limit_ = 0; } @@ -139,7 +90,7 @@ inline void CodedInputStream::RecomputeBufferLimits() { CodedInputStream::Limit CodedInputStream::PushLimit(int byte_limit) { // Current position relative to the beginning of the stream. int current_position = total_bytes_read_ - - (buffer_size_ + buffer_size_after_limit_); + (BufferSize() + buffer_size_after_limit_); Limit old_limit = current_limit_; @@ -176,7 +127,7 @@ void CodedInputStream::PopLimit(Limit limit) { int CodedInputStream::BytesUntilLimit() { if (current_limit_ == INT_MAX) return -1; int current_position = total_bytes_read_ - - (buffer_size_ + buffer_size_after_limit_); + (BufferSize() + buffer_size_after_limit_); return current_limit_ - current_position; } @@ -186,7 +137,7 @@ void CodedInputStream::SetTotalBytesLimit( // Make sure the limit isn't already past, since this could confuse other // code. int current_position = total_bytes_read_ - - (buffer_size_ + buffer_size_after_limit_); + (BufferSize() + buffer_size_after_limit_); total_bytes_limit_ = max(current_position, total_bytes_limit); total_bytes_warning_threshold_ = warning_threshold; RecomputeBufferLimits(); @@ -203,7 +154,9 @@ void CodedInputStream::PrintTotalBytesLimitError() { bool CodedInputStream::Skip(int count) { if (count < 0) return false; // security: count is often user-supplied - if (count <= buffer_size_) { + const int original_buffer_size = BufferSize(); + + if (count <= original_buffer_size) { // Just skipping within the current buffer. Easy. Advance(count); return true; @@ -211,13 +164,13 @@ bool CodedInputStream::Skip(int count) { if (buffer_size_after_limit_ > 0) { // We hit a limit inside this buffer. Advance to the limit and fail. - Advance(buffer_size_); + Advance(original_buffer_size); return false; } - count -= buffer_size_; + count -= original_buffer_size; buffer_ = NULL; - buffer_size_ = 0; + buffer_end_ = buffer_; // Make sure this skip doesn't try to skip past the current limit. int closest_limit = min(current_limit_, total_bytes_limit_); @@ -236,20 +189,21 @@ bool CodedInputStream::Skip(int count) { } bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) { - if (buffer_size_ == 0 && !Refresh()) return false; + if (BufferSize() == 0 && !Refresh()) return false; *data = buffer_; - *size = buffer_size_; + *size = BufferSize(); return true; } bool CodedInputStream::ReadRaw(void* buffer, int size) { - while (buffer_size_ < size) { + int current_buffer_size; + while ((current_buffer_size = BufferSize()) < size) { // Reading past end of buffer. Copy what we have, then refresh. - memcpy(buffer, buffer_, buffer_size_); - buffer = reinterpret_cast(buffer) + buffer_size_; - size -= buffer_size_; - Advance(buffer_size_); + memcpy(buffer, buffer_, current_buffer_size); + buffer = reinterpret_cast(buffer) + current_buffer_size; + size -= current_buffer_size; + Advance(current_buffer_size); if (!Refresh()) return false; } @@ -261,27 +215,25 @@ bool CodedInputStream::ReadRaw(void* buffer, int size) { bool CodedInputStream::ReadString(string* buffer, int size) { if (size < 0) return false; // security: size is often user-supplied + return InternalReadStringInline(buffer, size); +} +bool CodedInputStream::ReadStringFallback(string* buffer, int size) { if (!buffer->empty()) { buffer->clear(); } - if (size < buffer_size_) { - STLStringResizeUninitialized(buffer, size); - memcpy((uint8*)buffer->data(), buffer_, size); - Advance(size); - return true; - } - - while (buffer_size_ < size) { + int current_buffer_size; + while ((current_buffer_size = BufferSize()) < size) { // Some STL implementations "helpfully" crash on buffer->append(NULL, 0). - if (buffer_size_ != 0) { + if (current_buffer_size != 0) { // Note: string1.append(string2) is O(string2.size()) (as opposed to // O(string1.size() + string2.size()), which would be bad). - buffer->append(reinterpret_cast(buffer_), buffer_size_); + buffer->append(reinterpret_cast(buffer_), + current_buffer_size); } - size -= buffer_size_; - Advance(buffer_size_); + size -= current_buffer_size; + Advance(current_buffer_size); if (!Refresh()) return false; } @@ -292,11 +244,11 @@ bool CodedInputStream::ReadString(string* buffer, int size) { } -bool CodedInputStream::ReadLittleEndian32(uint32* value) { +bool CodedInputStream::ReadLittleEndian32Fallback(uint32* value) { uint8 bytes[sizeof(*value)]; const uint8* ptr; - if (buffer_size_ >= sizeof(*value)) { + if (BufferSize() >= sizeof(*value)) { // Fast path: Enough bytes in the buffer to read directly. ptr = buffer_; Advance(sizeof(*value)); @@ -305,19 +257,15 @@ bool CodedInputStream::ReadLittleEndian32(uint32* value) { if (!ReadRaw(bytes, sizeof(*value))) return false; ptr = bytes; } - - *value = (static_cast(ptr[0]) ) | - (static_cast(ptr[1]) << 8) | - (static_cast(ptr[2]) << 16) | - (static_cast(ptr[3]) << 24); + ReadLittleEndian32FromArray(ptr, value); return true; } -bool CodedInputStream::ReadLittleEndian64(uint64* value) { +bool CodedInputStream::ReadLittleEndian64Fallback(uint64* value) { uint8 bytes[sizeof(*value)]; const uint8* ptr; - if (buffer_size_ >= sizeof(*value)) { + if (BufferSize() >= sizeof(*value)) { // Fast path: Enough bytes in the buffer to read directly. ptr = buffer_; Advance(sizeof(*value)); @@ -326,99 +274,152 @@ bool CodedInputStream::ReadLittleEndian64(uint64* value) { if (!ReadRaw(bytes, sizeof(*value))) return false; ptr = bytes; } + ReadLittleEndian64FromArray(ptr, value); + return true; +} + +namespace { + +inline const uint8* ReadVarint32FromArray( + const uint8* buffer, uint32* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; +inline const uint8* ReadVarint32FromArray(const uint8* buffer, uint32* value) { + // Fast path: We have enough bytes left in the buffer to guarantee that + // this read won't cross the end, so we can skip the checks. + const uint8* ptr = buffer; + uint32 b; + uint32 result; + + b = *(ptr++); result = (b & 0x7F) ; if (!(b & 0x80)) goto done; + b = *(ptr++); result |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done; + b = *(ptr++); result |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done; + b = *(ptr++); result |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done; + b = *(ptr++); result |= b << 28; if (!(b & 0x80)) goto done; + + // If the input is larger than 32 bits, we still need to read it all + // and discard the high-order bits. + for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) { + b = *(ptr++); if (!(b & 0x80)) goto done; + } + + // We have overrun the maximum size of a varint (10 bytes). Assume + // the data is corrupt. + return NULL; + + done: + *value = result; + return ptr; +} + +} // namespace - uint32 part0 = (static_cast(ptr[0]) ) | - (static_cast(ptr[1]) << 8) | - (static_cast(ptr[2]) << 16) | - (static_cast(ptr[3]) << 24); - uint32 part1 = (static_cast(ptr[4]) ) | - (static_cast(ptr[5]) << 8) | - (static_cast(ptr[6]) << 16) | - (static_cast(ptr[7]) << 24); - *value = static_cast(part0) | - (static_cast(part1) << 32); +bool CodedInputStream::ReadVarint32Slow(uint32* value) { + uint64 result; + // Directly invoke ReadVarint64Fallback, since we already tried to optimize + // for one-byte varints. + if (!ReadVarint64Fallback(&result)) return false; + *value = (uint32)result; return true; } bool CodedInputStream::ReadVarint32Fallback(uint32* value) { - if (buffer_size_ >= kMaxVarintBytes || + if (BufferSize() >= kMaxVarintBytes || // Optimization: If the varint ends at exactly the end of the buffer, // we can detect that and still use the fast path. - (buffer_size_ != 0 && !(buffer_[buffer_size_-1] & 0x80))) { - // Fast path: We have enough bytes left in the buffer to guarantee that - // this read won't cross the end, so we can skip the checks. - const uint8* ptr = buffer_; - uint32 b; - uint32 result; - - b = *(ptr++); result = (b & 0x7F) ; if (!(b & 0x80)) goto done; - b = *(ptr++); result |= (b & 0x7F) << 7; if (!(b & 0x80)) goto done; - b = *(ptr++); result |= (b & 0x7F) << 14; if (!(b & 0x80)) goto done; - b = *(ptr++); result |= (b & 0x7F) << 21; if (!(b & 0x80)) goto done; - b = *(ptr++); result |= b << 28; if (!(b & 0x80)) goto done; - - // If the input is larger than 32 bits, we still need to read it all - // and discard the high-order bits. - for (int i = 0; i < kMaxVarintBytes - kMaxVarint32Bytes; i++) { - b = *(ptr++); if (!(b & 0x80)) goto done; - } - - // We have overrun the maximum size of a varint (10 bytes). Assume - // the data is corrupt. - return false; - - done: - Advance(ptr - buffer_); - *value = result; + (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { + const uint8* end = ReadVarint32FromArray(buffer_, value); + if (end == NULL) return false; + buffer_ = end; return true; - } else { - // Optimization: If we're at a limit, detect that quickly. (This is - // common when reading tags.) - while (buffer_size_ == 0) { - // Detect cases where we definitely hit a byte limit without calling - // Refresh(). - if (// If we hit a limit, buffer_size_after_limit_ will be non-zero. - buffer_size_after_limit_ > 0 && - // Make sure that the limit we hit is not total_bytes_limit_, since - // in that case we still need to call Refresh() so that it prints an - // error. - total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) { - // We hit a byte limit. - legitimate_message_end_ = true; - return false; - } + // Really slow case: we will incur the cost of an extra function call here, + // but moving this out of line reduces the size of this function, which + // improves the common case. In micro benchmarks, this is worth about 10-15% + return ReadVarint32Slow(value); + } +} - // Call refresh. - if (!Refresh()) { - // Refresh failed. Make sure that it failed due to EOF, not because - // we hit total_bytes_limit_, which, unlike normal limits, is not a - // valid place to end a message. - int current_position = total_bytes_read_ - buffer_size_after_limit_; - if (current_position >= total_bytes_limit_) { - // Hit total_bytes_limit_. But if we also hit the normal limit, - // we're still OK. - legitimate_message_end_ = current_limit_ == total_bytes_limit_; - } else { - legitimate_message_end_ = true; - } - return false; +uint32 CodedInputStream::ReadTagSlow() { + if (buffer_ == buffer_end_) { + // Call refresh. + if (!Refresh()) { + // Refresh failed. Make sure that it failed due to EOF, not because + // we hit total_bytes_limit_, which, unlike normal limits, is not a + // valid place to end a message. + int current_position = total_bytes_read_ - buffer_size_after_limit_; + if (current_position >= total_bytes_limit_) { + // Hit total_bytes_limit_. But if we also hit the normal limit, + // we're still OK. + legitimate_message_end_ = current_limit_ == total_bytes_limit_; + } else { + legitimate_message_end_ = true; } + return 0; } + } - // Slow path: Just do a 64-bit read. - uint64 result; - if (!ReadVarint64(&result)) return false; - *value = (uint32)result; - return true; + // For the slow path, just do a 64-bit read. Try to optimize for one-byte tags + // again, since we have now refreshed the buffer. + uint64 result; + if (!ReadVarint64(&result)) return 0; + return static_cast(result); +} + +uint32 CodedInputStream::ReadTagFallback() { + if (BufferSize() >= kMaxVarintBytes || + // Optimization: If the varint ends at exactly the end of the buffer, + // we can detect that and still use the fast path. + (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { + uint32 tag; + const uint8* end = ReadVarint32FromArray(buffer_, &tag); + if (end == NULL) { + return 0; + } + buffer_ = end; + return tag; + } else { + // We are commonly at a limit when attempting to read tags. Try to quickly + // detect this case without making another function call. + if (buffer_ == buffer_end_ && buffer_size_after_limit_ > 0 && + // Make sure that the limit we hit is not total_bytes_limit_, since + // in that case we still need to call Refresh() so that it prints an + // error. + total_bytes_read_ - buffer_size_after_limit_ < total_bytes_limit_) { + // We hit a byte limit. + legitimate_message_end_ = true; + return 0; + } + return ReadTagSlow(); } } -bool CodedInputStream::ReadVarint64(uint64* value) { - if (buffer_size_ >= kMaxVarintBytes || +bool CodedInputStream::ReadVarint64Slow(uint64* value) { + // Slow path: This read might cross the end of the buffer, so we + // need to check and refresh the buffer if and when it does. + + uint64 result = 0; + int count = 0; + uint32 b; + + do { + if (count == kMaxVarintBytes) return false; + while (buffer_ == buffer_end_) { + if (!Refresh()) return false; + } + b = *buffer_; + result |= static_cast(b & 0x7F) << (7 * count); + Advance(1); + ++count; + } while (b & 0x80); + + *value = result; + return true; +} + +bool CodedInputStream::ReadVarint64Fallback(uint64* value) { + if (BufferSize() >= kMaxVarintBytes || // Optimization: If the varint ends at exactly the end of the buffer, // we can detect that and still use the fast path. - (buffer_size_ != 0 && !(buffer_[buffer_size_-1] & 0x80))) { + (buffer_end_ > buffer_ && !(buffer_end_[-1] & 0x80))) { // Fast path: We have enough bytes left in the buffer to guarantee that // this read won't cross the end, so we can skip the checks. @@ -442,7 +443,7 @@ bool CodedInputStream::ReadVarint64(uint64* value) { // We have overrun the maximum size of a varint (10 bytes). The data // must be corrupt. - return false; + return NULL; done: Advance(ptr - buffer_); @@ -450,33 +451,13 @@ bool CodedInputStream::ReadVarint64(uint64* value) { (static_cast(part1) << 28) | (static_cast(part2) << 56); return true; - } else { - // Slow path: This read might cross the end of the buffer, so we - // need to check and refresh the buffer if and when it does. - - uint64 result = 0; - int count = 0; - uint32 b; - - do { - if (count == kMaxVarintBytes) return false; - while (buffer_size_ == 0) { - if (!Refresh()) return false; - } - b = *buffer_; - result |= static_cast(b & 0x7F) << (7 * count); - Advance(1); - ++count; - } while(b & 0x80); - - *value = result; - return true; + return ReadVarint64Slow(value); } } bool CodedInputStream::Refresh() { - GOOGLE_DCHECK_EQ(buffer_size_, 0); + GOOGLE_DCHECK_EQ(0, BufferSize()); if (buffer_size_after_limit_ > 0 || overflow_bytes_ > 0 || total_bytes_read_ == current_limit_) { @@ -507,25 +488,27 @@ bool CodedInputStream::Refresh() { } const void* void_buffer; - if (input_->Next(&void_buffer, &buffer_size_)) { + int buffer_size; + if (input_->Next(&void_buffer, &buffer_size)) { buffer_ = reinterpret_cast(void_buffer); - GOOGLE_CHECK_GE(buffer_size_, 0); + buffer_end_ = buffer_ + buffer_size; + GOOGLE_CHECK_GE(buffer_size, 0); - if (total_bytes_read_ <= INT_MAX - buffer_size_) { - total_bytes_read_ += buffer_size_; + if (total_bytes_read_ <= INT_MAX - buffer_size) { + total_bytes_read_ += buffer_size; } else { - // Overflow. Reset buffer_size_ to not include the bytes beyond INT_MAX. + // Overflow. Reset buffer_end_ to not include the bytes beyond INT_MAX. // We can't get that far anyway, because total_bytes_limit_ is guaranteed // to be less than it. We need to keep track of the number of bytes // we discarded, though, so that we can call input_->BackUp() to back // up over them on destruction. // The following line is equivalent to: - // overflow_bytes_ = total_bytes_read_ + buffer_size_ - INT_MAX; + // overflow_bytes_ = total_bytes_read_ + buffer_size - INT_MAX; // except that it avoids overflows. Signed integer overflow has // undefined results according to the C standard. - overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size_); - buffer_size_ -= overflow_bytes_; + overflow_bytes_ = total_bytes_read_ - (INT_MAX - buffer_size); + buffer_end_ -= overflow_bytes_; total_bytes_read_ = INT_MAX; } @@ -533,7 +516,7 @@ bool CodedInputStream::Refresh() { return true; } else { buffer_ = NULL; - buffer_size_ = 0; + buffer_end_ = NULL; return false; } } diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h index fa023f35..dcbb0d45 100644 --- a/src/google/protobuf/io/coded_stream.h +++ b/src/google/protobuf/io/coded_stream.h @@ -114,10 +114,15 @@ #include #endif // !_MSC_VER #include +#include // for GOOGLE_PREDICT_TRUE macro namespace google { namespace protobuf { + +class DescriptorPool; +class MessageFactory; + namespace io { // Defined in this file. @@ -166,6 +171,11 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // types of data not covered by the CodedInputStream interface. bool GetDirectBufferPointer(const void** data, int* size); + // Like GetDirectBufferPointer, but this method is inlined, and does not + // attempt to Refresh() if the buffer is currently empty. + inline void GetDirectBufferPointerInline(const void** data, + int* size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + // Read raw bytes, copying them into the given buffer. bool ReadRaw(void* buffer, int size); @@ -177,6 +187,10 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // could claim that a string is going to be MAX_INT bytes long in order to // crash the server because it can't allocate this much space at once. bool ReadString(string* buffer, int size); + // Like the above, with inlined optimizations. This should only be used + // by the protobuf implementation. + inline bool InternalReadStringInline(string* buffer, + int size) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; // Read a 32-bit little-endian integer. @@ -184,6 +198,15 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // Read a 64-bit little-endian integer. bool ReadLittleEndian64(uint64* value); + // These methods read from an externally provided buffer. The caller is + // responsible for ensuring that the buffer has sufficient space. + // Read a 32-bit little-endian integer. + static const uint8* ReadLittleEndian32FromArray(const uint8* buffer, + uint32* value); + // Read a 64-bit little-endian integer. + static const uint8* ReadLittleEndian64FromArray(const uint8* buffer, + uint64* value); + // Read an unsigned integer with Varint encoding, truncating to 32 bits. // Reading a 32-bit value is equivalent to reading a 64-bit one and casting // it to uint32, but may be more efficient. @@ -208,6 +231,17 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // when given a constant parameter, but GCC doesn't want to inline by default. bool ExpectTag(uint32 expected) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + // Like above, except this reads from the specified buffer. The caller is + // responsible for ensuring that the buffer is large enough to read a varint + // of the expected size. For best performance, use a compile-time constant as + // the expected tag parameter. + // + // Returns a pointer beyond the expected tag if it was found, or NULL if it + // was not. + static const uint8* ExpectTagFromArray( + const uint8* buffer, + uint32 expected) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + // Usually returns true if no more bytes can be read. Always returns false // if more bytes can be read. If ExpectAtEnd() returns true, a subsequent // call to LastTagWas() will act as if ReadTag() had been called and returned @@ -318,12 +352,90 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // Decrements the recursion depth. void DecrementRecursionDepth(); + // Extension Registry ---------------------------------------------- + // ADVANCED USAGE: 99.9% of people can ignore this section. + // + // By default, when parsing extensions, the parser looks for extension + // definitions in the pool which owns the outer message's Descriptor. + // However, you may call SetExtensionRegistry() to provide an alternative + // pool instead. This makes it possible, for example, to parse a message + // using a generated class, but represent some extensions using + // DynamicMessage. + + // Set the pool used to look up extensions. Most users do not need to call + // this as the correct pool will be chosen automatically. + // + // WARNING: It is very easy to misuse this. Carefully read the requirements + // below. Do not use this unless you are sure you need it. Almost no one + // does. + // + // Let's say you are parsing a message into message object m, and you want + // to take advantage of SetExtensionRegistry(). You must follow these + // requirements: + // + // The given DescriptorPool must contain m->GetDescriptor(). It is not + // sufficient for it to simply contain a descriptor that has the same name + // and content -- it must be the *exact object*. In other words: + // assert(pool->FindMessageTypeByName(m->GetDescriptor()->full_name()) == + // m->GetDescriptor()); + // There are two ways to satisfy this requirement: + // 1) Use m->GetDescriptor()->pool() as the pool. This is generally useless + // because this is the pool that would be used anyway if you didn't call + // SetExtensionRegistry() at all. + // 2) Use a DescriptorPool which has m->GetDescriptor()->pool() as an + // "underlay". Read the documentation for DescriptorPool for more + // information about underlays. + // + // You must also provide a MessageFactory. This factory will be used to + // construct Message objects representing extensions. The factory's + // GetPrototype() MUST return non-NULL for any Descriptor which can be found + // through the provided pool. + // + // If the provided factory might return instances of protocol-compiler- + // generated (i.e. compiled-in) types, or if the outer message object m is + // a generated type, then the given factory MUST have this property: If + // GetPrototype() is given a Descriptor which resides in + // DescriptorPool::generated_pool(), the factory MUST return the same + // prototype which MessageFactory::generated_factory() would return. That + // is, given a descriptor for a generated type, the factory must return an + // instance of the generated class (NOT DynamicMessage). However, when + // given a descriptor for a type that is NOT in generated_pool, the factory + // is free to return any implementation. + // + // The reason for this requirement is that generated sub-objects may be + // accessed via the standard (non-reflection) extension accessor methods, + // and these methods will down-cast the object to the generated class type. + // If the object is not actually of that type, the results would be undefined. + // On the other hand, if an extension is not compiled in, then there is no + // way the code could end up accessing it via the standard accessors -- the + // only way to access the extension is via reflection. When using reflection, + // DynamicMessage and generated messages are indistinguishable, so it's fine + // if these objects are represented using DynamicMessage. + // + // Using DynamicMessageFactory on which you have called + // SetDelegateToGeneratedFactory(true) should be sufficient to satisfy the + // above requirement. + // + // If either pool or factory is NULL, both must be NULL. + // + // Note that this feature is ignored when parsing "lite" messages as they do + // not have descriptors. + void SetExtensionRegistry(DescriptorPool* pool, MessageFactory* factory); + + // Get the DescriptorPool set via SetExtensionRegistry(), or NULL if no pool + // has been provided. + const DescriptorPool* GetExtensionPool(); + + // Get the MessageFactory set via SetExtensionRegistry(), or NULL if no + // factory has been provided. + MessageFactory* GetExtensionFactory(); + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CodedInputStream); ZeroCopyInputStream* input_; const uint8* buffer_; - int buffer_size_; // size of current buffer + const uint8* buffer_end_; // pointer to the end of the buffer. int total_bytes_read_; // total bytes read from input_, including // the current buffer @@ -334,7 +446,7 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // LastTagWas() stuff. uint32 last_tag_; // result of last ReadTag(). - // This is set true by ReadVarint32Fallback() if it is called when exactly + // This is set true by ReadTag{Fallback/Slow}() if it is called when exactly // at EOF, or by ExpectAtEnd() when it returns true. This happens when we // reach the end of a message and attempt to read another tag. bool legitimate_message_end_; @@ -365,6 +477,12 @@ class LIBPROTOBUF_EXPORT CodedInputStream { // Recursion depth limit, set by SetRecursionLimit(). int recursion_limit_; + // See SetExtensionRegistry(). + const DescriptorPool* extension_pool_; + MessageFactory* extension_factory_; + + // Private member functions. + // Advance the buffer by a given number of bytes. void Advance(int amount); @@ -379,10 +497,36 @@ class LIBPROTOBUF_EXPORT CodedInputStream { void PrintTotalBytesLimitError(); // Called when the buffer runs out to request more data. Implies an - // Advance(buffer_size_). + // Advance(BufferSize()). bool Refresh(); + // When parsing varints, we optimize for the common case of small values, and + // then optimize for the case when the varint fits within the current buffer + // piece. The Fallback method is used when we can't use the one-byte + // optimization. The Slow method is yet another fallback when the buffer is + // not large enough. Making the slow path out-of-line speeds up the common + // case by 10-15%. The slow path is fairly uncommon: it only triggers when a + // message crosses multiple buffers. bool ReadVarint32Fallback(uint32* value); + bool ReadVarint64Fallback(uint64* value); + bool ReadVarint32Slow(uint32* value); + bool ReadVarint64Slow(uint64* value); + bool ReadLittleEndian32Fallback(uint32* value); + bool ReadLittleEndian64Fallback(uint64* value); + // Fallback/slow methods for reading tags. These do not update last_tag_, + // but will set legitimate_message_end_ if we are at the end of the input + // stream. + uint32 ReadTagFallback(); + uint32 ReadTagSlow(); + bool ReadStringFallback(string* buffer, int size); + + // Return the size of the buffer. + int BufferSize() const; + + static const int kDefaultTotalBytesLimit = 64 << 20; // 64MB + + static const int kDefaultTotalBytesWarningThreshold = 32 << 20; // 32MB + static const int kDefaultRecursionLimit = 64; }; // Class which encodes and writes binary data which is composed of varint- @@ -568,7 +712,7 @@ class LIBPROTOBUF_EXPORT CodedOutputStream { // methods optimize for that case. inline bool CodedInputStream::ReadVarint32(uint32* value) { - if (buffer_size_ != 0 && *buffer_ < 0x80) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && *buffer_ < 0x80) { *value = *buffer_; Advance(1); return true; @@ -577,20 +721,93 @@ inline bool CodedInputStream::ReadVarint32(uint32* value) { } } +inline bool CodedInputStream::ReadVarint64(uint64* value) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && *buffer_ < 0x80) { + *value = *buffer_; + Advance(1); + return true; + } else { + return ReadVarint64Fallback(value); + } +} + +// static +inline const uint8* CodedInputStream::ReadLittleEndian32FromArray( + const uint8* buffer, + uint32* value) { +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ + defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN + memcpy(value, buffer, sizeof(*value)); + return buffer + sizeof(*value); +#else + *value = (static_cast(buffer[0]) ) | + (static_cast(buffer[1]) << 8) | + (static_cast(buffer[2]) << 16) | + (static_cast(buffer[3]) << 24); + return buffer + sizeof(*value); +#endif +} +// static +inline const uint8* CodedInputStream::ReadLittleEndian64FromArray( + const uint8* buffer, + uint64* value) { +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ + defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN + memcpy(value, buffer, sizeof(*value)); + return buffer + sizeof(*value); +#else + uint32 part0 = (static_cast(buffer[0]) ) | + (static_cast(buffer[1]) << 8) | + (static_cast(buffer[2]) << 16) | + (static_cast(buffer[3]) << 24); + uint32 part1 = (static_cast(buffer[4]) ) | + (static_cast(buffer[5]) << 8) | + (static_cast(buffer[6]) << 16) | + (static_cast(buffer[7]) << 24); + *value = static_cast(part0) | + (static_cast(part1) << 32); + return buffer + sizeof(*value); +#endif +} + +inline bool CodedInputStream::ReadLittleEndian32(uint32* value) { +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ + defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN + if (GOOGLE_PREDICT_TRUE(BufferSize() >= sizeof(*value))) { + memcpy(value, buffer_, sizeof(*value)); + Advance(sizeof(*value)); + return true; + } else { + return ReadLittleEndian32Fallback(value); + } +#else + return ReadLittleEndian32Fallback(value); +#endif +} + +inline bool CodedInputStream::ReadLittleEndian64(uint64* value) { +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ + defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN + if (GOOGLE_PREDICT_TRUE(BufferSize() >= sizeof(*value))) { + memcpy(value, buffer_, sizeof(*value)); + Advance(sizeof(*value)); + return true; + } else { + return ReadLittleEndian64Fallback(value); + } +#else + return ReadLittleEndian64Fallback(value); +#endif +} + inline uint32 CodedInputStream::ReadTag() { - if (buffer_size_ != 0 && buffer_[0] < 0x80) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && buffer_[0] < 0x80) { last_tag_ = buffer_[0]; Advance(1); return last_tag_; - } else if (buffer_size_ >= 2 && buffer_[1] < 0x80) { - last_tag_ = (buffer_[0] & 0x7f) + (buffer_[1] << 7); - Advance(2); - return last_tag_; - } else if (ReadVarint32Fallback(&last_tag_)) { - return last_tag_; } else { - last_tag_ = 0; - return 0; + last_tag_ = ReadTagFallback(); + return last_tag_; } } @@ -604,14 +821,14 @@ inline bool CodedInputStream::ConsumedEntireMessage() { inline bool CodedInputStream::ExpectTag(uint32 expected) { if (expected < (1 << 7)) { - if (buffer_size_ != 0 && buffer_[0] == expected) { + if (GOOGLE_PREDICT_TRUE(buffer_ < buffer_end_) && buffer_[0] == expected) { Advance(1); return true; } else { return false; } } else if (expected < (1 << 14)) { - if (buffer_size_ >= 2 && + if (GOOGLE_PREDICT_TRUE(BufferSize() >= 2) && buffer_[0] == static_cast(expected | 0x80) && buffer_[1] == static_cast(expected >> 7)) { Advance(2); @@ -625,11 +842,32 @@ inline bool CodedInputStream::ExpectTag(uint32 expected) { } } +inline const uint8* CodedInputStream::ExpectTagFromArray( + const uint8* buffer, uint32 expected) { + if (expected < (1 << 7)) { + if (buffer[0] == expected) { + return buffer + 1; + } + } else if (expected < (1 << 14)) { + if (buffer[0] == static_cast(expected | 0x80) && + buffer[1] == static_cast(expected >> 7)) { + return buffer + 2; + } + } + return NULL; +} + +inline void CodedInputStream::GetDirectBufferPointerInline(const void** data, + int* size) { + *data = buffer_; + *size = buffer_end_ - buffer_; +} + inline bool CodedInputStream::ExpectAtEnd() { // If we are at a limit we know no more bytes can be read. Otherwise, it's // hard to say without calling Refresh(), and we'd rather not do that. - if (buffer_size_ == 0 && buffer_size_after_limit_ != 0) { + if (buffer_ == buffer_end_ && buffer_size_after_limit_ != 0) { last_tag_ = 0; // Pretend we called ReadTag()... legitimate_message_end_ = true; // ... and it hit EOF. return true; @@ -677,11 +915,11 @@ inline uint8* CodedOutputStream::WriteVarint32SignExtendedToArray( inline uint8* CodedOutputStream::WriteLittleEndian32ToArray(uint32 value, uint8* target) { -#if !defined(PROTOBUF_TEST_NOT_LITTLE_ENDIAN) && \ +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN memcpy(target, &value, sizeof(value)); #else - target[0] = static_cast(value ); + target[0] = static_cast(value); target[1] = static_cast(value >> 8); target[2] = static_cast(value >> 16); target[3] = static_cast(value >> 24); @@ -691,18 +929,18 @@ inline uint8* CodedOutputStream::WriteLittleEndian32ToArray(uint32 value, inline uint8* CodedOutputStream::WriteLittleEndian64ToArray(uint64 value, uint8* target) { -#if !defined(PROTOBUF_TEST_NOT_LITTLE_ENDIAN) && \ +#if !defined(PROTOBUF_DISABLE_LITTLE_ENDIAN_OPT_FOR_TEST) && \ defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN memcpy(target, &value, sizeof(value)); #else uint32 part0 = static_cast(value); uint32 part1 = static_cast(value >> 32); - target[0] = static_cast(part0 ); + target[0] = static_cast(part0); target[1] = static_cast(part0 >> 8); target[2] = static_cast(part0 >> 16); target[3] = static_cast(part0 >> 24); - target[4] = static_cast(part1 ); + target[4] = static_cast(part1); target[5] = static_cast(part1 >> 8); target[6] = static_cast(part1 >> 16); target[7] = static_cast(part1 >> 24); @@ -759,7 +997,6 @@ inline int CodedOutputStream::ByteCount() const { inline void CodedInputStream::Advance(int amount) { buffer_ += amount; - buffer_size_ -= amount; } inline void CodedOutputStream::Advance(int amount) { @@ -780,6 +1017,72 @@ inline void CodedInputStream::DecrementRecursionDepth() { if (recursion_depth_ > 0) --recursion_depth_; } +inline void CodedInputStream::SetExtensionRegistry(DescriptorPool* pool, + MessageFactory* factory) { + extension_pool_ = pool; + extension_factory_ = factory; +} + +inline const DescriptorPool* CodedInputStream::GetExtensionPool() { + return extension_pool_; +} + +inline MessageFactory* CodedInputStream::GetExtensionFactory() { + return extension_factory_; +} + +inline int CodedInputStream::BufferSize() const { + return buffer_end_ - buffer_; +} + +inline CodedInputStream::CodedInputStream(ZeroCopyInputStream* input) + : input_(input), + buffer_(NULL), + buffer_end_(NULL), + total_bytes_read_(0), + overflow_bytes_(0), + last_tag_(0), + legitimate_message_end_(false), + aliasing_enabled_(false), + current_limit_(INT_MAX), + buffer_size_after_limit_(0), + total_bytes_limit_(kDefaultTotalBytesLimit), + total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), + recursion_depth_(0), + recursion_limit_(kDefaultRecursionLimit), + extension_pool_(NULL), + extension_factory_(NULL) { + // Eagerly Refresh() so buffer space is immediately available. + Refresh(); +} + +inline CodedInputStream::CodedInputStream(const uint8* buffer, int size) + : input_(NULL), + buffer_(buffer), + buffer_end_(buffer + size), + total_bytes_read_(size), + overflow_bytes_(0), + last_tag_(0), + legitimate_message_end_(false), + aliasing_enabled_(false), + current_limit_(size), + buffer_size_after_limit_(0), + total_bytes_limit_(kDefaultTotalBytesLimit), + total_bytes_warning_threshold_(kDefaultTotalBytesWarningThreshold), + recursion_depth_(0), + recursion_limit_(kDefaultRecursionLimit), + extension_pool_(NULL), + extension_factory_(NULL) { + // Note that setting current_limit_ == size is important to prevent some + // code paths from trying to access input_ and segfaulting. +} + +inline CodedInputStream::~CodedInputStream() { + if (input_ != NULL) { + BackUpInputToCurrentPosition(); + } +} + } // namespace io } // namespace protobuf diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc index e165fb93..7d298332 100644 --- a/src/google/protobuf/io/coded_stream_unittest.cc +++ b/src/google/protobuf/io/coded_stream_unittest.cc @@ -242,6 +242,24 @@ TEST_1D(CodedStreamTest, ExpectTag, kVarintCases) { } } +TEST_1D(CodedStreamTest, ExpectTagFromArray, kVarintCases) { + memcpy(buffer_, kVarintCases_case.bytes, kVarintCases_case.size); + + const uint32 expected_value = static_cast(kVarintCases_case.value); + + // If the expectation succeeds, it should return a pointer past the tag. + if (kVarintCases_case.size <= 2) { + EXPECT_TRUE(NULL == + CodedInputStream::ExpectTagFromArray(buffer_, + expected_value + 1)); + EXPECT_TRUE(buffer_ + kVarintCases_case.size == + CodedInputStream::ExpectTagFromArray(buffer_, expected_value)); + } else { + EXPECT_TRUE(NULL == + CodedInputStream::ExpectTagFromArray(buffer_, expected_value)); + } +} + TEST_2D(CodedStreamTest, ReadVarint64, kVarintCases, kBlockSizes) { memcpy(buffer_, kVarintCases_case.bytes, kVarintCases_case.size); ArrayInputStream input(buffer_, sizeof(buffer_), kBlockSizes_case); @@ -529,10 +547,32 @@ TEST_2D(CodedStreamTest, WriteLittleEndian64, kFixed64Cases, kBlockSizes) { EXPECT_EQ(0, memcmp(buffer_, kFixed64Cases_case.bytes, sizeof(uint64))); } +// Tests using the static methods to read fixed-size values from raw arrays. + +TEST_1D(CodedStreamTest, ReadLittleEndian32FromArray, kFixed32Cases) { + memcpy(buffer_, kFixed32Cases_case.bytes, sizeof(kFixed32Cases_case.bytes)); + + uint32 value; + const uint8* end = CodedInputStream::ReadLittleEndian32FromArray( + buffer_, &value); + EXPECT_EQ(kFixed32Cases_case.value, value); + EXPECT_TRUE(end == buffer_ + sizeof(value)); +} + +TEST_1D(CodedStreamTest, ReadLittleEndian64FromArray, kFixed64Cases) { + memcpy(buffer_, kFixed64Cases_case.bytes, sizeof(kFixed64Cases_case.bytes)); + + uint64 value; + const uint8* end = CodedInputStream::ReadLittleEndian64FromArray( + buffer_, &value); + EXPECT_EQ(kFixed64Cases_case.value, value); + EXPECT_TRUE(end == buffer_ + sizeof(value)); +} + // ------------------------------------------------------------------- // Raw reads and writes -const char kRawBytes[] = "Some bytes which will be writted and read raw."; +const char kRawBytes[] = "Some bytes which will be written and read raw."; TEST_1D(CodedStreamTest, ReadRaw, kBlockSizes) { memcpy(buffer_, kRawBytes, sizeof(kRawBytes)); @@ -593,6 +633,22 @@ TEST_1D(CodedStreamTest, ReadStringImpossiblyLarge, kBlockSizes) { } } +TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnStack) { + // Same test as above, except directly use a buffer. This used to cause + // crashes while the above did not. + uint8 buffer[8]; + CodedInputStream coded_input(buffer, 8); + string str; + EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30)); +} + +TEST_F(CodedStreamTest, ReadStringImpossiblyLargeFromStringOnHeap) { + scoped_array buffer(new uint8[8]); + CodedInputStream coded_input(buffer.get(), 8); + string str; + EXPECT_FALSE(coded_input.ReadString(&str, 1 << 30)); +} + // ------------------------------------------------------------------- // Skip @@ -652,6 +708,36 @@ TEST_F(CodedStreamTest, GetDirectBufferPointerInput) { EXPECT_EQ(8, size); } +TEST_F(CodedStreamTest, GetDirectBufferPointerInlineInput) { + ArrayInputStream input(buffer_, sizeof(buffer_), 8); + CodedInputStream coded_input(&input); + + const void* ptr; + int size; + + coded_input.GetDirectBufferPointerInline(&ptr, &size); + EXPECT_EQ(buffer_, ptr); + EXPECT_EQ(8, size); + + // Peeking again should return the same pointer. + coded_input.GetDirectBufferPointerInline(&ptr, &size); + EXPECT_EQ(buffer_, ptr); + EXPECT_EQ(8, size); + + // Skip forward in the same buffer then peek again. + EXPECT_TRUE(coded_input.Skip(3)); + coded_input.GetDirectBufferPointerInline(&ptr, &size); + EXPECT_EQ(buffer_ + 3, ptr); + EXPECT_EQ(5, size); + + // Skip to end of buffer and peek -- should return false and provide an empty + // buffer. It does not try to Refresh(). + EXPECT_TRUE(coded_input.Skip(5)); + coded_input.GetDirectBufferPointerInline(&ptr, &size); + EXPECT_EQ(buffer_ + 8, ptr); + EXPECT_EQ(0, size); +} + TEST_F(CodedStreamTest, GetDirectBufferPointerOutput) { ArrayOutputStream output(buffer_, sizeof(buffer_), 8); CodedOutputStream coded_output(&output); diff --git a/src/google/protobuf/io/gzip_stream.cc b/src/google/protobuf/io/gzip_stream.cc index 84d277f4..e1a35ea2 100644 --- a/src/google/protobuf/io/gzip_stream.cc +++ b/src/google/protobuf/io/gzip_stream.cc @@ -315,6 +315,6 @@ bool GzipOutputStream::Close() { } // namespace io } // namespace protobuf -} // namespace google #endif // HAVE_ZLIB +} // namespace google diff --git a/src/google/protobuf/io/printer.cc b/src/google/protobuf/io/printer.cc index 937d777e..c7d3074d 100644 --- a/src/google/protobuf/io/printer.cc +++ b/src/google/protobuf/io/printer.cc @@ -65,10 +65,10 @@ void Printer::Print(const map& variables, const char* text) { if (text[i] == '\n') { // Saw newline. If there is more text, we may need to insert an indent // here. So, write what we have so far, including the '\n'. - Write(text + pos, i - pos + 1); + WriteRaw(text + pos, i - pos + 1); pos = i + 1; - // Setting this true will cause the next Write() to insert an indent + // Setting this true will cause the next WriteRaw() to insert an indent // first. at_start_of_line_ = true; @@ -76,7 +76,7 @@ void Printer::Print(const map& variables, const char* text) { // Saw the start of a variable name. // Write what we have so far. - Write(text + pos, i - pos); + WriteRaw(text + pos, i - pos); pos = i + 1; // Find closing delimiter. @@ -90,14 +90,14 @@ void Printer::Print(const map& variables, const char* text) { string varname(text + pos, endpos - pos); if (varname.empty()) { // Two delimiters in a row reduce to a literal delimiter character. - Write(&variable_delimiter_, 1); + WriteRaw(&variable_delimiter_, 1); } else { // Replace with the variable's value. map::const_iterator iter = variables.find(varname); if (iter == variables.end()) { GOOGLE_LOG(DFATAL) << " Undefined variable: " << varname; } else { - Write(iter->second.data(), iter->second.size()); + WriteRaw(iter->second.data(), iter->second.size()); } } @@ -108,7 +108,7 @@ void Printer::Print(const map& variables, const char* text) { } // Write the rest. - Write(text + pos, size - pos); + WriteRaw(text + pos, size - pos); } void Printer::Print(const char* text) { @@ -145,14 +145,23 @@ void Printer::Outdent() { indent_.resize(indent_.size() - 2); } -void Printer::Write(const char* data, int size) { +void Printer::PrintRaw(const string& data) { + WriteRaw(data.data(), data.size()); +} + +void Printer::PrintRaw(const char* data) { + if (failed_) return; + WriteRaw(data, strlen(data)); +} + +void Printer::WriteRaw(const char* data, int size) { if (failed_) return; if (size == 0) return; if (at_start_of_line_) { // Insert an indent. at_start_of_line_ = false; - Write(indent_.data(), indent_.size()); + WriteRaw(indent_.data(), indent_.size()); if (failed_) return; } diff --git a/src/google/protobuf/io/printer.h b/src/google/protobuf/io/printer.h index b7c4cf39..de085389 100644 --- a/src/google/protobuf/io/printer.h +++ b/src/google/protobuf/io/printer.h @@ -59,8 +59,8 @@ class ZeroCopyOutputStream; // zero_copy_stream.h // The above writes "My name is Bob." to the output stream. // // Printer aggressively enforces correct usage, crashing (with assert failures) -// in the case of undefined variables. This helps greatly in debugging code -// which uses it. This class is not intended to be used by production servers. +// in the case of undefined variables in debug builds. This helps greatly in +// debugging code which uses it. class LIBPROTOBUF_EXPORT Printer { public: // Create a printer that writes text to the given output stream. Use the @@ -94,15 +94,24 @@ class LIBPROTOBUF_EXPORT Printer { // level is zero. void Outdent(); + // Write a string to the output buffer. + // This method does not look for newlines to add indentation. + void PrintRaw(const string& data); + + // Write a zero-delimited string to output buffer. + // This method does not look for newlines to add indentation. + void PrintRaw(const char* data); + + // Write some bytes to the output buffer. + // This method does not look for newlines to add indentation. + void WriteRaw(const char* data, int size); + // True if any write to the underlying stream failed. (We don't just // crash in this case because this is an I/O failure, not a programming // error.) bool failed() const { return failed_; } private: - // Write some text to the output buffer. - void Write(const char* data, int size); - const char variable_delimiter_; ZeroCopyOutputStream* const output_; diff --git a/src/google/protobuf/io/printer_unittest.cc b/src/google/protobuf/io/printer_unittest.cc index 69c7ee34..580a53da 100644 --- a/src/google/protobuf/io/printer_unittest.cc +++ b/src/google/protobuf/io/printer_unittest.cc @@ -76,10 +76,38 @@ TEST(Printer, BasicPrinting) { buffer[output.ByteCount()] = '\0'; - EXPECT_STREQ(buffer, - "Hello World! This is the same line.\n" - "But this is a new one.\n" - "And this is another one."); + EXPECT_STREQ("Hello World! This is the same line.\n" + "But this is a new one.\n" + "And this is another one.", + buffer); + } +} + +TEST(Printer, WriteRaw) { + char buffer[8192]; + + for (int block_size = 1; block_size < 512; block_size *= 2) { + ArrayOutputStream output(buffer, sizeof(buffer), block_size); + + { + string string_obj = "From an object\n"; + Printer printer(&output, '$'); + printer.WriteRaw("Hello World!", 12); + printer.PrintRaw(" This is the same line.\n"); + printer.PrintRaw("But this is a new one.\nAnd this is another one."); + printer.WriteRaw("\n", 1); + printer.PrintRaw(string_obj); + EXPECT_FALSE(printer.failed()); + } + + buffer[output.ByteCount()] = '\0'; + + EXPECT_STREQ("Hello World! This is the same line.\n" + "But this is a new one.\n" + "And this is another one." + "\n" + "From an object\n", + buffer); } } @@ -98,6 +126,7 @@ TEST(Printer, VariableSubstitution) { vars["abcdefg"] = "1234"; printer.Print(vars, "Hello $foo$!\nbar = $bar$\n"); + printer.PrintRaw("RawBit\n"); printer.Print(vars, "$abcdefg$\nA literal dollar sign: $$"); vars["foo"] = "blah"; @@ -108,12 +137,13 @@ TEST(Printer, VariableSubstitution) { buffer[output.ByteCount()] = '\0'; - EXPECT_STREQ(buffer, - "Hello World!\n" - "bar = $foo$\n" - "1234\n" - "A literal dollar sign: $\n" - "Now foo = blah."); + EXPECT_STREQ("Hello World!\n" + "bar = $foo$\n" + "RawBit\n" + "1234\n" + "A literal dollar sign: $\n" + "Now foo = blah.", + buffer); } } @@ -125,15 +155,17 @@ TEST(Printer, InlineVariableSubstitution) { { Printer printer(&output, '$'); printer.Print("Hello $foo$!\n", "foo", "World"); + printer.PrintRaw("RawBit\n"); printer.Print("$foo$ $bar$\n", "foo", "one", "bar", "two"); EXPECT_FALSE(printer.failed()); } buffer[output.ByteCount()] = '\0'; - EXPECT_STREQ(buffer, - "Hello World!\n" - "one two\n"); + EXPECT_STREQ("Hello World!\n" + "RawBit\n" + "one two\n", + buffer); } TEST(Printer, Indenting) { @@ -156,6 +188,8 @@ TEST(Printer, Indenting) { printer.Indent(); printer.Print(" And this is still the same line.\n" "But this is indented.\n"); + printer.PrintRaw("RawBit has indent at start\n"); + printer.PrintRaw("but not after a raw newline\n"); printer.Print(vars, "Note that a newline in a variable will break " "indenting, as we see$newline$here.\n"); printer.Indent(); @@ -169,16 +203,19 @@ TEST(Printer, Indenting) { buffer[output.ByteCount()] = '\0'; - EXPECT_STREQ(buffer, + EXPECT_STREQ( "This is not indented.\n" " This is indented\n" " And so is this\n" "But this is not. And this is still the same line.\n" " But this is indented.\n" - " Note that a newline in a variable will break indenting, as we see\n" + " RawBit has indent at start\n" + "but not after a raw newline\n" + "Note that a newline in a variable will break indenting, as we see\n" "here.\n" " And this is double-indented\n" - "Back to normal."); + "Back to normal.", + buffer); } } diff --git a/src/google/protobuf/io/tokenizer.cc b/src/google/protobuf/io/tokenizer.cc index 0bda451b..75cbfed5 100644 --- a/src/google/protobuf/io/tokenizer.cc +++ b/src/google/protobuf/io/tokenizer.cc @@ -119,7 +119,7 @@ namespace { CHARACTER_CLASS(Whitespace, c == ' ' || c == '\n' || c == '\t' || c == '\r' || c == '\v'); -CHARACTER_CLASS(Unprintable, c < ' ' && c != '\0'); +CHARACTER_CLASS(Unprintable, c < ' ' && c > '\0'); CHARACTER_CLASS(Digit, '0' <= c && c <= '9'); CHARACTER_CLASS(OctalDigit, '0' <= c && c <= '7'); diff --git a/src/google/protobuf/io/tokenizer.h b/src/google/protobuf/io/tokenizer.h index 98386e0b..d115161f 100644 --- a/src/google/protobuf/io/tokenizer.h +++ b/src/google/protobuf/io/tokenizer.h @@ -63,6 +63,11 @@ class LIBPROTOBUF_EXPORT ErrorCollector { // 1 to each before printing them. virtual void AddError(int line, int column, const string& message) = 0; + // Indicates that there was a warning in the input at the given line and + // column numbers. The numbers are zero-based, so you may want to add + // 1 to each before printing them. + virtual void AddWarning(int line, int column, const string& message) { } + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ErrorCollector); }; diff --git a/src/google/protobuf/io/tokenizer_unittest.cc b/src/google/protobuf/io/tokenizer_unittest.cc index eac1455d..3598e188 100644 --- a/src/google/protobuf/io/tokenizer_unittest.cc +++ b/src/google/protobuf/io/tokenizer_unittest.cc @@ -397,6 +397,12 @@ MultiTokenCase kMultiTokenCases[] = { { Tokenizer::TYPE_IDENTIFIER, "baz", 1, 0 }, { Tokenizer::TYPE_END , "" , 1, 3 }, }}, + + // Bytes with the high-order bit set should not be seen as control characters. + { "\300", { + { Tokenizer::TYPE_SYMBOL, "\300", 0, 0 }, + { Tokenizer::TYPE_END , "" , 0, 1 }, + }}, }; TEST_2D(TokenizerTest, MultipleTokens, kMultiTokenCases, kBlockSizes) { diff --git a/src/google/protobuf/io/zero_copy_stream_impl.h b/src/google/protobuf/io/zero_copy_stream_impl.h index 64e96cd4..9fedb005 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl.h +++ b/src/google/protobuf/io/zero_copy_stream_impl.h @@ -133,10 +133,11 @@ class LIBPROTOBUF_EXPORT FileInputStream : public ZeroCopyInputStream { // A ZeroCopyOutputStream which writes to a file descriptor. // -// FileInputStream is preferred over using an ofstream with OstreamOutputStream. -// The latter will introduce an extra layer of buffering, harming performance. -// Also, it's conceivable that FileInputStream could someday be enhanced -// to use zero-copy file descriptors on OSs which support them. +// FileOutputStream is preferred over using an ofstream with +// OstreamOutputStream. The latter will introduce an extra layer of buffering, +// harming performance. Also, it's conceivable that FileOutputStream could +// someday be enhanced to use zero-copy file descriptors on OSs which +// support them. class LIBPROTOBUF_EXPORT FileOutputStream : public ZeroCopyOutputStream { public: // Creates a stream that writes to the given Unix file descriptor. diff --git a/src/google/protobuf/io/zero_copy_stream_unittest.cc b/src/google/protobuf/io/zero_copy_stream_unittest.cc index f919b7ac..8229ee6d 100644 --- a/src/google/protobuf/io/zero_copy_stream_unittest.cc +++ b/src/google/protobuf/io/zero_copy_stream_unittest.cc @@ -403,7 +403,8 @@ TEST_F(IoTest, CompressionOptions) { string golden; File::ReadFileToStringOrDie( - TestSourceDir() + "/google/protobuf/testdata/golden_message", &golden); + TestSourceDir() + "/google/protobuf/testdata/golden_message", + &golden); GzipOutputStream::Options options; string gzip_compressed = Compress(golden, options); diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index 4e5b662c..d43507cd 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -212,7 +212,7 @@ class GeneratedMessageFactory : public MessageFactory { }; GeneratedMessageFactory* generated_message_factory_ = NULL; -GOOGLE_PROTOBUF_DECLARE_ONCE(generated_message_factory_once_init_); +GoogleOnceType generated_message_factory_once_init_; void ShutdownGeneratedMessageFactory() { delete generated_message_factory_; @@ -227,7 +227,7 @@ GeneratedMessageFactory::GeneratedMessageFactory() {} GeneratedMessageFactory::~GeneratedMessageFactory() {} GeneratedMessageFactory* GeneratedMessageFactory::singleton() { - GoogleOnceInit(&generated_message_factory_once_init_, + ::google::protobuf::GoogleOnceInit(&generated_message_factory_once_init_, &InitGeneratedMessageFactory); return generated_message_factory_; } diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h index 54b596d5..c0062f98 100644 --- a/src/google/protobuf/message.h +++ b/src/google/protobuf/message.h @@ -148,6 +148,7 @@ namespace protobuf { // Defined in this file. class Message; class Reflection; +class MessageFactory; // Defined in other files. class Descriptor; // descriptor.h @@ -238,13 +239,15 @@ class LIBPROTOBUF_EXPORT Message : public MessageLite { // Reflection object's SpaceUsed() method. virtual int SpaceUsed() const; - // Debugging ------------------------------------------------------- + // Debugging & Testing---------------------------------------------- // Generates a human readable form of this message, useful for debugging // and other purposes. string DebugString() const; // Like DebugString(), but with less whitespace. string ShortDebugString() const; + // Like DebugString(), but do not escape UTF-8 byte sequences. + string Utf8DebugString() const; // Convenience function useful in GDB. Prints DebugString() to stdout. void PrintDebugString() const; @@ -327,6 +330,7 @@ class LIBPROTOBUF_EXPORT Message : public MessageLite { // GetReflection() wrappers. virtual Metadata GetMetadata() const = 0; + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(Message); }; @@ -453,8 +457,10 @@ class LIBPROTOBUF_EXPORT Reflection { const FieldDescriptor* field) const = 0; virtual const EnumValueDescriptor* GetEnum( const Message& message, const FieldDescriptor* field) const = 0; + // See MutableMessage() for the meaning of the "factory" parameter. virtual const Message& GetMessage(const Message& message, - const FieldDescriptor* field) const = 0; + const FieldDescriptor* field, + MessageFactory* factory = NULL) const = 0; // Get a string value without copying, if possible. // @@ -499,9 +505,19 @@ class LIBPROTOBUF_EXPORT Reflection { virtual void SetEnum (Message* message, const FieldDescriptor* field, const EnumValueDescriptor* value) const = 0; - // Get a mutable pointer to a field with a message type. + // Get a mutable pointer to a field with a message type. If a MessageFactory + // is provided, it will be used to construct instances of the sub-message; + // otherwise, the default factory is used. If the field is an extension that + // does not live in the same pool as the containing message's descriptor (e.g. + // it lives in an overlay pool), then a MessageFactory must be provided. + // If you have no idea what that meant, then you probably don't need to worry + // about it (don't provide a MessageFactory). WARNING: If the + // FieldDescriptor is for a compiled-in extension, then + // factory->GetPrototype(field->message_type() MUST return an instance of the + // compiled-in class for this type, NOT DynamicMessage. virtual Message* MutableMessage(Message* message, - const FieldDescriptor* field) const = 0; + const FieldDescriptor* field, + MessageFactory* factory = NULL) const = 0; // Repeated field getters ------------------------------------------ @@ -603,8 +619,10 @@ class LIBPROTOBUF_EXPORT Reflection { virtual void AddEnum (Message* message, const FieldDescriptor* field, const EnumValueDescriptor* value) const = 0; + // See MutableMessage() for comments on the "factory" parameter. virtual Message* AddMessage(Message* message, - const FieldDescriptor* field) const = 0; + const FieldDescriptor* field, + MessageFactory* factory = NULL) const = 0; // Extensions ------------------------------------------------------ diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc index a53740ad..7c8f37dc 100644 --- a/src/google/protobuf/message_lite.cc +++ b/src/google/protobuf/message_lite.cc @@ -33,9 +33,8 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. - #include - +#include #include #include #include @@ -52,6 +51,24 @@ string MessageLite::InitializationErrorString() const { namespace { +// When serializing, we first compute the byte size, then serialize the message. +// If serialization produces a different number of bytes than expected, we +// call this function, which crashes. The problem could be due to a bug in the +// protobuf implementation but is more likely caused by concurrent modification +// of the message. This function attempts to distinguish between the two and +// provide a useful error message. +void ByteSizeConsistencyError(int byte_size_before_serialization, + int byte_size_after_serialization, + int bytes_produced_by_serialization) { + GOOGLE_CHECK_EQ(byte_size_before_serialization, byte_size_after_serialization) + << "Protocol message was modified concurrently during serialization."; + GOOGLE_CHECK_EQ(bytes_produced_by_serialization, byte_size_before_serialization) + << "Byte size calculation and serialization were inconsistent. This " + "may indicate a bug in protocol buffers or it may be caused by " + "concurrent modification of the message."; + GOOGLE_LOG(FATAL) << "This shouldn't be called if all the sizes are equal."; +} + string InitializationErrorMessage(const char* action, const MessageLite& message) { // Note: We want to avoid depending on strutil in the lite library, otherwise @@ -215,9 +232,29 @@ bool MessageLite::SerializeToCodedStream(io::CodedOutputStream* output) const { bool MessageLite::SerializePartialToCodedStream( io::CodedOutputStream* output) const { - ByteSize(); // Force size to be cached. - SerializeWithCachedSizes(output); - return !output->HadError(); + const int size = ByteSize(); // Force size to be cached. + uint8* buffer = output->GetDirectBufferForNBytesAndAdvance(size); + if (buffer != NULL) { + uint8* end = SerializeWithCachedSizesToArray(buffer); + if (end - buffer != size) { + ByteSizeConsistencyError(size, ByteSize(), end - buffer); + } + return true; + } else { + int original_byte_count = output->ByteCount(); + SerializeWithCachedSizes(output); + if (output->HadError()) { + return false; + } + int final_byte_count = output->ByteCount(); + + if (final_byte_count - original_byte_count != size) { + ByteSizeConsistencyError(size, ByteSize(), + final_byte_count - original_byte_count); + } + + return true; + } } bool MessageLite::SerializeToZeroCopyStream( @@ -243,7 +280,9 @@ bool MessageLite::AppendPartialToString(string* output) const { STLStringResizeUninitialized(output, old_size + byte_size); uint8* start = reinterpret_cast(string_as_array(output) + old_size); uint8* end = SerializeWithCachedSizesToArray(start); - GOOGLE_CHECK_EQ(end - start, byte_size); + if (end - start != byte_size) { + ByteSizeConsistencyError(byte_size, ByteSize(), end - start); + } return true; } @@ -265,9 +304,11 @@ bool MessageLite::SerializeToArray(void* data, int size) const { bool MessageLite::SerializePartialToArray(void* data, int size) const { int byte_size = ByteSize(); if (size < byte_size) return false; - uint8* end = - SerializeWithCachedSizesToArray(reinterpret_cast(data)); - GOOGLE_CHECK_EQ(end, reinterpret_cast(data) + byte_size); + uint8* start = reinterpret_cast(data); + uint8* end = SerializeWithCachedSizesToArray(start); + if (end - start != byte_size) { + ByteSizeConsistencyError(byte_size, ByteSize(), end - start); + } return true; } diff --git a/src/google/protobuf/repeated_field.cc b/src/google/protobuf/repeated_field.cc index 3230c04c..f7beb110 100644 --- a/src/google/protobuf/repeated_field.cc +++ b/src/google/protobuf/repeated_field.cc @@ -39,6 +39,18 @@ namespace google { namespace protobuf { namespace internal { +void RepeatedPtrFieldBase::Reserve(int new_size) { + if (total_size_ >= new_size) return; + + void** old_elements = elements_; + total_size_ = max(total_size_ * 2, new_size); + elements_ = new void*[total_size_]; + memcpy(elements_, old_elements, allocated_size_ * sizeof(elements_[0])); + if (old_elements != initial_space_) { + delete [] old_elements; + } +} + void RepeatedPtrFieldBase::Swap(RepeatedPtrFieldBase* other) { void** swap_elements = elements_; int swap_current_size = current_size_; diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index 1696e2a3..5954db55 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -51,8 +51,8 @@ #include #include - namespace google { + namespace protobuf { class Message; @@ -76,10 +76,11 @@ class RepeatedField { int size() const; - Element Get(int index) const; + const Element& Get(int index) const; Element* Mutable(int index); - void Set(int index, Element value); - void Add(Element value); + void Set(int index, const Element& value); + void Add(const Element& value); + Element* Add(); // Remove the last element in the array. // We don't provide a way to remove any element other than the last // because it invites inefficient use, such as O(n^2) filtering loops @@ -94,6 +95,13 @@ class RepeatedField { // array is grown, it will always be at least doubled in size. void Reserve(int new_size); + // Resize the RepeatedField to a new, smaller size. This is O(1). + void Truncate(int new_size); + + void AddAlreadyReserved(const Element& value); + Element* AddAlreadyReserved(); + int Capacity() const; + // Gets the underlying array. This pointer is possibly invalidated by // any add or remove operation. Element* mutable_data(); @@ -128,10 +136,19 @@ class RepeatedField { int total_size_; Element initial_space_[kInitialSize]; + + // Move the contents of |from| into |to|, possibly clobbering |from| in the + // process. For primitive types this is just a memcpy(), but it could be + // specialized for non-primitive types to, say, swap each element instead. + void MoveArray(Element to[], Element from[], int size); + + // Copy the elements of |from| into |to|. + void CopyArray(Element to[], const Element from[], int size); }; namespace internal { template class RepeatedPtrIterator; +template class RepeatedPtrOverPtrsIterator; } // namespace internal namespace internal { @@ -189,8 +206,11 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { void Reserve(int new_size); + int Capacity() const; + // Used for constructing iterators. void* const* raw_data() const; + void** raw_mutable_data() const; template typename TypeHandler::Type** mutable_data(); @@ -204,6 +224,7 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { template int SpaceUsedExcludingSelf() const; + // Advanced memory management -------------------------------------- // Like Add(), but if there are no cleared objects to use, returns NULL. @@ -215,7 +236,7 @@ class LIBPROTOBUF_EXPORT RepeatedPtrFieldBase { template typename TypeHandler::Type* ReleaseLast(); - int ClearedCount(); + int ClearedCount() const; template void AddCleared(typename TypeHandler::Type* value); template @@ -279,13 +300,14 @@ class LIBPROTOBUF_EXPORT StringTypeHandlerBase { static void Merge(const string& from, string* to) { *to = from; } }; -class StringTypeHandler : public StringTypeHandlerBase { +class LIBPROTOBUF_EXPORT StringTypeHandler : public StringTypeHandlerBase { public: static int SpaceUsed(const string& value) { return sizeof(value) + StringSpaceUsedExcludingSelf(value); } }; + } // namespace internal // RepeatedPtrField is like RepeatedField, but used for repeated strings or @@ -311,6 +333,8 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { // array is grown, it will always be at least doubled in size. void Reserve(int new_size); + int Capacity() const; + // Gets the underlying array. This pointer is possibly invalidated by // any add or remove operation. Element** mutable_data(); @@ -331,6 +355,12 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { iterator end(); const_iterator end() const; + // Custom STL-like iterator that iterates over and returns the underlying + // pointers to Element rather than Element itself. + typedef internal::RepeatedPtrOverPtrsIterator pointer_iterator; + pointer_iterator pointer_begin(); + pointer_iterator pointer_end(); + // Returns (an estimate of) the number of bytes used by the repeated field, // excluding sizeof(*this). int SpaceUsedExcludingSelf() const; @@ -363,7 +393,7 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { // Get the number of cleared objects that are currently being kept // around for reuse. - int ClearedCount(); + int ClearedCount() const; // Add an element to the pool of cleared objects, passing ownership to // the RepeatedPtrField. The element must be cleared prior to calling // this method. @@ -373,16 +403,16 @@ class RepeatedPtrField : public internal::RepeatedPtrFieldBase { // Requires: ClearedCount() > 0 Element* ReleaseCleared(); - private: + protected: + // Note: RepeatedPtrField SHOULD NOT be subclassed by users. We only + // subclass it in one place as a hack for compatibility with proto1. The + // subclass needs to know about TypeHandler in order to call protected + // methods on RepeatedPtrFieldBase. class TypeHandler; - GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrField); - // prototype_ is used for RepeatedPtrField and - // RepeatedPtrField only (see constructor). - // TODO(kenton): Can we use some template magic to avoid wasting space on - // this field when it isn't used? - const Element* prototype_; + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPtrField); }; // implementation ==================================================== @@ -406,9 +436,25 @@ inline int RepeatedField::size() const { return current_size_; } +template +inline int RepeatedField::Capacity() const { + return total_size_; +} + +template +inline void RepeatedField::AddAlreadyReserved(const Element& value) { + GOOGLE_DCHECK_LT(size(), Capacity()); + elements_[current_size_++] = value; +} + +template +inline Element* RepeatedField::AddAlreadyReserved() { + GOOGLE_DCHECK_LT(size(), Capacity()); + return &elements_[current_size_++]; +} template -inline Element RepeatedField::Get(int index) const { +inline const Element& RepeatedField::Get(int index) const { GOOGLE_DCHECK_LT(index, size()); return elements_[index]; } @@ -420,17 +466,23 @@ inline Element* RepeatedField::Mutable(int index) { } template -inline void RepeatedField::Set(int index, Element value) { +inline void RepeatedField::Set(int index, const Element& value) { GOOGLE_DCHECK_LT(index, size()); elements_[index] = value; } template -inline void RepeatedField::Add(Element value) { +inline void RepeatedField::Add(const Element& value) { if (current_size_ == total_size_) Reserve(total_size_ + 1); elements_[current_size_++] = value; } +template +inline Element* RepeatedField::Add() { + if (current_size_ == total_size_) Reserve(total_size_ + 1); + return &elements_[current_size_++]; +} + template inline void RepeatedField::RemoveLast() { GOOGLE_DCHECK_GT(current_size_, 0); @@ -443,10 +495,9 @@ inline void RepeatedField::Clear() { } template -void RepeatedField::MergeFrom(const RepeatedField& other) { +inline void RepeatedField::MergeFrom(const RepeatedField& other) { Reserve(current_size_ + other.current_size_); - memcpy(elements_ + current_size_, other.elements_, - sizeof(Element) * other.current_size_); + CopyArray(elements_ + current_size_, other.elements_, other.current_size_); current_size_ += other.current_size_; } @@ -469,17 +520,17 @@ void RepeatedField::Swap(RepeatedField* other) { // We may not be using initial_space_ but it's not worth checking. Just // copy it anyway. Element swap_initial_space[kInitialSize]; - memcpy(swap_initial_space, initial_space_, sizeof(initial_space_)); + MoveArray(swap_initial_space, initial_space_, kInitialSize); elements_ = other->elements_; current_size_ = other->current_size_; total_size_ = other->total_size_; - memcpy(initial_space_, other->initial_space_, sizeof(initial_space_)); + MoveArray(initial_space_, other->initial_space_, kInitialSize); other->elements_ = swap_elements; other->current_size_ = swap_current_size; other->total_size_ = swap_total_size; - memcpy(other->initial_space_, swap_initial_space, sizeof(swap_initial_space)); + MoveArray(other->initial_space_, swap_initial_space, kInitialSize); if (elements_ == other->initial_space_) { elements_ = initial_space_; @@ -520,19 +571,40 @@ inline int RepeatedField::SpaceUsedExcludingSelf() const { return (elements_ != initial_space_) ? total_size_ * sizeof(elements_[0]) : 0; } +// Avoid inlining of Reserve(): new, memcpy, and delete[] lead to a significant +// amount of code bloat. template -inline void RepeatedField::Reserve(int new_size) { +void RepeatedField::Reserve(int new_size) { if (total_size_ >= new_size) return; Element* old_elements = elements_; total_size_ = max(total_size_ * 2, new_size); elements_ = new Element[total_size_]; - memcpy(elements_, old_elements, current_size_ * sizeof(elements_[0])); + MoveArray(elements_, old_elements, current_size_); if (old_elements != initial_space_) { delete [] old_elements; } } +template +inline void RepeatedField::Truncate(int new_size) { + GOOGLE_DCHECK_LE(new_size, current_size_); + current_size_ = new_size; +} + +template +inline void RepeatedField::MoveArray( + Element to[], Element from[], int size) { + memcpy(to, from, size * sizeof(Element)); +} + +template +inline void RepeatedField::CopyArray( + Element to[], const Element from[], int size) { + memcpy(to, from, size * sizeof(Element)); +} + + // ------------------------------------------------------------------- namespace internal { @@ -600,17 +672,25 @@ void RepeatedPtrFieldBase::Clear() { } template -void RepeatedPtrFieldBase::MergeFrom(const RepeatedPtrFieldBase& other) { +inline void RepeatedPtrFieldBase::MergeFrom(const RepeatedPtrFieldBase& other) { Reserve(current_size_ + other.current_size_); for (int i = 0; i < other.current_size_; i++) { TypeHandler::Merge(other.Get(i), Add()); } } +inline int RepeatedPtrFieldBase::Capacity() const { + return total_size_; +} + inline void* const* RepeatedPtrFieldBase::raw_data() const { return elements_; } +inline void** RepeatedPtrFieldBase::raw_mutable_data() const { + return elements_; +} + template inline typename TypeHandler::Type** RepeatedPtrFieldBase::mutable_data() { // TODO(kenton): Breaks C++ aliasing rules. We should probably remove this @@ -650,15 +730,29 @@ inline typename TypeHandler::Type* RepeatedPtrFieldBase::AddFromCleared() { } template -inline void RepeatedPtrFieldBase::AddAllocated( +void RepeatedPtrFieldBase::AddAllocated( typename TypeHandler::Type* value) { - if (allocated_size_ == total_size_) Reserve(total_size_ + 1); - // We don't care about the order of cleared elements, so if there's one - // in the way, just move it to the back of the array. - if (current_size_ < allocated_size_) { + // Make room for the new pointer. + if (current_size_ == total_size_) { + // The array is completely full with no cleared objects, so grow it. + Reserve(total_size_ + 1); + ++allocated_size_; + } else if (allocated_size_ == total_size_) { + // There is no more space in the pointer array because it contains some + // cleared objects awaiting reuse. We don't want to grow the array in this + // case because otherwise a loop calling AddAllocated() followed by Clear() + // would leak memory. + TypeHandler::Delete(cast(elements_[current_size_])); + } else if (current_size_ < allocated_size_) { + // We have some cleared objects. We don't care about their order, so we + // can just move the first one to the end to make space. elements_[allocated_size_] = elements_[current_size_]; + ++allocated_size_; + } else { + // There are no cleared objects. + ++allocated_size_; } - ++allocated_size_; + elements_[current_size_++] = value; } @@ -677,7 +771,7 @@ inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseLast() { } -inline int RepeatedPtrFieldBase::ClearedCount() { +inline int RepeatedPtrFieldBase::ClearedCount() const { return allocated_size_ - current_size_; } @@ -694,18 +788,6 @@ inline typename TypeHandler::Type* RepeatedPtrFieldBase::ReleaseCleared() { return cast(elements_[--allocated_size_]); } -inline void RepeatedPtrFieldBase::Reserve(int new_size) { - if (total_size_ >= new_size) return; - - void** old_elements = elements_; - total_size_ = max(total_size_ * 2, new_size); - elements_ = new void*[total_size_]; - memcpy(elements_, old_elements, allocated_size_ * sizeof(elements_[0])); - if (old_elements != initial_space_) { - delete [] old_elements; - } -} - } // namespace internal // ------------------------------------------------------------------- @@ -720,9 +802,7 @@ class RepeatedPtrField::TypeHandler template -inline RepeatedPtrField::RepeatedPtrField() - : prototype_(NULL) { -} +inline RepeatedPtrField::RepeatedPtrField() {} template RepeatedPtrField::~RepeatedPtrField() { @@ -802,7 +882,7 @@ inline Element* RepeatedPtrField::ReleaseLast() { template -inline int RepeatedPtrField::ClearedCount() { +inline int RepeatedPtrField::ClearedCount() const { return RepeatedPtrFieldBase::ClearedCount(); } @@ -821,6 +901,11 @@ inline void RepeatedPtrField::Reserve(int new_size) { return RepeatedPtrFieldBase::Reserve(new_size); } +template +inline int RepeatedPtrField::Capacity() const { + return RepeatedPtrFieldBase::Capacity(); +} + // ------------------------------------------------------------------- namespace internal { @@ -921,6 +1006,84 @@ class RepeatedPtrIterator void* const* it_; }; +// Provide an iterator that operates on pointers to the underlying objects +// rather than the objects themselves as RepeatedPtrIterator does. +// Consider using this when working with stl algorithms that change +// the array. +template +class RepeatedPtrOverPtrsIterator + : public std::iterator { + public: + typedef RepeatedPtrOverPtrsIterator iterator; + typedef std::iterator< + std::random_access_iterator_tag, Element*> superclass; + + // Let the compiler know that these are type names, so we don't have to + // write "typename" in front of them everywhere. + typedef typename superclass::reference reference; + typedef typename superclass::pointer pointer; + typedef typename superclass::difference_type difference_type; + + RepeatedPtrOverPtrsIterator() : it_(NULL) {} + explicit RepeatedPtrOverPtrsIterator(void** it) : it_(it) {} + + // dereferenceable + reference operator*() const { return *reinterpret_cast(it_); } + pointer operator->() const { return &(operator*()); } + + // {inc,dec}rementable + iterator& operator++() { ++it_; return *this; } + iterator operator++(int) { return iterator(it_++); } + iterator& operator--() { --it_; return *this; } + iterator operator--(int) { return iterator(it_--); } + + // equality_comparable + bool operator==(const iterator& x) const { return it_ == x.it_; } + bool operator!=(const iterator& x) const { return it_ != x.it_; } + + // less_than_comparable + bool operator<(const iterator& x) const { return it_ < x.it_; } + bool operator<=(const iterator& x) const { return it_ <= x.it_; } + bool operator>(const iterator& x) const { return it_ > x.it_; } + bool operator>=(const iterator& x) const { return it_ >= x.it_; } + + // addable, subtractable + iterator& operator+=(difference_type d) { + it_ += d; + return *this; + } + friend iterator operator+(iterator it, difference_type d) { + it += d; + return it; + } + friend iterator operator+(difference_type d, iterator it) { + it += d; + return it; + } + iterator& operator-=(difference_type d) { + it_ -= d; + return *this; + } + friend iterator operator-(iterator it, difference_type d) { + it -= d; + return it; + } + + // indexable + reference operator[](difference_type d) const { return *(*this + d); } + + // random access iterator + difference_type operator-(const iterator& x) const { return it_ - x.it_; } + + private: + template + friend class RepeatedPtrIterator; + + // The internal iterator. + void** it_; +}; + + } // namespace internal template @@ -944,6 +1107,18 @@ RepeatedPtrField::end() const { return iterator(raw_data() + size()); } +template +inline typename RepeatedPtrField::pointer_iterator +RepeatedPtrField::pointer_begin() { + return pointer_iterator(raw_mutable_data()); +} +template +inline typename RepeatedPtrField::pointer_iterator +RepeatedPtrField::pointer_end() { + return pointer_iterator(raw_mutable_data() + size()); +} + + // Iterators and helper functions that follow the spirit of the STL // std::back_insert_iterator and std::back_inserter but are tailor-made // for RepeatedField and RepatedPtrField. Typical usage would be: diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc index 2d87ba88..798b05ee 100644 --- a/src/google/protobuf/repeated_field_unittest.cc +++ b/src/google/protobuf/repeated_field_unittest.cc @@ -37,6 +37,7 @@ #include #include +#include #include @@ -241,6 +242,29 @@ TEST(RepeatedField, MutableDataIsMutable) { EXPECT_EQ(2, field.Get(0)); } +TEST(RepeatedField, Truncate) { + RepeatedField field; + + field.Add(12); + field.Add(34); + field.Add(56); + field.Add(78); + EXPECT_EQ(4, field.size()); + + field.Truncate(3); + EXPECT_EQ(3, field.size()); + + field.Add(90); + EXPECT_EQ(4, field.size()); + EXPECT_EQ(90, field.Get(3)); + + // Truncations that don't change the size are allowed, but growing is not + // allowed. + field.Truncate(field.size()); + EXPECT_DEBUG_DEATH(field.Truncate(field.size() + 1), "new_size"); +} + + // =================================================================== // RepeatedPtrField tests. These pretty much just mirror the RepeatedField // tests above. @@ -443,6 +467,52 @@ TEST(RepeatedPtrField, ClearedElements) { EXPECT_EQ(field.ClearedCount(), 0); } +// Test all code paths in AddAllocated(). +TEST(RepeatedPtrField, AddAlocated) { + RepeatedPtrField field; + while (field.size() < field.Capacity()) { + field.Add()->assign("filler"); + } + + int index = field.size(); + + // First branch: Field is at capacity with no cleared objects. + string* foo = new string("foo"); + field.AddAllocated(foo); + EXPECT_EQ(index + 1, field.size()); + EXPECT_EQ(0, field.ClearedCount()); + EXPECT_EQ(foo, &field.Get(index)); + + // Last branch: Field is not at capacity and there are no cleared objects. + string* bar = new string("bar"); + field.AddAllocated(bar); + ++index; + EXPECT_EQ(index + 1, field.size()); + EXPECT_EQ(0, field.ClearedCount()); + EXPECT_EQ(bar, &field.Get(index)); + + // Third branch: Field is not at capacity and there are no cleared objects. + field.RemoveLast(); + string* baz = new string("baz"); + field.AddAllocated(baz); + EXPECT_EQ(index + 1, field.size()); + EXPECT_EQ(1, field.ClearedCount()); + EXPECT_EQ(baz, &field.Get(index)); + + // Second branch: Field is at capacity but has some cleared objects. + while (field.size() < field.Capacity()) { + field.Add()->assign("filler2"); + } + field.RemoveLast(); + index = field.size(); + string* qux = new string("qux"); + field.AddAllocated(qux); + EXPECT_EQ(index + 1, field.size()); + // We should have discarded the cleared object. + EXPECT_EQ(0, field.ClearedCount()); + EXPECT_EQ(qux, &field.Get(index)); +} + TEST(RepeatedPtrField, MergeFrom) { RepeatedPtrField source, destination; @@ -614,6 +684,7 @@ TEST_F(RepeatedPtrFieldIteratorTest, STLAlgorithms_lower_bound) { string v = "f"; RepeatedPtrField::const_iterator it = lower_bound(proto_array_.begin(), proto_array_.end(), v); + EXPECT_EQ(*it, "n"); EXPECT_TRUE(it == proto_array_.begin() + 3); } @@ -624,6 +695,149 @@ TEST_F(RepeatedPtrFieldIteratorTest, Mutation) { EXPECT_EQ("qux", proto_array_.Get(0)); } +// ------------------------------------------------------------------- + +class RepeatedPtrFieldPtrsIteratorTest : public testing::Test { + protected: + virtual void SetUp() { + proto_array_.Add()->assign("foo"); + proto_array_.Add()->assign("bar"); + proto_array_.Add()->assign("baz"); + } + + RepeatedPtrField proto_array_; +}; + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, ConvertiblePtr) { + RepeatedPtrField::pointer_iterator iter = + proto_array_.pointer_begin(); +} + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, MutablePtrIteration) { + RepeatedPtrField::pointer_iterator iter = + proto_array_.pointer_begin(); + EXPECT_EQ("foo", **iter); + ++iter; + EXPECT_EQ("bar", **(iter++)); + EXPECT_EQ("baz", **iter); + ++iter; + EXPECT_TRUE(proto_array_.pointer_end() == iter); + EXPECT_EQ("baz", **(--proto_array_.pointer_end())); +} + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, RandomPtrAccess) { + RepeatedPtrField::pointer_iterator iter = + proto_array_.pointer_begin(); + RepeatedPtrField::pointer_iterator iter2 = iter; + ++iter2; + ++iter2; + EXPECT_TRUE(iter + 2 == iter2); + EXPECT_TRUE(iter == iter2 - 2); + EXPECT_EQ("baz", *iter[2]); + EXPECT_EQ("baz", **(iter + 2)); + EXPECT_EQ(3, proto_array_.end() - proto_array_.begin()); +} + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, ComparablePtr) { + RepeatedPtrField::pointer_iterator iter = + proto_array_.pointer_begin(); + RepeatedPtrField::pointer_iterator iter2 = iter + 1; + EXPECT_TRUE(iter == iter); + EXPECT_TRUE(iter != iter2); + EXPECT_TRUE(iter < iter2); + EXPECT_TRUE(iter <= iter2); + EXPECT_TRUE(iter <= iter); + EXPECT_TRUE(iter2 > iter); + EXPECT_TRUE(iter2 >= iter); + EXPECT_TRUE(iter >= iter); +} + +// Uninitialized iterator does not point to any of the RepeatedPtrOverPtrs. +// Dereferencing an uninitialized iterator crashes the process. +TEST_F(RepeatedPtrFieldPtrsIteratorTest, UninitializedPtrIterator) { + RepeatedPtrField::pointer_iterator iter; + EXPECT_TRUE(iter != proto_array_.pointer_begin()); + EXPECT_TRUE(iter != proto_array_.pointer_begin() + 1); + EXPECT_TRUE(iter != proto_array_.pointer_begin() + 2); + EXPECT_TRUE(iter != proto_array_.pointer_begin() + 3); + EXPECT_TRUE(iter != proto_array_.pointer_end()); +} + + +// This comparison functor is required by the tests for RepeatedPtrOverPtrs. +// They operate on strings and need to compare strings as strings in +// any stl algorithm, even though the iterator returns a pointer to a string +// - i.e. *iter has type string*. +struct StringLessThan { + bool operator()(const string* z, const string& y) { + return *z < y; + } + bool operator()(const string* z, const string* y) { + return *z < *y; + } +}; + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, PtrSTLAlgorithms_lower_bound) { + proto_array_.Clear(); + proto_array_.Add()->assign("a"); + proto_array_.Add()->assign("c"); + proto_array_.Add()->assign("d"); + proto_array_.Add()->assign("n"); + proto_array_.Add()->assign("p"); + proto_array_.Add()->assign("x"); + proto_array_.Add()->assign("y"); + + RepeatedPtrField::pointer_iterator iter = + proto_array_.pointer_begin(); + string v = "f"; + RepeatedPtrField::pointer_iterator it = + lower_bound(proto_array_.pointer_begin(), proto_array_.pointer_end(), + v, StringLessThan()); + + GOOGLE_CHECK(*it != NULL); + + EXPECT_EQ(**it, "n"); + EXPECT_TRUE(it == proto_array_.pointer_begin() + 3); +} + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, PtrMutation) { + RepeatedPtrField::pointer_iterator iter = + proto_array_.pointer_begin(); + **iter = "qux"; + EXPECT_EQ("qux", proto_array_.Get(0)); + + EXPECT_EQ("bar", proto_array_.Get(1)); + EXPECT_EQ("baz", proto_array_.Get(2)); + ++iter; + delete *iter; + *iter = new string("a"); + ++iter; + delete *iter; + *iter = new string("b"); + EXPECT_EQ("a", proto_array_.Get(1)); + EXPECT_EQ("b", proto_array_.Get(2)); +} + +TEST_F(RepeatedPtrFieldPtrsIteratorTest, Sort) { + proto_array_.Add()->assign("c"); + proto_array_.Add()->assign("d"); + proto_array_.Add()->assign("n"); + proto_array_.Add()->assign("p"); + proto_array_.Add()->assign("a"); + proto_array_.Add()->assign("y"); + proto_array_.Add()->assign("x"); + EXPECT_EQ("foo", proto_array_.Get(0)); + EXPECT_EQ("n", proto_array_.Get(5)); + EXPECT_EQ("x", proto_array_.Get(9)); + sort(proto_array_.pointer_begin(), + proto_array_.pointer_end(), + StringLessThan()); + EXPECT_EQ("a", proto_array_.Get(0)); + EXPECT_EQ("baz", proto_array_.Get(2)); + EXPECT_EQ("y", proto_array_.Get(9)); +} + + // ----------------------------------------------------------------------------- // Unit-tests for the insert iterators // google::protobuf::RepeatedFieldBackInserter, diff --git a/src/google/protobuf/stubs/common.h b/src/google/protobuf/stubs/common.h index 3f002373..848ec3ab 100644 --- a/src/google/protobuf/stubs/common.h +++ b/src/google/protobuf/stubs/common.h @@ -171,7 +171,13 @@ static const int64 kint64min = -kint64max - 1; static const uint32 kuint32max = 0xFFFFFFFFu; static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF); -#undef GOOGLE_ATTRIBUTE_ALWAYS_INLINE +// ------------------------------------------------------------------- +// Annotations: Some parts of the code have been annotated in ways that might +// be useful to some compilers or tools, but are not supported universally. +// You can #define these annotations yourself if the default implementation +// is not right for you. + +#ifndef GOOGLE_ATTRIBUTE_ALWAYS_INLINE #if defined(__GNUC__) && (__GNUC__ > 3 ||(__GNUC__ == 3 && __GNUC_MINOR__ >= 1)) // For functions we want to force inline. // Introduced in gcc 3.1. @@ -180,14 +186,35 @@ static const uint64 kuint64max = GOOGLE_ULONGLONG(0xFFFFFFFFFFFFFFFF); // Other compilers will have to figure it out for themselves. #define GOOGLE_ATTRIBUTE_ALWAYS_INLINE #endif +#endif -#undef GOOGLE_ATTRIBUTE_DEPRECATED +#ifndef GOOGLE_ATTRIBUTE_DEPRECATED #ifdef __GNUC__ // If the method/variable/type is used anywhere, produce a warning. #define GOOGLE_ATTRIBUTE_DEPRECATED __attribute__((deprecated)) #else #define GOOGLE_ATTRIBUTE_DEPRECATED #endif +#endif + +#ifndef GOOGLE_PREDICT_TRUE +#ifdef __GNUC__ +// Provided at least since GCC 3.0. +#define GOOGLE_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) +#else +#define GOOGLE_PREDICT_TRUE +#endif +#endif + +// Delimits a block of code which may write to memory which is simultaneously +// written by other threads, but which has been determined to be thread-safe +// (e.g. because it is an idempotent write). +#ifndef GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN +#define GOOGLE_SAFE_CONCURRENT_WRITES_BEGIN() +#endif +#ifndef GOOGLE_SAFE_CONCURRENT_WRITES_END +#define GOOGLE_SAFE_CONCURRENT_WRITES_END() +#endif // =================================================================== // from google3/base/basictypes.h diff --git a/src/google/protobuf/stubs/strutil.cc b/src/google/protobuf/stubs/strutil.cc index 76d9d21e..bb658ba8 100644 --- a/src/google/protobuf/stubs/strutil.cc +++ b/src/google/protobuf/stubs/strutil.cc @@ -425,8 +425,8 @@ string UnescapeCEscapeString(const string& src) { // // Currently only \n, \r, \t, ", ', \ and !isprint() chars are escaped. // ---------------------------------------------------------------------- -static int CEscapeInternal(const char* src, int src_len, char* dest, - int dest_len, bool use_hex) { +int CEscapeInternal(const char* src, int src_len, char* dest, + int dest_len, bool use_hex, bool utf8_safe) { const char* src_end = src + src_len; int used = 0; bool last_hex_escape = false; // true if last output char was \xNN @@ -447,7 +447,9 @@ static int CEscapeInternal(const char* src, int src_len, char* dest, // Note that if we emit \xNN and the src character after that is a hex // digit then that digit must be escaped too to prevent it being // interpreted as part of the character code by C. - if (!isprint(*src) || (last_hex_escape && isxdigit(*src))) { + if ((!utf8_safe || static_cast(*src) < 0x80) && + (!isprint(*src) || + (last_hex_escape && isxdigit(*src)))) { if (dest_len - used < 4) // need space for 4 letter escape return -1; sprintf(dest + used, (use_hex ? "\\x%02x" : "\\%03o"), @@ -469,7 +471,7 @@ static int CEscapeInternal(const char* src, int src_len, char* dest, } int CEscapeString(const char* src, int src_len, char* dest, int dest_len) { - return CEscapeInternal(src, src_len, dest, dest_len, false); + return CEscapeInternal(src, src_len, dest, dest_len, false, false); } // ---------------------------------------------------------------------- @@ -486,11 +488,33 @@ string CEscape(const string& src) { const int dest_length = src.size() * 4 + 1; // Maximum possible expansion scoped_array dest(new char[dest_length]); const int len = CEscapeInternal(src.data(), src.size(), - dest.get(), dest_length, false); + dest.get(), dest_length, false, false); GOOGLE_DCHECK_GE(len, 0); return string(dest.get(), len); } +namespace strings { + +string Utf8SafeCEscape(const string& src) { + const int dest_length = src.size() * 4 + 1; // Maximum possible expansion + scoped_array dest(new char[dest_length]); + const int len = CEscapeInternal(src.data(), src.size(), + dest.get(), dest_length, false, true); + GOOGLE_DCHECK_GE(len, 0); + return string(dest.get(), len); +} + +string CHexEscape(const string& src) { + const int dest_length = src.size() * 4 + 1; // Maximum possible expansion + scoped_array dest(new char[dest_length]); + const int len = CEscapeInternal(src.data(), src.size(), + dest.get(), dest_length, true, false); + GOOGLE_DCHECK_GE(len, 0); + return string(dest.get(), len); +} + +} // namespace strings + // ---------------------------------------------------------------------- // strto32_adaptor() // strtou32_adaptor() diff --git a/src/google/protobuf/stubs/strutil.h b/src/google/protobuf/stubs/strutil.h index c04c1230..777694b7 100644 --- a/src/google/protobuf/stubs/strutil.h +++ b/src/google/protobuf/stubs/strutil.h @@ -265,6 +265,14 @@ LIBPROTOBUF_EXPORT int CEscapeString(const char* src, int src_len, // ---------------------------------------------------------------------- LIBPROTOBUF_EXPORT string CEscape(const string& src); +namespace strings { +// Like CEscape() but does not escape bytes with the upper bit set. +LIBPROTOBUF_EXPORT string Utf8SafeCEscape(const string& src); + +// Like CEscape() but uses hex (\x) escapes instead of octals. +LIBPROTOBUF_EXPORT string CHexEscape(const string& src); +} // namespace strings + // ---------------------------------------------------------------------- // strto32() // strtou32() diff --git a/src/google/protobuf/test_util.cc b/src/google/protobuf/test_util.cc index 0637c0a5..af8b3909 100644 --- a/src/google/protobuf/test_util.cc +++ b/src/google/protobuf/test_util.cc @@ -229,11 +229,11 @@ void TestUtil::ModifyRepeatedFields(unittest::TestAllTypes* message) { message->GetReflection()->SetRepeatedString( message, message->GetDescriptor()->FindFieldByName("repeated_string_piece"), - 1, "424"); + 1, "524"); message->GetReflection()->SetRepeatedString( message, message->GetDescriptor()->FindFieldByName("repeated_cord"), - 1, "425"); + 1, "525"); #endif // !PROTOBUF_TEST_NO_DESCRIPTORS } @@ -692,6 +692,40 @@ void TestUtil::SetPackedFields(unittest::TestPackedTypes* message) { message->add_packed_enum (unittest::FOREIGN_BAZ); } +void TestUtil::SetUnpackedFields(unittest::TestUnpackedTypes* message) { + // The values applied here must match those of SetPackedFields. + + message->add_unpacked_int32 (601); + message->add_unpacked_int64 (602); + message->add_unpacked_uint32 (603); + message->add_unpacked_uint64 (604); + message->add_unpacked_sint32 (605); + message->add_unpacked_sint64 (606); + message->add_unpacked_fixed32 (607); + message->add_unpacked_fixed64 (608); + message->add_unpacked_sfixed32(609); + message->add_unpacked_sfixed64(610); + message->add_unpacked_float (611); + message->add_unpacked_double (612); + message->add_unpacked_bool (true); + message->add_unpacked_enum (unittest::FOREIGN_BAR); + // add a second one of each field + message->add_unpacked_int32 (701); + message->add_unpacked_int64 (702); + message->add_unpacked_uint32 (703); + message->add_unpacked_uint64 (704); + message->add_unpacked_sint32 (705); + message->add_unpacked_sint64 (706); + message->add_unpacked_fixed32 (707); + message->add_unpacked_fixed64 (708); + message->add_unpacked_sfixed32(709); + message->add_unpacked_sfixed64(710); + message->add_unpacked_float (711); + message->add_unpacked_double (712); + message->add_unpacked_bool (false); + message->add_unpacked_enum (unittest::FOREIGN_BAZ); +} + // ------------------------------------------------------------------- void TestUtil::ModifyPackedFields(unittest::TestPackedTypes* message) { @@ -760,6 +794,56 @@ void TestUtil::ExpectPackedFieldsSet(const unittest::TestPackedTypes& message) { EXPECT_EQ(unittest::FOREIGN_BAZ, message.packed_enum(1)); } +void TestUtil::ExpectUnpackedFieldsSet( + const unittest::TestUnpackedTypes& message) { + // The values expected here must match those of ExpectPackedFieldsSet. + + ASSERT_EQ(2, message.unpacked_int32_size ()); + ASSERT_EQ(2, message.unpacked_int64_size ()); + ASSERT_EQ(2, message.unpacked_uint32_size ()); + ASSERT_EQ(2, message.unpacked_uint64_size ()); + ASSERT_EQ(2, message.unpacked_sint32_size ()); + ASSERT_EQ(2, message.unpacked_sint64_size ()); + ASSERT_EQ(2, message.unpacked_fixed32_size ()); + ASSERT_EQ(2, message.unpacked_fixed64_size ()); + ASSERT_EQ(2, message.unpacked_sfixed32_size()); + ASSERT_EQ(2, message.unpacked_sfixed64_size()); + ASSERT_EQ(2, message.unpacked_float_size ()); + ASSERT_EQ(2, message.unpacked_double_size ()); + ASSERT_EQ(2, message.unpacked_bool_size ()); + ASSERT_EQ(2, message.unpacked_enum_size ()); + + EXPECT_EQ(601 , message.unpacked_int32 (0)); + EXPECT_EQ(602 , message.unpacked_int64 (0)); + EXPECT_EQ(603 , message.unpacked_uint32 (0)); + EXPECT_EQ(604 , message.unpacked_uint64 (0)); + EXPECT_EQ(605 , message.unpacked_sint32 (0)); + EXPECT_EQ(606 , message.unpacked_sint64 (0)); + EXPECT_EQ(607 , message.unpacked_fixed32 (0)); + EXPECT_EQ(608 , message.unpacked_fixed64 (0)); + EXPECT_EQ(609 , message.unpacked_sfixed32(0)); + EXPECT_EQ(610 , message.unpacked_sfixed64(0)); + EXPECT_EQ(611 , message.unpacked_float (0)); + EXPECT_EQ(612 , message.unpacked_double (0)); + EXPECT_EQ(true , message.unpacked_bool (0)); + EXPECT_EQ(unittest::FOREIGN_BAR, message.unpacked_enum(0)); + + EXPECT_EQ(701 , message.unpacked_int32 (1)); + EXPECT_EQ(702 , message.unpacked_int64 (1)); + EXPECT_EQ(703 , message.unpacked_uint32 (1)); + EXPECT_EQ(704 , message.unpacked_uint64 (1)); + EXPECT_EQ(705 , message.unpacked_sint32 (1)); + EXPECT_EQ(706 , message.unpacked_sint64 (1)); + EXPECT_EQ(707 , message.unpacked_fixed32 (1)); + EXPECT_EQ(708 , message.unpacked_fixed64 (1)); + EXPECT_EQ(709 , message.unpacked_sfixed32(1)); + EXPECT_EQ(710 , message.unpacked_sfixed64(1)); + EXPECT_EQ(711 , message.unpacked_float (1)); + EXPECT_EQ(712 , message.unpacked_double (1)); + EXPECT_EQ(false, message.unpacked_bool (1)); + EXPECT_EQ(unittest::FOREIGN_BAZ, message.unpacked_enum(1)); +} + // ------------------------------------------------------------------- void TestUtil::ExpectPackedClear( diff --git a/src/google/protobuf/test_util.h b/src/google/protobuf/test_util.h index 5a6ec88f..25165f3a 100644 --- a/src/google/protobuf/test_util.h +++ b/src/google/protobuf/test_util.h @@ -54,6 +54,7 @@ class TestUtil { static void SetAllFieldsAndExtensions(unittest::TestFieldOrderings* message); static void SetPackedFields(unittest::TestPackedTypes* message); static void SetPackedExtensions(unittest::TestPackedExtensions* message); + static void SetUnpackedFields(unittest::TestUnpackedTypes* message); // Use the repeated versions of the set_*() accessors to modify all the // repeated fields of the messsage (which should already have been @@ -72,6 +73,8 @@ class TestUtil { static void ExpectPackedFieldsSet(const unittest::TestPackedTypes& message); static void ExpectPackedExtensionsSet( const unittest::TestPackedExtensions& message); + static void ExpectUnpackedFieldsSet( + const unittest::TestUnpackedTypes& message); // Expect that the message is modified as would be expected from // Modify*Fields(). diff --git a/src/google/protobuf/testing/file.cc b/src/google/protobuf/testing/file.cc index f813e8ee..e224781d 100644 --- a/src/google/protobuf/testing/file.cc +++ b/src/google/protobuf/testing/file.cc @@ -84,10 +84,13 @@ void File::ReadFileToStringOrDie(const string& name, string* output) { void File::WriteStringToFileOrDie(const string& contents, const string& name) { FILE* file = fopen(name.c_str(), "wb"); - GOOGLE_CHECK(file != NULL); + GOOGLE_CHECK(file != NULL) + << "fopen(" << name << ", \"wb\"): " << strerror(errno); GOOGLE_CHECK_EQ(fwrite(contents.data(), 1, contents.size(), file), - contents.size()); - GOOGLE_CHECK(fclose(file) == 0); + contents.size()) + << "fwrite(" << name << "): " << strerror(errno); + GOOGLE_CHECK(fclose(file) == 0) + << "fclose(" << name << "): " << strerror(errno); } bool File::CreateDir(const string& name, int mode) { @@ -97,8 +100,10 @@ bool File::CreateDir(const string& name, int mode) { bool File::RecursivelyCreateDir(const string& path, int mode) { if (CreateDir(path, mode)) return true; + if (Exists(path)) return false; + // Try creating the parent. - string::size_type slashpos = path.find_first_of('/'); + string::size_type slashpos = path.find_last_of('/'); if (slashpos == string::npos) { // No parent given. return false; diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc index cf754024..137cbcee 100644 --- a/src/google/protobuf/text_format.cc +++ b/src/google/protobuf/text_format.cc @@ -54,21 +54,19 @@ namespace protobuf { string Message::DebugString() const { string debug_string; - io::StringOutputStream output_stream(&debug_string); - TextFormat::Print(*this, &output_stream); + TextFormat::PrintToString(*this, &debug_string); return debug_string; } string Message::ShortDebugString() const { string debug_string; - io::StringOutputStream output_stream(&debug_string); TextFormat::Printer printer; printer.SetSingleLineMode(true); - printer.Print(*this, &output_stream); + printer.PrintToString(*this, &debug_string); // Single line mode currently might have an extra space at the end. if (debug_string.size() > 0 && debug_string[debug_string.size() - 1] == ' ') { @@ -78,10 +76,22 @@ string Message::ShortDebugString() const { return debug_string; } +string Message::Utf8DebugString() const { + string debug_string; + + TextFormat::Printer printer; + printer.SetUseUtf8StringEscaping(true); + + printer.PrintToString(*this, &debug_string); + + return debug_string; +} + void Message::PrintDebugString() const { printf("%s", DebugString().c_str()); } + // =========================================================================== // Internal class for parsing an ASCII representation of a Protocol Message. // This class makes use of the Protocol Message compiler's tokenizer found @@ -170,6 +180,23 @@ class TextFormat::Parser::ParserImpl { } } + void ReportWarning(int line, int col, const string& message) { + if (error_collector_ == NULL) { + if (line >= 0) { + GOOGLE_LOG(WARNING) << "Warning parsing text-format " + << root_message_type_->full_name() + << ": " << (line + 1) << ":" + << (col + 1) << ": " << message; + } else { + GOOGLE_LOG(WARNING) << "Warning parsing text-format " + << root_message_type_->full_name() + << ": " << message; + } + } else { + error_collector_->AddWarning(line, col, message); + } + } + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParserImpl); @@ -180,6 +207,13 @@ class TextFormat::Parser::ParserImpl { message); } + // Reports a warning with the given message with information indicating + // the position (as derived from the current token). + void ReportWarning(const string& message) { + ReportWarning(tokenizer_.current().line, tokenizer_.current().column, + message); + } + // Consumes the specified message with the given starting delimeter. // This method checks to see that the end delimeter at the conclusion of // the consumption matches the starting delimeter passed in here. @@ -270,6 +304,11 @@ class TextFormat::Parser::ParserImpl { DO(ConsumeFieldValue(message, reflection, field)); } + if (field->options().deprecated()) { + ReportWarning("text format contains deprecated field \"" + + field_name + "\""); + } + return true; } @@ -583,6 +622,10 @@ class TextFormat::Parser::ParserImpl { parser_->ReportError(line, column, message); } + virtual void AddWarning(int line, int column, const string& message) { + parser_->ReportWarning(line, column, message); + } + private: GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ParserErrorCollector); TextFormat::Parser::ParserImpl* parser_; @@ -644,12 +687,16 @@ class TextFormat::Printer::TextGenerator { // Print text to the output stream. void Print(const string& str) { - Print(str.c_str()); + Print(str.data(), str.size()); } // Print text to the output stream. void Print(const char* text) { - int size = strlen(text); + Print(text, strlen(text)); + } + + // Print text to the output stream. + void Print(const char* text, int size) { int pos = 0; // The number of bytes we've written so far. for (int i = 0; i < size; i++) { @@ -799,7 +846,9 @@ bool TextFormat::Parser::ParseFieldValueFromString( TextFormat::Printer::Printer() : initial_indent_level_(0), - single_line_mode_(false) {} + single_line_mode_(false), + use_short_repeated_primitives_(false), + utf8_string_escaping_(false) {} TextFormat::Printer::~Printer() {} @@ -876,6 +925,14 @@ void TextFormat::Printer::PrintField(const Message& message, const Reflection* reflection, const FieldDescriptor* field, TextGenerator& generator) { + if (use_short_repeated_primitives_ && + field->is_repeated() && + field->cpp_type() != FieldDescriptor::CPPTYPE_STRING && + field->cpp_type() != FieldDescriptor::CPPTYPE_MESSAGE) { + PrintShortRepeatedField(message, reflection, field, generator); + return; + } + int count = 0; if (field->is_repeated()) { @@ -885,26 +942,7 @@ void TextFormat::Printer::PrintField(const Message& message, } for (int j = 0; j < count; ++j) { - if (field->is_extension()) { - generator.Print("["); - // We special-case MessageSet elements for compatibility with proto1. - if (field->containing_type()->options().message_set_wire_format() - && field->type() == FieldDescriptor::TYPE_MESSAGE - && field->is_optional() - && field->extension_scope() == field->message_type()) { - generator.Print(field->message_type()->full_name()); - } else { - generator.Print(field->full_name()); - } - generator.Print("]"); - } else { - if (field->type() == FieldDescriptor::TYPE_GROUP) { - // Groups must be serialized with their original capitalization. - generator.Print(field->message_type()->name()); - } else { - generator.Print(field->name()); - } - } + PrintFieldName(message, reflection, field, generator); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { if (single_line_mode_) { @@ -926,16 +964,64 @@ void TextFormat::Printer::PrintField(const Message& message, PrintFieldValue(message, reflection, field, field_index, generator); if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - if (!single_line_mode_) { + if (single_line_mode_) { + generator.Print("} "); + } else { generator.Outdent(); + generator.Print("}\n"); + } + } else { + if (single_line_mode_) { + generator.Print(" "); + } else { + generator.Print("\n"); } - generator.Print("}"); } + } +} - if (single_line_mode_) { - generator.Print(" "); +void TextFormat::Printer::PrintShortRepeatedField(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator) { + // Print primitive repeated field in short form. + PrintFieldName(message, reflection, field, generator); + + int size = reflection->FieldSize(message, field); + generator.Print(": ["); + for (int i = 0; i < size; i++) { + if (i > 0) generator.Print(", "); + PrintFieldValue(message, reflection, field, i, generator); + } + if (single_line_mode_) { + generator.Print("] "); + } else { + generator.Print("]\n"); + } +} + +void TextFormat::Printer::PrintFieldName(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator) { + if (field->is_extension()) { + generator.Print("["); + // We special-case MessageSet elements for compatibility with proto1. + if (field->containing_type()->options().message_set_wire_format() + && field->type() == FieldDescriptor::TYPE_MESSAGE + && field->is_optional() + && field->extension_scope() == field->message_type()) { + generator.Print(field->message_type()->full_name()); + } else { + generator.Print(field->full_name()); + } + generator.Print("]"); + } else { + if (field->type() == FieldDescriptor::TYPE_GROUP) { + // Groups must be serialized with their original capitalization. + generator.Print(field->message_type()->name()); } else { - generator.Print("\n"); + generator.Print(field->name()); } } } @@ -973,7 +1059,11 @@ void TextFormat::Printer::PrintFieldValue( reflection->GetStringReference(message, field, &scratch); generator.Print("\""); - generator.Print(CEscape(value)); + if (utf8_string_escaping_) { + generator.Print(strings::Utf8SafeCEscape(value)); + } else { + generator.Print(CEscape(value)); + } generator.Print("\""); break; diff --git a/src/google/protobuf/text_format.h b/src/google/protobuf/text_format.h index 39a039d9..e78e1042 100644 --- a/src/google/protobuf/text_format.h +++ b/src/google/protobuf/text_format.h @@ -117,6 +117,24 @@ class LIBPROTOBUF_EXPORT TextFormat { single_line_mode_ = single_line_mode; } + // Set true to print repeated primitives in a format like: + // field_name: [1, 2, 3, 4] + // instead of printing each value on its own line. Short format applies + // only to primitive values -- i.e. everything except strings and + // sub-messages/groups. Note that at present this format is not recognized + // by the parser. + void SetUseShortRepeatedPrimitives(bool use_short_repeated_primitives) { + use_short_repeated_primitives_ = use_short_repeated_primitives; + } + + // Set true to output UTF-8 instead of ASCII. The only difference + // is that bytes >= 0x80 in string fields will not be escaped, + // because they are assumed to be part of UTF-8 multi-byte + // sequences. + void SetUseUtf8StringEscaping(bool as_utf8) { + utf8_string_escaping_ = as_utf8; + } + private: // Forward declaration of an internal class used to print the text // output to the OutputStream (see text_format.cc for implementation). @@ -133,6 +151,19 @@ class LIBPROTOBUF_EXPORT TextFormat { const FieldDescriptor* field, TextGenerator& generator); + // Print a repeated primitive field in short form. + void PrintShortRepeatedField(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator); + + // Print the name of a field -- i.e. everything that comes before the + // ':' for a single name/value pair. + void PrintFieldName(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field, + TextGenerator& generator); + // Outputs a textual representation of the value of the field supplied on // the message supplied or the default value if not set. void PrintFieldValue(const Message& message, @@ -150,6 +181,10 @@ class LIBPROTOBUF_EXPORT TextFormat { int initial_indent_level_; bool single_line_mode_; + + bool use_short_repeated_primitives_; + + bool utf8_string_escaping_; }; // Parses a text-format protocol message from the given input stream to diff --git a/src/google/protobuf/text_format_unittest.cc b/src/google/protobuf/text_format_unittest.cc index 7c31e80f..ddf8ff7f 100644 --- a/src/google/protobuf/text_format_unittest.cc +++ b/src/google/protobuf/text_format_unittest.cc @@ -138,12 +138,53 @@ TEST_F(TextFormatTest, ShortDebugString) { proto_.ShortDebugString()); } +TEST_F(TextFormatTest, ShortPrimitiveRepeateds) { + proto_.set_optional_int32(123); + proto_.add_repeated_int32(456); + proto_.add_repeated_int32(789); + proto_.add_repeated_string("foo"); + proto_.add_repeated_string("bar"); + proto_.add_repeated_nested_message()->set_bb(2); + proto_.add_repeated_nested_message()->set_bb(3); + proto_.add_repeated_nested_enum(unittest::TestAllTypes::FOO); + proto_.add_repeated_nested_enum(unittest::TestAllTypes::BAR); + + TextFormat::Printer printer; + printer.SetUseShortRepeatedPrimitives(true); + string text; + printer.PrintToString(proto_, &text); + + EXPECT_EQ("optional_int32: 123\n" + "repeated_int32: [456, 789]\n" + "repeated_string: \"foo\"\n" + "repeated_string: \"bar\"\n" + "repeated_nested_message {\n bb: 2\n}\n" + "repeated_nested_message {\n bb: 3\n}\n" + "repeated_nested_enum: [FOO, BAR]\n", + text); + + // Try in single-line mode. + printer.SetSingleLineMode(true); + printer.PrintToString(proto_, &text); + + EXPECT_EQ("optional_int32: 123 " + "repeated_int32: [456, 789] " + "repeated_string: \"foo\" " + "repeated_string: \"bar\" " + "repeated_nested_message { bb: 2 } " + "repeated_nested_message { bb: 3 } " + "repeated_nested_enum: [FOO, BAR] ", + text); +} + + TEST_F(TextFormatTest, StringEscape) { // Set the string value to test. proto_.set_optional_string(kEscapeTestString); // Get the DebugString from the proto. string debug_string = proto_.DebugString(); + string utf8_debug_string = proto_.Utf8DebugString(); // Hardcode a correct value to test against. string correct_string = "optional_string: " @@ -152,12 +193,36 @@ TEST_F(TextFormatTest, StringEscape) { // Compare. EXPECT_EQ(correct_string, debug_string); + // UTF-8 string is the same as non-UTF-8 because + // the protocol buffer contains no UTF-8 text. + EXPECT_EQ(correct_string, utf8_debug_string); string expected_short_debug_string = "optional_string: " + kEscapeTestStringEscaped; EXPECT_EQ(expected_short_debug_string, proto_.ShortDebugString()); } +TEST_F(TextFormatTest, Utf8DebugString) { + // Set the string value to test. + proto_.set_optional_string("\350\260\267\346\255\214"); + + // Get the DebugString from the proto. + string debug_string = proto_.DebugString(); + string utf8_debug_string = proto_.Utf8DebugString(); + + // Hardcode a correct value to test against. + string correct_utf8_string = "optional_string: " + "\"\350\260\267\346\255\214\"" + "\n"; + string correct_string = "optional_string: " + "\"\\350\\260\\267\\346\\255\\214\"" + "\n"; + + // Compare. + EXPECT_EQ(correct_utf8_string, utf8_debug_string); + EXPECT_EQ(correct_string, debug_string); +} + TEST_F(TextFormatTest, PrintUnknownFields) { // Test printing of unknown fields in a message. @@ -603,10 +668,15 @@ class TextFormatParserTest : public testing::Test { void ExpectFailure(const string& input, const string& message, int line, int col, Message* proto) { + ExpectMessage(input, message, line, col, proto, false); + } + + void ExpectMessage(const string& input, const string& message, int line, + int col, Message* proto, bool expected_result) { TextFormat::Parser parser; MockErrorCollector error_collector; parser.RecordErrorsTo(&error_collector); - EXPECT_FALSE(parser.ParseFromString(input, proto)); + EXPECT_EQ(parser.ParseFromString(input, proto), expected_result); EXPECT_EQ(SimpleItoa(line) + ":" + SimpleItoa(col) + ": " + message + "\n", error_collector.text_); } @@ -625,6 +695,10 @@ class TextFormatParserTest : public testing::Test { strings::SubstituteAndAppend(&text_, "$0:$1: $2\n", line + 1, column + 1, message); } + + void AddWarning(int line, int column, const string& message) { + AddError(line, column, "WARNING:" + message); + } }; }; @@ -945,6 +1019,12 @@ TEST_F(TextFormatParserTest, FailsOnTokenizationError) { errors[0]); } +TEST_F(TextFormatParserTest, ParseDeprecatedField) { + unittest::TestDeprecatedFields message; + ExpectMessage("deprecated_int32: 42", + "WARNING:text format contains deprecated field " + "\"deprecated_int32\"", 1, 21, &message, true); +} class TextFormatMessageSetTest : public testing::Test { protected: @@ -991,5 +1071,4 @@ TEST_F(TextFormatMessageSetTest, Deserialize) { } // namespace text_format_unittest } // namespace protobuf - } // namespace google diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto index 03811de8..d51fa1e7 100644 --- a/src/google/protobuf/unittest.proto +++ b/src/google/protobuf/unittest.proto @@ -155,6 +155,10 @@ message TestAllTypes { optional string default_cord = 85 [ctype=CORD,default="123"]; } +message TestDeprecatedFields { + optional int32 deprecated_int32 = 1 [deprecated=true]; +} + // Define these after TestAllTypes to make sure the compiler can handle // that. message ForeignMessage { @@ -348,6 +352,12 @@ message TestEmptyMessageWithExtensions { extensions 1 to max; } +message TestMultipleExtensionRanges { + extensions 42; + extensions 4143 to 4243; + extensions 65536 to max; +} + // Test that really large tag numbers don't break anything. message TestReallyLargeTagNumber { // The largest possible tag number is 2^28 - 1, since the wire format uses @@ -372,13 +382,14 @@ message TestMutualRecursionB { } // Test that groups have disjoint field numbers from their siblings and -// parents. This is NOT possible in proto1; only proto2. When outputting -// proto1, the dup fields should be dropped. -message TestDupFieldNumber { - optional int32 a = 1; - optional group Foo = 2 { optional int32 a = 1; } - optional group Bar = 3 { optional int32 a = 1; } -} +// parents. This is NOT possible in proto1; only proto2. When attempting +// to compile with proto1, this will emit an error; so we only include it +// in protobuf_unittest_proto. +message TestDupFieldNumber { // NO_PROTO1 + optional int32 a = 1; // NO_PROTO1 + optional group Foo = 2 { optional int32 a = 1; } // NO_PROTO1 + optional group Bar = 3 { optional int32 a = 1; } // NO_PROTO1 +} // NO_PROTO1 // Needed for a Python test. @@ -468,6 +479,14 @@ message TestExtremeDefaultValues { // Using exponents optional float large_float = 12 [default = 2E8]; optional float small_negative_float = 13 [default = -8e-28]; + + // Text for nonfinite floating-point values. + optional double inf_double = 14 [default = inf]; + optional double neg_inf_double = 15 [default = -inf]; + optional double nan_double = 16 [default = nan]; + optional float inf_float = 17 [default = inf]; + optional float neg_inf_float = 18 [default = -inf]; + optional float nan_float = 19 [default = nan]; } // Test String and Bytes: string is for valid UTF-8 strings @@ -498,6 +517,25 @@ message TestPackedTypes { repeated ForeignEnum packed_enum = 103 [packed = true]; } +// A message with the same fields as TestPackedTypes, but without packing. Used +// to test packed <-> unpacked wire compatibility. +message TestUnpackedTypes { + repeated int32 unpacked_int32 = 90 [packed = false]; + repeated int64 unpacked_int64 = 91 [packed = false]; + repeated uint32 unpacked_uint32 = 92 [packed = false]; + repeated uint64 unpacked_uint64 = 93 [packed = false]; + repeated sint32 unpacked_sint32 = 94 [packed = false]; + repeated sint64 unpacked_sint64 = 95 [packed = false]; + repeated fixed32 unpacked_fixed32 = 96 [packed = false]; + repeated fixed64 unpacked_fixed64 = 97 [packed = false]; + repeated sfixed32 unpacked_sfixed32 = 98 [packed = false]; + repeated sfixed64 unpacked_sfixed64 = 99 [packed = false]; + repeated float unpacked_float = 100 [packed = false]; + repeated double unpacked_double = 101 [packed = false]; + repeated bool unpacked_bool = 102 [packed = false]; + repeated ForeignEnum unpacked_enum = 103 [packed = false]; +} + message TestPackedExtensions { extensions 1 to max; } @@ -519,6 +557,47 @@ extend TestPackedExtensions { repeated ForeignEnum packed_enum_extension = 103 [packed = true]; } +// Used by ExtensionSetTest/DynamicExtensions. The test actually builds +// a set of extensions to TestAllExtensions dynamically, based on the fields +// of this message type. +message TestDynamicExtensions { + enum DynamicEnumType { + DYNAMIC_FOO = 2200; + DYNAMIC_BAR = 2201; + DYNAMIC_BAZ = 2202; + } + message DynamicMessageType { + optional int32 dynamic_field = 2100; + } + + optional fixed32 scalar_extension = 2000; + optional ForeignEnum enum_extension = 2001; + optional DynamicEnumType dynamic_enum_extension = 2002; + + optional ForeignMessage message_extension = 2003; + optional DynamicMessageType dynamic_message_extension = 2004; + + repeated string repeated_extension = 2005; + repeated sint32 packed_extension = 2006 [packed = true]; +} + +message TestRepeatedScalarDifferentTagSizes { + // Parsing repeated fixed size values used to fail. This message needs to be + // used in order to get a tag of the right size; all of the repeated fields + // in TestAllTypes didn't trigger the check. + repeated fixed32 repeated_fixed32 = 12; + // Check for a varint type, just for good measure. + repeated int32 repeated_int32 = 13; + + // These have two-byte tags. + repeated fixed64 repeated_fixed64 = 2046; + repeated int64 repeated_int64 = 2047; + + // Three byte tags. + repeated float repeated_float = 262142; + repeated uint64 repeated_uint64 = 262143; +} + // Test that RPC services work. message FooRequest {} message FooResponse {} diff --git a/src/google/protobuf/unittest_enormous_descriptor.proto b/src/google/protobuf/unittest_enormous_descriptor.proto index 6ad2dab3..bc0b7c16 100644 --- a/src/google/protobuf/unittest_enormous_descriptor.proto +++ b/src/google/protobuf/unittest_enormous_descriptor.proto @@ -35,6 +35,7 @@ // A proto file that has an extremely large descriptor. Used to test that // descriptors over 64k don't break the string literal length limit in Java. + package google.protobuf; option java_package = "com.google.protobuf"; diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc index 318ffafe..e1f8b838 100644 --- a/src/google/protobuf/unknown_field_set.cc +++ b/src/google/protobuf/unknown_field_set.cc @@ -32,6 +32,7 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include #include #include #include @@ -50,13 +51,12 @@ UnknownFieldSet::~UnknownFieldSet() { delete fields_; } -void UnknownFieldSet::Clear() { - if (fields_ != NULL) { - for (int i = 0; i < fields_->size(); i++) { - (*fields_)[i].Delete(); - } - fields_->clear(); +void UnknownFieldSet::ClearFallback() { + GOOGLE_DCHECK(fields_ != NULL); + for (int i = 0; i < fields_->size(); i++) { + (*fields_)[i].Delete(); } + fields_->clear(); } void UnknownFieldSet::MergeFrom(const UnknownFieldSet& other) { diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h index d6ca70fc..84c2e2b6 100644 --- a/src/google/protobuf/unknown_field_set.h +++ b/src/google/protobuf/unknown_field_set.h @@ -66,7 +66,7 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet { ~UnknownFieldSet(); // Remove all fields. - void Clear(); + inline void Clear(); // Is this set empty? inline bool empty() const; @@ -119,6 +119,8 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet { } private: + void ClearFallback(); + vector* fields_; GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UnknownFieldSet); @@ -180,6 +182,12 @@ class LIBPROTOBUF_EXPORT UnknownField { // =================================================================== // inline implementations +inline void UnknownFieldSet::Clear() { + if (fields_ != NULL) { + ClearFallback(); + } +} + inline bool UnknownFieldSet::empty() const { return fields_ == NULL || fields_->empty(); } diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc index 5aa67727..831a5794 100644 --- a/src/google/protobuf/wire_format.cc +++ b/src/google/protobuf/wire_format.cc @@ -391,7 +391,12 @@ bool WireFormat::ParseAndMergePartial(io::CodedInputStream* input, // If that failed, check if the field is an extension. if (field == NULL && descriptor->IsExtensionNumber(field_number)) { - field = message_reflection->FindKnownExtensionByNumber(field_number); + if (input->GetExtensionPool() == NULL) { + field = message_reflection->FindKnownExtensionByNumber(field_number); + } else { + field = input->GetExtensionPool() + ->FindExtensionByNumber(descriptor, field_number); + } } // If that failed, but we're a MessageSet, and this is the tag for a @@ -419,52 +424,67 @@ bool WireFormat::ParseAndMergeField( io::CodedInputStream* input) { const Reflection* message_reflection = message->GetReflection(); - if (field == NULL || - WireFormatLite::GetTagWireType(tag) != WireTypeForField(field)) { - // We don't recognize this field. Either the field number is unknown - // or the wire type doesn't match. Put it in our unknown field set. - return SkipField(input, tag, - message_reflection->MutableUnknownFields(message)); + enum { UNKNOWN, NORMAL_FORMAT, PACKED_FORMAT } value_format; + + if (field == NULL) { + value_format = UNKNOWN; + } else if (WireFormatLite::GetTagWireType(tag) == + WireTypeForFieldType(field->type())) { + value_format = NORMAL_FORMAT; + } else if (field->is_packable() && + WireFormatLite::GetTagWireType(tag) == + WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { + value_format = PACKED_FORMAT; + } else { + // We don't recognize this field. Either the field number is unknown + // or the wire type doesn't match. Put it in our unknown field set. + value_format = UNKNOWN; } - if (field->options().packed()) { + if (value_format == UNKNOWN) { + return SkipField(input, tag, + message_reflection->MutableUnknownFields(message)); + } else if (value_format == PACKED_FORMAT) { uint32 length; if (!input->ReadVarint32(&length)) return false; io::CodedInputStream::Limit limit = input->PushLimit(length); switch (field->type()) { -#define HANDLE_PACKED_TYPE(TYPE, TYPE_METHOD, CPPTYPE, CPPTYPE_METHOD) \ +#define HANDLE_PACKED_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD) \ case FieldDescriptor::TYPE_##TYPE: { \ while (input->BytesUntilLimit() > 0) { \ CPPTYPE value; \ - if (!WireFormatLite::Read##TYPE_METHOD(input, &value)) return false; \ + if (!WireFormatLite::ReadPrimitive< \ + CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)) \ + return false; \ message_reflection->Add##CPPTYPE_METHOD(message, field, value); \ } \ break; \ } - HANDLE_PACKED_TYPE( INT32, Int32, int32, Int32) - HANDLE_PACKED_TYPE( INT64, Int64, int64, Int64) - HANDLE_PACKED_TYPE(SINT32, SInt32, int32, Int32) - HANDLE_PACKED_TYPE(SINT64, SInt64, int64, Int64) - HANDLE_PACKED_TYPE(UINT32, UInt32, uint32, UInt32) - HANDLE_PACKED_TYPE(UINT64, UInt64, uint64, UInt64) + HANDLE_PACKED_TYPE( INT32, int32, Int32) + HANDLE_PACKED_TYPE( INT64, int64, Int64) + HANDLE_PACKED_TYPE(SINT32, int32, Int32) + HANDLE_PACKED_TYPE(SINT64, int64, Int64) + HANDLE_PACKED_TYPE(UINT32, uint32, UInt32) + HANDLE_PACKED_TYPE(UINT64, uint64, UInt64) - HANDLE_PACKED_TYPE( FIXED32, Fixed32, uint32, UInt32) - HANDLE_PACKED_TYPE( FIXED64, Fixed64, uint64, UInt64) - HANDLE_PACKED_TYPE(SFIXED32, SFixed32, int32, Int32) - HANDLE_PACKED_TYPE(SFIXED64, SFixed64, int64, Int64) + HANDLE_PACKED_TYPE( FIXED32, uint32, UInt32) + HANDLE_PACKED_TYPE( FIXED64, uint64, UInt64) + HANDLE_PACKED_TYPE(SFIXED32, int32, Int32) + HANDLE_PACKED_TYPE(SFIXED64, int64, Int64) - HANDLE_PACKED_TYPE(FLOAT , Float , float , Float ) - HANDLE_PACKED_TYPE(DOUBLE, Double, double, Double) + HANDLE_PACKED_TYPE(FLOAT , float , Float ) + HANDLE_PACKED_TYPE(DOUBLE, double, Double) - HANDLE_PACKED_TYPE(BOOL, Bool, bool, Bool) + HANDLE_PACKED_TYPE(BOOL, bool, Bool) #undef HANDLE_PACKED_TYPE case FieldDescriptor::TYPE_ENUM: { while (input->BytesUntilLimit() > 0) { int value; - if (!WireFormatLite::ReadEnum(input, &value)) return false; + if (!WireFormatLite::ReadPrimitive( + input, &value)) return false; const EnumValueDescriptor* enum_value = field->enum_type()->FindValueByNumber(value); if (enum_value != NULL) { @@ -487,11 +507,14 @@ bool WireFormat::ParseAndMergeField( input->PopLimit(limit); } else { + // Non-packed value (value_format == NORMAL_FORMAT) switch (field->type()) { -#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE, CPPTYPE_METHOD) \ +#define HANDLE_TYPE(TYPE, CPPTYPE, CPPTYPE_METHOD) \ case FieldDescriptor::TYPE_##TYPE: { \ CPPTYPE value; \ - if (!WireFormatLite::Read##TYPE_METHOD(input, &value)) return false; \ + if (!WireFormatLite::ReadPrimitive< \ + CPPTYPE, WireFormatLite::TYPE_##TYPE>(input, &value)) \ + return false; \ if (field->is_repeated()) { \ message_reflection->Add##CPPTYPE_METHOD(message, field, value); \ } else { \ @@ -500,31 +523,28 @@ bool WireFormat::ParseAndMergeField( break; \ } - HANDLE_TYPE( INT32, Int32, int32, Int32) - HANDLE_TYPE( INT64, Int64, int64, Int64) - HANDLE_TYPE(SINT32, SInt32, int32, Int32) - HANDLE_TYPE(SINT64, SInt64, int64, Int64) - HANDLE_TYPE(UINT32, UInt32, uint32, UInt32) - HANDLE_TYPE(UINT64, UInt64, uint64, UInt64) - - HANDLE_TYPE( FIXED32, Fixed32, uint32, UInt32) - HANDLE_TYPE( FIXED64, Fixed64, uint64, UInt64) - HANDLE_TYPE(SFIXED32, SFixed32, int32, Int32) - HANDLE_TYPE(SFIXED64, SFixed64, int64, Int64) - - HANDLE_TYPE(FLOAT , Float , float , Float ) - HANDLE_TYPE(DOUBLE, Double, double, Double) + HANDLE_TYPE( INT32, int32, Int32) + HANDLE_TYPE( INT64, int64, Int64) + HANDLE_TYPE(SINT32, int32, Int32) + HANDLE_TYPE(SINT64, int64, Int64) + HANDLE_TYPE(UINT32, uint32, UInt32) + HANDLE_TYPE(UINT64, uint64, UInt64) - HANDLE_TYPE(BOOL, Bool, bool, Bool) + HANDLE_TYPE( FIXED32, uint32, UInt32) + HANDLE_TYPE( FIXED64, uint64, UInt64) + HANDLE_TYPE(SFIXED32, int32, Int32) + HANDLE_TYPE(SFIXED64, int64, Int64) - HANDLE_TYPE(STRING, String, string, String) - HANDLE_TYPE(BYTES, Bytes, string, String) + HANDLE_TYPE(FLOAT , float , Float ) + HANDLE_TYPE(DOUBLE, double, Double) + HANDLE_TYPE(BOOL, bool, Bool) #undef HANDLE_TYPE case FieldDescriptor::TYPE_ENUM: { int value; - if (!WireFormatLite::ReadEnum(input, &value)) return false; + if (!WireFormatLite::ReadPrimitive( + input, &value)) return false; const EnumValueDescriptor* enum_value = field->enum_type()->FindValueByNumber(value); if (enum_value != NULL) { @@ -544,13 +564,38 @@ bool WireFormat::ParseAndMergeField( break; } + // Handle strings separately so that we can optimize the ctype=CORD case. + case FieldDescriptor::TYPE_STRING: { + string value; + if (!WireFormatLite::ReadString(input, &value)) return false; + VerifyUTF8String(value.data(), value.length(), PARSE); + if (field->is_repeated()) { + message_reflection->AddString(message, field, value); + } else { + message_reflection->SetString(message, field, value); + } + break; + } + + case FieldDescriptor::TYPE_BYTES: { + string value; + if (!WireFormatLite::ReadBytes(input, &value)) return false; + if (field->is_repeated()) { + message_reflection->AddString(message, field, value); + } else { + message_reflection->SetString(message, field, value); + } + break; + } case FieldDescriptor::TYPE_GROUP: { Message* sub_message; if (field->is_repeated()) { - sub_message = message_reflection->AddMessage(message, field); + sub_message = message_reflection->AddMessage( + message, field, input->GetExtensionFactory()); } else { - sub_message = message_reflection->MutableMessage(message, field); + sub_message = message_reflection->MutableMessage( + message, field, input->GetExtensionFactory()); } if (!WireFormatLite::ReadGroup(WireFormatLite::GetTagFieldNumber(tag), @@ -562,9 +607,11 @@ bool WireFormat::ParseAndMergeField( case FieldDescriptor::TYPE_MESSAGE: { Message* sub_message; if (field->is_repeated()) { - sub_message = message_reflection->AddMessage(message, field); + sub_message = message_reflection->AddMessage( + message, field, input->GetExtensionFactory()); } else { - sub_message = message_reflection->MutableMessage(message, field); + sub_message = message_reflection->MutableMessage( + message, field, input->GetExtensionFactory()); } if (!WireFormatLite::ReadMessage(input, sub_message)) return false; @@ -782,23 +829,23 @@ void WireFormat::SerializeFieldWithCachedSizes( // Handle strings separately so that we can get string references // instead of copying. case FieldDescriptor::TYPE_STRING: { - string scratch; - const string& value = field->is_repeated() ? - message_reflection->GetRepeatedStringReference( - message, field, j, &scratch) : - message_reflection->GetStringReference(message, field, &scratch); - VerifyUTF8String(value.data(), value.length(), SERIALIZE); - WireFormatLite::WriteString(field->number(), value, output); + string scratch; + const string& value = field->is_repeated() ? + message_reflection->GetRepeatedStringReference( + message, field, j, &scratch) : + message_reflection->GetStringReference(message, field, &scratch); + VerifyUTF8String(value.data(), value.length(), SERIALIZE); + WireFormatLite::WriteString(field->number(), value, output); break; } case FieldDescriptor::TYPE_BYTES: { - string scratch; - const string& value = field->is_repeated() ? - message_reflection->GetRepeatedStringReference( - message, field, j, &scratch) : - message_reflection->GetStringReference(message, field, &scratch); - WireFormatLite::WriteBytes(field->number(), value, output); + string scratch; + const string& value = field->is_repeated() ? + message_reflection->GetRepeatedStringReference( + message, field, j, &scratch) : + message_reflection->GetStringReference(message, field, &scratch); + WireFormatLite::WriteBytes(field->number(), value, output); break; } } @@ -961,14 +1008,14 @@ int WireFormat::FieldDataOnlyByteSize( // instead of copying. case FieldDescriptor::TYPE_STRING: case FieldDescriptor::TYPE_BYTES: { - for (int j = 0; j < count; j++) { - string scratch; - const string& value = field->is_repeated() ? - message_reflection->GetRepeatedStringReference( - message, field, j, &scratch) : - message_reflection->GetStringReference(message, field, &scratch); - data_size += WireFormatLite::StringSize(value); - } + for (int j = 0; j < count; j++) { + string scratch; + const string& value = field->is_repeated() ? + message_reflection->GetRepeatedStringReference( + message, field, j, &scratch) : + message_reflection->GetStringReference(message, field, &scratch); + data_size += WireFormatLite::StringSize(value); + } break; } } diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc index 5d09803a..d347d116 100644 --- a/src/google/protobuf/wire_format_lite.cc +++ b/src/google/protobuf/wire_format_lite.cc @@ -32,14 +32,13 @@ // Based on original Protocol Buffers design by // Sanjay Ghemawat, Jeff Dean, and others. +#include + #include #include #include - -#include - #include -#include +#include #include #include @@ -187,6 +186,174 @@ void FieldSkipper::SkipUnknownEnum( // Nothing. } +bool WireFormatLite::ReadPackedEnumNoInline(io::CodedInputStream* input, + bool (*is_valid)(int), + RepeatedField* values) { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + io::CodedInputStream::Limit limit = input->PushLimit(length); + while (input->BytesUntilLimit() > 0) { + int value; + if (!google::protobuf::internal::WireFormatLite::ReadPrimitive< + int, WireFormatLite::TYPE_ENUM>(input, &value)) { + return false; + } + if (is_valid(value)) { + values->Add(value); + } + } + input->PopLimit(limit); + return true; +} + +void WireFormatLite::WriteInt32(int field_number, int32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteInt32NoTag(value, output); +} +void WireFormatLite::WriteInt64(int field_number, int64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteInt64NoTag(value, output); +} +void WireFormatLite::WriteUInt32(int field_number, uint32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteUInt32NoTag(value, output); +} +void WireFormatLite::WriteUInt64(int field_number, uint64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteUInt64NoTag(value, output); +} +void WireFormatLite::WriteSInt32(int field_number, int32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteSInt32NoTag(value, output); +} +void WireFormatLite::WriteSInt64(int field_number, int64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteSInt64NoTag(value, output); +} +void WireFormatLite::WriteFixed32(int field_number, uint32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED32, output); + WriteFixed32NoTag(value, output); +} +void WireFormatLite::WriteFixed64(int field_number, uint64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED64, output); + WriteFixed64NoTag(value, output); +} +void WireFormatLite::WriteSFixed32(int field_number, int32 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED32, output); + WriteSFixed32NoTag(value, output); +} +void WireFormatLite::WriteSFixed64(int field_number, int64 value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED64, output); + WriteSFixed64NoTag(value, output); +} +void WireFormatLite::WriteFloat(int field_number, float value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED32, output); + WriteFloatNoTag(value, output); +} +void WireFormatLite::WriteDouble(int field_number, double value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_FIXED64, output); + WriteDoubleNoTag(value, output); +} +void WireFormatLite::WriteBool(int field_number, bool value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteBoolNoTag(value, output); +} +void WireFormatLite::WriteEnum(int field_number, int value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_VARINT, output); + WriteEnumNoTag(value, output); +} + +void WireFormatLite::WriteString(int field_number, const string& value, + io::CodedOutputStream* output) { + // String is for UTF-8 text only + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32(value.size()); + output->WriteString(value); +} +void WireFormatLite::WriteBytes(int field_number, const string& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + output->WriteVarint32(value.size()); + output->WriteString(value); +} + + +void WireFormatLite::WriteGroup(int field_number, + const MessageLite& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_START_GROUP, output); + value.SerializeWithCachedSizes(output); + WriteTag(field_number, WIRETYPE_END_GROUP, output); +} + +void WireFormatLite::WriteMessage(int field_number, + const MessageLite& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + const int size = value.GetCachedSize(); + output->WriteVarint32(size); + value.SerializeWithCachedSizes(output); +} + +void WireFormatLite::WriteGroupMaybeToArray(int field_number, + const MessageLite& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_START_GROUP, output); + const int size = value.GetCachedSize(); + uint8* target = output->GetDirectBufferForNBytesAndAdvance(size); + if (target != NULL) { + uint8* end = value.SerializeWithCachedSizesToArray(target); + GOOGLE_DCHECK_EQ(end - target, size); + } else { + value.SerializeWithCachedSizes(output); + } + WriteTag(field_number, WIRETYPE_END_GROUP, output); +} + +void WireFormatLite::WriteMessageMaybeToArray(int field_number, + const MessageLite& value, + io::CodedOutputStream* output) { + WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); + const int size = value.GetCachedSize(); + output->WriteVarint32(size); + uint8* target = output->GetDirectBufferForNBytesAndAdvance(size); + if (target != NULL) { + uint8* end = value.SerializeWithCachedSizesToArray(target); + GOOGLE_DCHECK_EQ(end - target, size); + } else { + value.SerializeWithCachedSizes(output); + } +} + +bool WireFormatLite::ReadString(io::CodedInputStream* input, + string* value) { + // String is for UTF-8 text only + uint32 length; + if (!input->ReadVarint32(&length)) return false; + if (!input->InternalReadStringInline(value, length)) return false; + return true; +} +bool WireFormatLite::ReadBytes(io::CodedInputStream* input, + string* value) { + uint32 length; + if (!input->ReadVarint32(&length)) return false; + return input->InternalReadStringInline(value, length); +} + } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/wire_format_lite.h b/src/google/protobuf/wire_format_lite.h index 9b7a4010..e3d5b2d8 100644 --- a/src/google/protobuf/wire_format_lite.h +++ b/src/google/protobuf/wire_format_lite.h @@ -46,15 +46,18 @@ namespace google { namespace protobuf { + template class RepeatedField; // repeated_field.h namespace io { - class CodedInputStream; // coded_stream.h - class CodedOutputStream; // coded_stream.h + class CodedInputStream; // coded_stream.h + class CodedOutputStream; // coded_stream.h } } namespace protobuf { namespace internal { +class StringPieceField; + // This class is for internal use by the protocol buffer library and by // protocol-complier-generated message classes. It must not be called // directly by clients. @@ -183,14 +186,21 @@ class LIBPROTOBUF_EXPORT WireFormatLite { // required string message = 3; // } // } + static const int kMessageSetItemNumber = 1; + static const int kMessageSetTypeIdNumber = 2; + static const int kMessageSetMessageNumber = 3; static const int kMessageSetItemStartTag = - GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(1, WireFormatLite::WIRETYPE_START_GROUP); + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetItemNumber, + WireFormatLite::WIRETYPE_START_GROUP); static const int kMessageSetItemEndTag = - GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(1, WireFormatLite::WIRETYPE_END_GROUP); + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetItemNumber, + WireFormatLite::WIRETYPE_END_GROUP); static const int kMessageSetTypeIdTag = - GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(2, WireFormatLite::WIRETYPE_VARINT); + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetTypeIdNumber, + WireFormatLite::WIRETYPE_VARINT); static const int kMessageSetMessageTag = - GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(3, WireFormatLite::WIRETYPE_LENGTH_DELIMITED); + GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kMessageSetMessageNumber, + WireFormatLite::WIRETYPE_LENGTH_DELIMITED); // Byte size of all tags of a MessageSet::Item combined. static const int kMessageSetItemTagsSize; @@ -227,23 +237,59 @@ class LIBPROTOBUF_EXPORT WireFormatLite { // Read fields, not including tags. The assumption is that you already // read the tag to determine what field to read. - static inline bool ReadInt32 (input, int32* value); - static inline bool ReadInt64 (input, int64* value); - static inline bool ReadUInt32 (input, uint32* value); - static inline bool ReadUInt64 (input, uint64* value); - static inline bool ReadSInt32 (input, int32* value); - static inline bool ReadSInt64 (input, int64* value); - static inline bool ReadFixed32 (input, uint32* value); - static inline bool ReadFixed64 (input, uint64* value); - static inline bool ReadSFixed32(input, int32* value); - static inline bool ReadSFixed64(input, int64* value); - static inline bool ReadFloat (input, float* value); - static inline bool ReadDouble (input, double* value); - static inline bool ReadBool (input, bool* value); - static inline bool ReadEnum (input, int* value); - - static inline bool ReadString(input, string* value); - static inline bool ReadBytes (input, string* value); + + // For primitive fields, we just use a templatized routine parameterized by + // the represented type and the FieldType. These are specialized with the + // appropriate definition for each declared type. + template + static inline bool ReadPrimitive(input, CType* value) INL; + + // Reads repeated primitive values, with optimizations for repeats. + // tag_size and tag should both be compile-time constants provided by the + // protocol compiler. + template + static inline bool ReadRepeatedPrimitive(int tag_size, + uint32 tag, + input, + RepeatedField* value) INL; + + // Identical to ReadRepeatedPrimitive, except will not inline the + // implementation. + template + static bool ReadRepeatedPrimitiveNoInline(int tag_size, + uint32 tag, + input, + RepeatedField* value); + + // Reads a primitive value directly from the provided buffer. It returns a + // pointer past the segment of data that was read. + // + // This is only implemented for the types with fixed wire size, e.g. + // float, double, and the (s)fixed* types. + template + static inline const uint8* ReadPrimitiveFromArray(const uint8* buffer, + CType* value) INL; + + // Reads a primitive packed field. + // + // This is only implemented for packable types. + template + static inline bool ReadPackedPrimitive(input, + RepeatedField* value) INL; + + // Identical to ReadPackedPrimitive, except will not inline the + // implementation. + template + static bool ReadPackedPrimitiveNoInline(input, RepeatedField* value); + + // Read a packed enum field. Values for which is_valid() returns false are + // dropped. + static bool ReadPackedEnumNoInline(input, + bool (*is_valid)(int), + RepeatedField* value); + + static bool ReadString(input, string* value); + static bool ReadBytes (input, string* value); static inline bool ReadGroup (field_number, input, MessageLite* value); static inline bool ReadMessage(input, MessageLite* value); @@ -279,38 +325,44 @@ class LIBPROTOBUF_EXPORT WireFormatLite { static inline void WriteEnumNoTag (int value, output) INL; // Write fields, including tags. - static inline void WriteInt32 (field_number, int32 value, output) INL; - static inline void WriteInt64 (field_number, int64 value, output) INL; - static inline void WriteUInt32 (field_number, uint32 value, output) INL; - static inline void WriteUInt64 (field_number, uint64 value, output) INL; - static inline void WriteSInt32 (field_number, int32 value, output) INL; - static inline void WriteSInt64 (field_number, int64 value, output) INL; - static inline void WriteFixed32 (field_number, uint32 value, output) INL; - static inline void WriteFixed64 (field_number, uint64 value, output) INL; - static inline void WriteSFixed32(field_number, int32 value, output) INL; - static inline void WriteSFixed64(field_number, int64 value, output) INL; - static inline void WriteFloat (field_number, float value, output) INL; - static inline void WriteDouble (field_number, double value, output) INL; - static inline void WriteBool (field_number, bool value, output) INL; - static inline void WriteEnum (field_number, int value, output) INL; - - static inline void WriteString(field_number, const string& value, output) INL; - static inline void WriteBytes (field_number, const string& value, output) INL; - - static inline void WriteGroup( - field_number, const MessageLite& value, output) INL; - static inline void WriteMessage( - field_number, const MessageLite& value, output) INL; + static void WriteInt32 (field_number, int32 value, output); + static void WriteInt64 (field_number, int64 value, output); + static void WriteUInt32 (field_number, uint32 value, output); + static void WriteUInt64 (field_number, uint64 value, output); + static void WriteSInt32 (field_number, int32 value, output); + static void WriteSInt64 (field_number, int64 value, output); + static void WriteFixed32 (field_number, uint32 value, output); + static void WriteFixed64 (field_number, uint64 value, output); + static void WriteSFixed32(field_number, int32 value, output); + static void WriteSFixed64(field_number, int64 value, output); + static void WriteFloat (field_number, float value, output); + static void WriteDouble (field_number, double value, output); + static void WriteBool (field_number, bool value, output); + static void WriteEnum (field_number, int value, output); + + static void WriteString(field_number, const string& value, output); + static void WriteBytes (field_number, const string& value, output); + + static void WriteGroup( + field_number, const MessageLite& value, output); + static void WriteMessage( + field_number, const MessageLite& value, output); + // Like above, but these will check if the output stream has enough + // space to write directly to a flat array. + static void WriteGroupMaybeToArray( + field_number, const MessageLite& value, output); + static void WriteMessageMaybeToArray( + field_number, const MessageLite& value, output); // Like above, but de-virtualize the call to SerializeWithCachedSizes(). The // pointer must point at an instance of MessageType, *not* a subclass (or // the subclass must not override SerializeWithCachedSizes()). template static inline void WriteGroupNoVirtual( - field_number, const MessageType& value, output) INL; + field_number, const MessageType& value, output); template static inline void WriteMessageNoVirtual( - field_number, const MessageType& value, output) INL; + field_number, const MessageType& value, output); #undef output #define output uint8* target @@ -426,6 +478,16 @@ class LIBPROTOBUF_EXPORT WireFormatLite { static inline int MessageSizeNoVirtual(const MessageType& value); private: + // A helper method for the repeated primitive reader. This method has + // optimizations for primitive types that have fixed size on the wire, and + // can be read using potentially faster paths. + template + static inline bool ReadRepeatedFixedSizePrimitive( + int tag_size, + uint32 tag, + google::protobuf::io::CodedInputStream* input, + RepeatedField* value) GOOGLE_ATTRIBUTE_ALWAYS_INLINE; + static const CppType kFieldTypeToCppTypeMap[]; static const WireFormatLite::WireType kWireTypeForFieldType[]; diff --git a/src/google/protobuf/wire_format_lite_inl.h b/src/google/protobuf/wire_format_lite_inl.h index eb9155e9..d7b2c302 100644 --- a/src/google/protobuf/wire_format_lite_inl.h +++ b/src/google/protobuf/wire_format_lite_inl.h @@ -39,7 +39,9 @@ #include #include #include +#include #include +#include #include @@ -47,106 +49,295 @@ namespace google { namespace protobuf { namespace internal { -inline bool WireFormatLite::ReadInt32(io::CodedInputStream* input, - int32* value) { +// Implementation details of ReadPrimitive. + +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int32* value) { uint32 temp; if (!input->ReadVarint32(&temp)) return false; *value = static_cast(temp); return true; } -inline bool WireFormatLite::ReadInt64(io::CodedInputStream* input, - int64* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int64* value) { uint64 temp; if (!input->ReadVarint64(&temp)) return false; *value = static_cast(temp); return true; } -inline bool WireFormatLite::ReadUInt32(io::CodedInputStream* input, - uint32* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + uint32* value) { return input->ReadVarint32(value); } -inline bool WireFormatLite::ReadUInt64(io::CodedInputStream* input, - uint64* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + uint64* value) { return input->ReadVarint64(value); } -inline bool WireFormatLite::ReadSInt32(io::CodedInputStream* input, - int32* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int32* value) { uint32 temp; if (!input->ReadVarint32(&temp)) return false; *value = ZigZagDecode32(temp); return true; } -inline bool WireFormatLite::ReadSInt64(io::CodedInputStream* input, - int64* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int64* value) { uint64 temp; if (!input->ReadVarint64(&temp)) return false; *value = ZigZagDecode64(temp); return true; } -inline bool WireFormatLite::ReadFixed32(io::CodedInputStream* input, - uint32* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + uint32* value) { return input->ReadLittleEndian32(value); } -inline bool WireFormatLite::ReadFixed64(io::CodedInputStream* input, - uint64* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + uint64* value) { return input->ReadLittleEndian64(value); } -inline bool WireFormatLite::ReadSFixed32(io::CodedInputStream* input, - int32* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int32* value) { uint32 temp; if (!input->ReadLittleEndian32(&temp)) return false; *value = static_cast(temp); return true; } -inline bool WireFormatLite::ReadSFixed64(io::CodedInputStream* input, - int64* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int64* value) { uint64 temp; if (!input->ReadLittleEndian64(&temp)) return false; *value = static_cast(temp); return true; } -inline bool WireFormatLite::ReadFloat(io::CodedInputStream* input, - float* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + float* value) { uint32 temp; if (!input->ReadLittleEndian32(&temp)) return false; *value = DecodeFloat(temp); return true; } -inline bool WireFormatLite::ReadDouble(io::CodedInputStream* input, - double* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + double* value) { uint64 temp; if (!input->ReadLittleEndian64(&temp)) return false; *value = DecodeDouble(temp); return true; } -inline bool WireFormatLite::ReadBool(io::CodedInputStream* input, - bool* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + bool* value) { uint32 temp; if (!input->ReadVarint32(&temp)) return false; *value = temp != 0; return true; } -inline bool WireFormatLite::ReadEnum(io::CodedInputStream* input, - int* value) { +template <> +inline bool WireFormatLite::ReadPrimitive( + io::CodedInputStream* input, + int* value) { uint32 temp; if (!input->ReadVarint32(&temp)) return false; *value = static_cast(temp); return true; } -inline bool WireFormatLite::ReadString(io::CodedInputStream* input, - string* value) { - // String is for UTF-8 text only - uint32 length; - if (!input->ReadVarint32(&length)) return false; - if (!input->ReadString(value, length)) return false; +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + uint32, WireFormatLite::TYPE_FIXED32>( + const uint8* buffer, + uint32* value) { + return io::CodedInputStream::ReadLittleEndian32FromArray(buffer, value); +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + uint64, WireFormatLite::TYPE_FIXED64>( + const uint8* buffer, + uint64* value) { + return io::CodedInputStream::ReadLittleEndian64FromArray(buffer, value); +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + int32, WireFormatLite::TYPE_SFIXED32>( + const uint8* buffer, + int32* value) { + uint32 temp; + buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp); + *value = static_cast(temp); + return buffer; +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + int64, WireFormatLite::TYPE_SFIXED64>( + const uint8* buffer, + int64* value) { + uint64 temp; + buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp); + *value = static_cast(temp); + return buffer; +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + float, WireFormatLite::TYPE_FLOAT>( + const uint8* buffer, + float* value) { + uint32 temp; + buffer = io::CodedInputStream::ReadLittleEndian32FromArray(buffer, &temp); + *value = DecodeFloat(temp); + return buffer; +} +template <> +inline const uint8* WireFormatLite::ReadPrimitiveFromArray< + double, WireFormatLite::TYPE_DOUBLE>( + const uint8* buffer, + double* value) { + uint64 temp; + buffer = io::CodedInputStream::ReadLittleEndian64FromArray(buffer, &temp); + *value = DecodeDouble(temp); + return buffer; +} + +template +inline bool WireFormatLite::ReadRepeatedPrimitive(int tag_size, + uint32 tag, + io::CodedInputStream* input, + RepeatedField* values) { + CType value; + if (!ReadPrimitive(input, &value)) return false; + values->Add(value); + int elements_already_reserved = values->Capacity() - values->size(); + while (elements_already_reserved > 0 && input->ExpectTag(tag)) { + if (!ReadPrimitive(input, &value)) return false; + values->AddAlreadyReserved(value); + elements_already_reserved--; + } + return true; +} + +template +inline bool WireFormatLite::ReadRepeatedFixedSizePrimitive( + int tag_size, + uint32 tag, + io::CodedInputStream* input, + RepeatedField* values) { + GOOGLE_DCHECK_EQ(UInt32Size(tag), tag_size); + CType value; + if (!ReadPrimitive(input, &value)) + return false; + values->Add(value); + + // For fixed size values, repeated values can be read more quickly by + // reading directly from a raw array. + // + // We can get a tight loop by only reading as many elements as can be + // added to the RepeatedField without having to do any resizing. Additionally, + // we only try to read as many elements as are available from the current + // buffer space. Doing so avoids having to perform boundary checks when + // reading the value: the maximum number of elements that can be read is + // known outside of the loop. + const void* void_pointer; + int size; + input->GetDirectBufferPointerInline(&void_pointer, &size); + if (size > 0) { + const uint8* buffer = reinterpret_cast(void_pointer); + // The number of bytes each type occupies on the wire. + const int per_value_size = tag_size + sizeof(value); + + int elements_available = min(values->Capacity() - values->size(), + size / per_value_size); + int num_read = 0; + while (num_read < elements_available && + (buffer = io::CodedInputStream::ExpectTagFromArray( + buffer, tag)) != NULL) { + buffer = ReadPrimitiveFromArray(buffer, &value); + values->AddAlreadyReserved(value); + ++num_read; + } + const int read_bytes = num_read * per_value_size; + if (read_bytes > 0) { + input->Skip(read_bytes); + } + } return true; } -inline bool WireFormatLite::ReadBytes(io::CodedInputStream* input, - string* value) { + +// Specializations of ReadRepeatedPrimitive for the fixed size types, which use +// the optimized code path. +#define READ_REPEATED_FIXED_SIZE_PRIMITIVE(CPPTYPE, DECLARED_TYPE) \ +template <> \ +inline bool WireFormatLite::ReadRepeatedPrimitive< \ + CPPTYPE, WireFormatLite::DECLARED_TYPE>( \ + int tag_size, \ + uint32 tag, \ + io::CodedInputStream* input, \ + RepeatedField* values) { \ + return ReadRepeatedFixedSizePrimitive< \ + CPPTYPE, WireFormatLite::DECLARED_TYPE>( \ + tag_size, tag, input, values); \ +} + +READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint32, TYPE_FIXED32); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(uint64, TYPE_FIXED64); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(int32, TYPE_SFIXED32); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(int64, TYPE_SFIXED64); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(float, TYPE_FLOAT); +READ_REPEATED_FIXED_SIZE_PRIMITIVE(double, TYPE_DOUBLE); + +#undef READ_REPEATED_FIXED_SIZE_PRIMITIVE + +template +bool WireFormatLite::ReadRepeatedPrimitiveNoInline( + int tag_size, + uint32 tag, + io::CodedInputStream* input, + RepeatedField* value) { + return ReadRepeatedPrimitive( + tag_size, tag, input, value); +} + +template +inline bool WireFormatLite::ReadPackedPrimitive(io::CodedInputStream* input, + RepeatedField* values) { uint32 length; if (!input->ReadVarint32(&length)) return false; - return input->ReadString(value, length); + io::CodedInputStream::Limit limit = input->PushLimit(length); + while (input->BytesUntilLimit() > 0) { + CType value; + if (!ReadPrimitive(input, &value)) return false; + values->Add(value); + } + input->PopLimit(limit); + return true; +} + +template +bool WireFormatLite::ReadPackedPrimitiveNoInline(io::CodedInputStream* input, + RepeatedField* values) { + return ReadPackedPrimitive(input, values); } @@ -270,107 +461,6 @@ inline void WireFormatLite::WriteEnumNoTag(int value, output->WriteVarint32SignExtended(value); } -inline void WireFormatLite::WriteInt32(int field_number, int32 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteInt32NoTag(value, output); -} -inline void WireFormatLite::WriteInt64(int field_number, int64 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteInt64NoTag(value, output); -} -inline void WireFormatLite::WriteUInt32(int field_number, uint32 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteUInt32NoTag(value, output); -} -inline void WireFormatLite::WriteUInt64(int field_number, uint64 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteUInt64NoTag(value, output); -} -inline void WireFormatLite::WriteSInt32(int field_number, int32 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteSInt32NoTag(value, output); -} -inline void WireFormatLite::WriteSInt64(int field_number, int64 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteSInt64NoTag(value, output); -} -inline void WireFormatLite::WriteFixed32(int field_number, uint32 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED32, output); - WriteFixed32NoTag(value, output); -} -inline void WireFormatLite::WriteFixed64(int field_number, uint64 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED64, output); - WriteFixed64NoTag(value, output); -} -inline void WireFormatLite::WriteSFixed32(int field_number, int32 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED32, output); - WriteSFixed32NoTag(value, output); -} -inline void WireFormatLite::WriteSFixed64(int field_number, int64 value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED64, output); - WriteSFixed64NoTag(value, output); -} -inline void WireFormatLite::WriteFloat(int field_number, float value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED32, output); - WriteFloatNoTag(value, output); -} -inline void WireFormatLite::WriteDouble(int field_number, double value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_FIXED64, output); - WriteDoubleNoTag(value, output); -} -inline void WireFormatLite::WriteBool(int field_number, bool value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteBoolNoTag(value, output); -} -inline void WireFormatLite::WriteEnum(int field_number, int value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_VARINT, output); - WriteEnumNoTag(value, output); -} - -inline void WireFormatLite::WriteString(int field_number, const string& value, - io::CodedOutputStream* output) { - // String is for UTF-8 text only - WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); - output->WriteVarint32(value.size()); - output->WriteString(value); -} -inline void WireFormatLite::WriteBytes(int field_number, const string& value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); - output->WriteVarint32(value.size()); - output->WriteString(value); -} - - -inline void WireFormatLite::WriteGroup(int field_number, - const MessageLite& value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_START_GROUP, output); - value.SerializeWithCachedSizes(output); - WriteTag(field_number, WIRETYPE_END_GROUP, output); -} -inline void WireFormatLite::WriteMessage(int field_number, - const MessageLite& value, - io::CodedOutputStream* output) { - WriteTag(field_number, WIRETYPE_LENGTH_DELIMITED, output); - output->WriteVarint32(value.GetCachedSize()); - value.SerializeWithCachedSizes(output); -} - template inline void WireFormatLite::WriteGroupNoVirtual(int field_number, const MessageType& value, diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc index 51960ee7..867970c4 100644 --- a/src/google/protobuf/wire_format_unittest.cc +++ b/src/google/protobuf/wire_format_unittest.cc @@ -126,6 +126,38 @@ TEST(WireFormatTest, ParsePacked) { TestUtil::ExpectPackedFieldsSet(dest); } +TEST(WireFormatTest, ParsePackedFromUnpacked) { + // Serialize using the generated code. + unittest::TestUnpackedTypes source; + TestUtil::SetUnpackedFields(&source); + string data = source.SerializeAsString(); + + // Parse using WireFormat. + unittest::TestPackedTypes dest; + io::ArrayInputStream raw_input(data.data(), data.size()); + io::CodedInputStream input(&raw_input); + WireFormat::ParseAndMergePartial(&input, &dest); + + // Check. + TestUtil::ExpectPackedFieldsSet(dest); +} + +TEST(WireFormatTest, ParseUnpackedFromPacked) { + // Serialize using the generated code. + unittest::TestPackedTypes source; + TestUtil::SetPackedFields(&source); + string data = source.SerializeAsString(); + + // Parse using WireFormat. + unittest::TestUnpackedTypes dest; + io::ArrayInputStream raw_input(data.data(), data.size()); + io::CodedInputStream input(&raw_input); + WireFormat::ParseAndMergePartial(&input, &dest); + + // Check. + TestUtil::ExpectUnpackedFieldsSet(dest); +} + TEST(WireFormatTest, ParsePackedExtensions) { unittest::TestPackedExtensions source, dest; string data; @@ -568,6 +600,45 @@ TEST(WireFormatTest, ZigZag) { LL(-75123905439571256)))); } +TEST(WireFormatTest, RepeatedScalarsDifferentTagSizes) { + // At one point checks would trigger when parsing repeated fixed scalar + // fields. + protobuf_unittest::TestRepeatedScalarDifferentTagSizes msg1, msg2; + for (int i = 0; i < 100; ++i) { + msg1.add_repeated_fixed32(i); + msg1.add_repeated_int32(i); + msg1.add_repeated_fixed64(i); + msg1.add_repeated_int64(i); + msg1.add_repeated_float(i); + msg1.add_repeated_uint64(i); + } + + // Make sure that we have a variety of tag sizes. + const google::protobuf::Descriptor* desc = msg1.GetDescriptor(); + const google::protobuf::FieldDescriptor* field; + field = desc->FindFieldByName("repeated_fixed32"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(1, WireFormat::TagSize(field->number(), field->type())); + field = desc->FindFieldByName("repeated_int32"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(1, WireFormat::TagSize(field->number(), field->type())); + field = desc->FindFieldByName("repeated_fixed64"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(2, WireFormat::TagSize(field->number(), field->type())); + field = desc->FindFieldByName("repeated_int64"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(2, WireFormat::TagSize(field->number(), field->type())); + field = desc->FindFieldByName("repeated_float"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(3, WireFormat::TagSize(field->number(), field->type())); + field = desc->FindFieldByName("repeated_uint64"); + ASSERT_TRUE(field != NULL); + ASSERT_EQ(3, WireFormat::TagSize(field->number(), field->type())); + + EXPECT_TRUE(msg2.ParseFromString(msg1.SerializeAsString())); + EXPECT_EQ(msg1.DebugString(), msg2.DebugString()); +} + class WireFormatInvalidInputTest : public testing::Test { protected: // Make a serialized TestAllTypes in which the field optional_nested_message -- cgit v1.2.3