diff options
Diffstat (limited to 'src/google')
51 files changed, 5895 insertions, 240 deletions
diff --git a/src/google/protobuf/arena.cc b/src/google/protobuf/arena.cc index 17b095aa..be0d9e34 100644 --- a/src/google/protobuf/arena.cc +++ b/src/google/protobuf/arena.cc @@ -30,6 +30,10 @@ #include <google/protobuf/arena.h> +#ifdef ADDRESS_SANITIZER +#include <sanitizer/asan_interface.h> +#endif + namespace google { namespace protobuf { @@ -91,6 +95,12 @@ Arena::Block* Arena::NewBlock(void* me, Block* my_last_block, size_t n, } else { b->owner = me; } +#ifdef ADDRESS_SANITIZER + // Poison the rest of the block for ASAN. It was unpoisoned by the underlying + // malloc but it's not yet usable until we return it as part of an allocation. + ASAN_POISON_MEMORY_REGION( + reinterpret_cast<char*>(b) + b->pos, b->size - b->pos); +#endif return b; } @@ -152,6 +162,9 @@ void* Arena::AllocateAligned(size_t n) { void* Arena::AllocFromBlock(Block* b, size_t n) { size_t p = b->pos; b->pos = p + n; +#ifdef ADDRESS_SANITIZER + ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast<char*>(b) + p, n); +#endif return reinterpret_cast<char*>(b) + p; } diff --git a/src/google/protobuf/arena_unittest.cc b/src/google/protobuf/arena_unittest.cc index b2281817..76a4274f 100644 --- a/src/google/protobuf/arena_unittest.cc +++ b/src/google/protobuf/arena_unittest.cc @@ -144,7 +144,7 @@ TEST(ArenaTest, InitialBlockTooSmall) { // Write to the memory we allocated; this should (but is not guaranteed to) // trigger a check for heap corruption if the object was allocated from the // initially-provided block. - memset(p, '\0', 128); + memset(p, '\0', 96); } TEST(ArenaTest, Parsing) { diff --git a/src/google/protobuf/compiler/cpp/cpp_enum.cc b/src/google/protobuf/compiler/cpp/cpp_enum.cc index 32d5516e..3ce1f120 100644 --- a/src/google/protobuf/compiler/cpp/cpp_enum.cc +++ b/src/google/protobuf/compiler/cpp/cpp_enum.cc @@ -106,8 +106,8 @@ void EnumGenerator::GenerateDefinition(io::Printer* printer) { // INT32_MIN and INT32_MAX if (descriptor_->value_count() > 0) printer->Print(",\n"); printer->Print(vars, - "$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = INT32_MIN,\n" - "$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = INT32_MAX"); + "$classname$_$prefix$INT_MIN_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32min,\n" + "$classname$_$prefix$INT_MAX_SENTINEL_DO_NOT_USE_ = ::google::protobuf::kint32max"); } printer->Outdent(); diff --git a/src/google/protobuf/compiler/cpp/cpp_extension.h b/src/google/protobuf/compiler/cpp/cpp_extension.h index d354c16a..1c1caf1f 100644 --- a/src/google/protobuf/compiler/cpp/cpp_extension.h +++ b/src/google/protobuf/compiler/cpp/cpp_extension.h @@ -57,7 +57,7 @@ namespace cpp { class ExtensionGenerator { public: // See generator.cc for the meaning of dllexport_decl. - explicit ExtensionGenerator(const FieldDescriptor* desycriptor, + explicit ExtensionGenerator(const FieldDescriptor* descriptor, const Options& options); ~ExtensionGenerator(); diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc index 8745577f..fae4df40 100644 --- a/src/google/protobuf/compiler/cpp/cpp_file.cc +++ b/src/google/protobuf/compiler/cpp/cpp_file.cc @@ -105,7 +105,6 @@ void FileGenerator::GenerateHeader(io::Printer* printer) { "#define PROTOBUF_$filename_identifier$__INCLUDED\n" "\n" "#include <string>\n" - "#include <stdint.h>\n" // INT32_MIN, INT32_MAX "\n", "filename", file_->name(), "filename_identifier", filename_identifier); diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc index 28ee3a9d..212bc3e9 100644 --- a/src/google/protobuf/compiler/cpp/cpp_message.cc +++ b/src/google/protobuf/compiler/cpp/cpp_message.cc @@ -561,7 +561,7 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) { } else { printer->Print(vars, "inline bool $classname$::has_$name$() const {\n" - " return $name$_ != NULL;\n" + " return !_is_default_instance_ && $name$_ != NULL;\n" "}\n"); } } @@ -614,7 +614,7 @@ GenerateFieldAccessorDefinitions(io::Printer* printer) { vars["classname"] = classname_; printer->Print( vars, - "inline bool $classname$::has_$oneof_name$() {\n" + "inline bool $classname$::has_$oneof_name$() const {\n" " return $oneof_name$_case() != $cap_oneof_name$_NOT_SET;\n" "}\n" "inline void $classname$::clear_has_$oneof_name$() {\n" @@ -975,7 +975,7 @@ GenerateClassDefinition(io::Printer* printer) { // Generate oneof function declarations for (int i = 0; i < descriptor_->oneof_decl_count(); i++) { printer->Print( - "inline bool has_$oneof_name$();\n" + "inline bool has_$oneof_name$() const;\n" "void clear_$oneof_name$();\n" "inline void clear_has_$oneof_name$();\n\n", "oneof_name", descriptor_->oneof_decl(i)->name()); @@ -1051,6 +1051,22 @@ GenerateClassDefinition(io::Printer* printer) { printer->Print(cached_size_decl.c_str()); need_to_emit_cached_size = false; } + } else { + // Without field presence, we need another way to disambiguate the default + // instance, because the default instance's submessage fields (if any) store + // pointers to the default instances of the submessages even when they + // aren't present. Alternatives to this approach might be to (i) use a + // tagged pointer on all message fields, setting a tag bit for "not really + // present, just default instance"; or (ii) comparing |this| against the + // return value from GeneratedMessageFactory::GetPrototype() in all + // has_$field$() calls. However, both of these options are much more + // expensive (in code size and CPU overhead) than just checking a field in + // the message. Long-term, the best solution would be to rearchitect the + // default instance design not to store pointers to submessage default + // instances, and have reflection get those some other way; but that change + // would have too much impact on proto2. + printer->Print( + "bool _is_default_instance_;\n"); } // Field members: @@ -1323,11 +1339,21 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) { if (UseUnknownFieldSet(descriptor_->file())) { printer->Print(vars, " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" - "$classname$, _internal_metadata_));\n"); + "$classname$, _internal_metadata_),\n"); + } else { + printer->Print(vars, + " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" + "$classname$, _arena_),\n"); + } + + // is_default_instance_ offset. + if (HasFieldPresence(descriptor_->file())) { + printer->Print(vars, + " -1);\n"); } else { printer->Print(vars, " GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(" - "$classname$, _arena_));\n"); + "$classname$, _is_default_instance_));\n"); } // Handle nested types. @@ -1612,6 +1638,11 @@ GenerateSharedConstructorCode(io::Printer* printer) { "classname", classname_); printer->Indent(); + if (!HasFieldPresence(descriptor_->file())) { + printer->Print( + " _is_default_instance_ = false;\n"); + } + printer->Print(StrCat( uses_string_ ? "::google::protobuf::internal::GetEmptyString();\n" : "", "_cached_size_ = 0;\n").c_str()); @@ -1809,6 +1840,11 @@ GenerateStructors(io::Printer* printer) { "void $classname$::InitAsDefaultInstance() {\n", "classname", classname_); + if (!HasFieldPresence(descriptor_->file())) { + printer->Print( + " _is_default_instance_ = true;\n"); + } + // The default instance needs all of its embedded message pointers // cross-linked to other default instances. We can't do this initialization // in the constructor because some other default instances may not have been diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc index 70f379bc..1171b718 100644 --- a/src/google/protobuf/compiler/java/java_message.cc +++ b/src/google/protobuf/compiler/java/java_message.cc @@ -306,31 +306,28 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { variables["lite"]); } printer->Indent(); - // Using builder_type, instead of Builder, prevents the Builder class from - // being loaded into PermGen space when the default instance is created. - // This optimizes the PermGen space usage for clients that do not modify - // messages. - printer->Print( - "// Use $classname$.newBuilder() to construct.\n" - "private $classname$($buildertype$ builder) {\n" - " super(builder);\n" - "}\n", - "classname", descriptor_->name(), - "buildertype", builder_type); - printer->Print( - "private $classname$() {\n", - "classname", descriptor_->name()); - printer->Indent(); - for (int i = 0; i < descriptor_->field_count(); i++) { - if (!descriptor_->field(i)->containing_oneof()) { - field_generators_.get(descriptor_->field(i)) - .GenerateInitializationCode(printer); - } + if (HasDescriptorMethods(descriptor_)) { + // Using builder_type, instead of Builder, prevents the Builder class from + // being loaded into PermGen space when the default instance is created. + // This optimizes the PermGen space usage for clients that do not modify + // messages. + printer->Print( + "// Use $classname$.newBuilder() to construct.\n" + "private $classname$($buildertype$ builder) {\n" + " super(builder);\n" + "}\n", + "classname", descriptor_->name(), + "buildertype", builder_type); + printer->Print( + "private $classname$() {\n", + "classname", descriptor_->name()); + printer->Indent(); + GenerateInitializers(printer); + printer->Outdent(); + printer->Print( + "}\n" + "\n"); } - printer->Outdent(); - printer->Print( - "}\n" - "\n"); if (HasDescriptorMethods(descriptor_)) { printer->Print( @@ -480,10 +477,37 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { "// @@protoc_insertion_point(class_scope:$full_name$)\n", "full_name", descriptor_->full_name()); + // Carefully initialize the default instance in such a way that it doesn't // conflict with other initialization. - printer->Print("private static final $classname$ defaultInstance =\n" - " new $classname$();\n" + printer->Print( + "private static final $classname$ defaultInstance;", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + if (HasDescriptorMethods(descriptor_)) { + printer->Print( + "static {\n" + " defaultInstance = new $classname$();\n" + "}\n" + "\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + } else { + // LITE_RUNTIME only has one constructor. + printer->Print( + "static {\n" + " try {\n" + " defaultInstance = new $classname$(\n" + " com.google.protobuf.Internal\n" + " .EMPTY_CODED_INPUT_STREAM,\n" + " com.google.protobuf.ExtensionRegistryLite\n" + " .getEmptyRegistry());\n" + " } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n" + " throw new ExceptionInInitializerError(e);\n" + " }\n" + "}\n" + "\n", + "classname", descriptor_->name()); + } + printer->Print( "public static $classname$ getDefaultInstance() {\n" " return defaultInstance;\n" "}\n" @@ -492,7 +516,7 @@ void ImmutableMessageGenerator::Generate(io::Printer* printer) { " return defaultInstance;\n" "}\n" "\n", - "classname", descriptor_->name()); + "classname", name_resolver_->GetImmutableClassName(descriptor_)); // Extensions must be declared after the defaultInstance is initialized // because the defaultInstance is used by the extension to lazily retrieve @@ -773,6 +797,7 @@ void ImmutableMessageGenerator::GenerateBuilder(io::Printer* printer) { if (HasGeneratedMethods(descriptor_)) { GenerateIsInitialized(printer, DONT_MEMOIZE); + GenerateBuilderParsingMethods(printer); } // oneof @@ -1034,10 +1059,33 @@ GenerateCommonBuilderMethods(io::Printer* printer) { "classname", name_resolver_->GetImmutableClassName(descriptor_)); } - printer->Print( - "public $classname$ buildPartial() {\n" - " $classname$ result = new $classname$(this);\n", - "classname", name_resolver_->GetImmutableClassName(descriptor_)); + if (HasDescriptorMethods(descriptor_)) { + printer->Print( + "public $classname$ buildPartial() {\n" + " $classname$ result = new $classname$(this);\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + } else { + // LITE_RUNTIME only provides a single message constructor. + printer->Print( + "public $classname$ buildPartial() {\n" + " $classname$ result = null;\n" + " try {\n" + " result = new $classname$(\n" + " com.google.protobuf.Internal\n" + " .EMPTY_CODED_INPUT_STREAM,\n" + " com.google.protobuf.ExtensionRegistryLite\n" + " .getEmptyRegistry());\n" + " } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n" + " throw new RuntimeException(e);\n" + " }\n" + " result.unknownFields = this.unknownFields;\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + + if (descriptor_->extension_range_count() > 0) { + printer->Print( + " result.extensions = this.buildExtensions();\n"); + } + } printer->Indent(); @@ -1193,6 +1241,34 @@ GenerateCommonBuilderMethods(io::Printer* printer) { // =================================================================== +void ImmutableMessageGenerator:: +GenerateBuilderParsingMethods(io::Printer* printer) { + if (HasDescriptorMethods(descriptor_)) { + // LITE_RUNTIME implements this at the GeneratedMessageLite level. + printer->Print( + "public Builder mergeFrom(\n" + " com.google.protobuf.CodedInputStream input,\n" + " com.google.protobuf.ExtensionRegistryLite extensionRegistry)\n" + " throws java.io.IOException {\n" + " $classname$ parsedMessage = null;\n" + " try {\n" + " parsedMessage = PARSER.parsePartialFrom(input, extensionRegistry);\n" + " } catch (com.google.protobuf.InvalidProtocolBufferException e) {\n" + " parsedMessage = ($classname$) e.getUnfinishedMessage();\n" + " throw e;\n" + " } finally {\n" + " if (parsedMessage != null) {\n" + " mergeFrom(parsedMessage);\n" + " }\n" + " }\n" + " return this;\n" + "}\n", + "classname", name_resolver_->GetImmutableClassName(descriptor_)); + } +} + +// =================================================================== + void ImmutableMessageGenerator::GenerateIsInitialized( io::Printer* printer, UseMemoization useMemoization) { bool memoization = useMemoization == MEMOIZE; @@ -1488,8 +1564,13 @@ GenerateParsingConstructor(io::Printer* printer) { printer->Indent(); // Initialize all fields to default. - printer->Print( - "this();\n"); + if (HasDescriptorMethods(descriptor_)) { + printer->Print( + "this();\n"); + } else { + // LITE_RUNTIME only has one constructor. + GenerateInitializers(printer); + } // Use builder bits to track mutable repeated fields. int totalBuilderBits = 0; @@ -1703,6 +1784,16 @@ void ImmutableMessageGenerator::GenerateParser(io::Printer* printer) { "classname", descriptor_->name()); } +// =================================================================== +void ImmutableMessageGenerator::GenerateInitializers(io::Printer* printer) { + for (int i = 0; i < descriptor_->field_count(); i++) { + if (!descriptor_->field(i)->containing_oneof()) { + field_generators_.get(descriptor_->field(i)) + .GenerateInitializationCode(printer); + } + } +} + } // namespace java } // namespace compiler diff --git a/src/google/protobuf/compiler/java/java_message.h b/src/google/protobuf/compiler/java/java_message.h index 2703016e..91eb2876 100644 --- a/src/google/protobuf/compiler/java/java_message.h +++ b/src/google/protobuf/compiler/java/java_message.h @@ -118,8 +118,10 @@ class ImmutableMessageGenerator : public MessageGenerator { void GenerateBuilder(io::Printer* printer); void GenerateCommonBuilderMethods(io::Printer* printer); void GenerateDescriptorMethods(io::Printer* printer); + void GenerateBuilderParsingMethods(io::Printer* printer); void GenerateIsInitialized(io::Printer* printer, UseMemoization useMemoization); + void GenerateInitializers(io::Printer* printer); void GenerateEqualsAndHashCode(io::Printer* printer); void GenerateParser(io::Printer* printer); void GenerateParsingConstructor(io::Printer* printer); diff --git a/src/google/protobuf/compiler/javanano/javanano_enum.cc b/src/google/protobuf/compiler/javanano/javanano_enum.cc new file mode 100644 index 00000000..f934b05f --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_enum.cc @@ -0,0 +1,111 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <map> +#include <string> + +#include <google/protobuf/compiler/javanano/javanano_params.h> +#include <google/protobuf/compiler/javanano/javanano_enum.h> +#include <google/protobuf/compiler/javanano/javanano_helpers.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +EnumGenerator::EnumGenerator(const EnumDescriptor* descriptor, const Params& params) + : params_(params), descriptor_(descriptor) { + for (int i = 0; i < descriptor_->value_count(); i++) { + const EnumValueDescriptor* value = descriptor_->value(i); + const EnumValueDescriptor* canonical_value = + descriptor_->FindValueByNumber(value->number()); + + if (value == canonical_value) { + canonical_values_.push_back(value); + } else { + Alias alias; + alias.value = value; + alias.canonical_value = canonical_value; + aliases_.push_back(alias); + } + } +} + +EnumGenerator::~EnumGenerator() {} + +void EnumGenerator::Generate(io::Printer* printer) { + printer->Print( + "\n" + "// enum $classname$\n", + "classname", descriptor_->name()); + + // Start of container interface + bool use_shell_class = params_.java_enum_style(); + if (use_shell_class) { + printer->Print( + "public interface $classname$ {\n", + "classname", RenameJavaKeywords(descriptor_->name())); + printer->Indent(); + } + + // Canonical values + for (int i = 0; i < canonical_values_.size(); i++) { + printer->Print( + "public static final int $name$ = $canonical_value$;\n", + "name", RenameJavaKeywords(canonical_values_[i]->name()), + "canonical_value", SimpleItoa(canonical_values_[i]->number())); + } + + // Aliases + for (int i = 0; i < aliases_.size(); i++) { + printer->Print( + "public static final int $name$ = $canonical_name$;\n", + "name", RenameJavaKeywords(aliases_[i].value->name()), + "canonical_name", RenameJavaKeywords(aliases_[i].canonical_value->name())); + } + + // End of container interface + if (use_shell_class) { + printer->Outdent(); + printer->Print("}\n"); + } +} + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javanano/javanano_enum.h b/src/google/protobuf/compiler/javanano/javanano_enum.h new file mode 100644 index 00000000..10dd3648 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_enum.h @@ -0,0 +1,87 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_H__ + +#include <string> +#include <vector> + +#include <google/protobuf/compiler/javanano/javanano_params.h> +#include <google/protobuf/descriptor.h> + +namespace google { +namespace protobuf { + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace javanano { + +class EnumGenerator { + public: + explicit EnumGenerator(const EnumDescriptor* descriptor, const Params& params); + ~EnumGenerator(); + + void Generate(io::Printer* printer); + + private: + const Params& params_; + const EnumDescriptor* descriptor_; + + // The proto language allows multiple enum constants to have the same numeric + // value. Java, however, does not allow multiple enum constants to be + // considered equivalent. We treat the first defined constant for any + // given numeric value as "canonical" and the rest as aliases of that + // canonical value. + vector<const EnumValueDescriptor*> canonical_values_; + + struct Alias { + const EnumValueDescriptor* value; + const EnumValueDescriptor* canonical_value; + }; + vector<Alias> aliases_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumGenerator); +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_H__ diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.cc b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc new file mode 100644 index 00000000..8a59d323 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc @@ -0,0 +1,520 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <map> +#include <string> + +#include <google/protobuf/compiler/javanano/javanano_enum_field.h> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/javanano/javanano_helpers.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +namespace { + +// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of +// repeat code between this and the other field types. +void SetEnumVariables(const Params& params, + const FieldDescriptor* descriptor, map<string, string>* variables) { + (*variables)["name"] = + RenameJavaKeywords(UnderscoresToCamelCase(descriptor)); + (*variables)["capitalized_name"] = + RenameJavaKeywords(UnderscoresToCapitalizedCamelCase(descriptor)); + (*variables)["number"] = SimpleItoa(descriptor->number()); + if (params.use_reference_types_for_primitives() + && !params.reftypes_primitive_enums() + && !descriptor->is_repeated()) { + (*variables)["type"] = "java.lang.Integer"; + (*variables)["default"] = "null"; + } else { + (*variables)["type"] = "int"; + (*variables)["default"] = DefaultValue(params, descriptor); + } + (*variables)["repeated_default"] = + "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY"; + (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor)); + (*variables)["tag_size"] = SimpleItoa( + internal::WireFormat::TagSize(descriptor->number(), descriptor->type())); + (*variables)["non_packed_tag"] = SimpleItoa( + internal::WireFormatLite::MakeTag(descriptor->number(), + internal::WireFormat::WireTypeForFieldType(descriptor->type()))); + (*variables)["message_name"] = descriptor->containing_type()->name(); +} + +void LoadEnumValues(const Params& params, + const EnumDescriptor* enum_descriptor, vector<string>* canonical_values) { + string enum_class_name = ClassName(params, enum_descriptor); + for (int i = 0; i < enum_descriptor->value_count(); i++) { + const EnumValueDescriptor* value = enum_descriptor->value(i); + const EnumValueDescriptor* canonical_value = + enum_descriptor->FindValueByNumber(value->number()); + if (value == canonical_value) { + canonical_values->push_back( + enum_class_name + "." + RenameJavaKeywords(value->name())); + } + } +} + +void PrintCaseLabels( + io::Printer* printer, const vector<string>& canonical_values) { + for (int i = 0; i < canonical_values.size(); i++) { + printer->Print( + " case $value$:\n", + "value", canonical_values[i]); + } +} + +} // namespace + +// =================================================================== + +EnumFieldGenerator:: +EnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params) + : FieldGenerator(params), descriptor_(descriptor) { + SetEnumVariables(params, descriptor, &variables_); + LoadEnumValues(params, descriptor->enum_type(), &canonical_values_); +} + +EnumFieldGenerator::~EnumFieldGenerator() {} + +void EnumFieldGenerator:: +GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const { + printer->Print(variables_, + "public $type$ $name$;\n"); + + if (params_.generate_has()) { + printer->Print(variables_, + "public boolean has$capitalized_name$;\n"); + } +} + +void EnumFieldGenerator:: +GenerateClearCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$ = $default$;\n"); + + if (params_.generate_has()) { + printer->Print(variables_, + "has$capitalized_name$ = false;\n"); + } +} + +void EnumFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "int value = input.readInt32();\n" + "switch (value) {\n"); + PrintCaseLabels(printer, canonical_values_); + printer->Print(variables_, + " this.$name$ = value;\n"); + if (params_.generate_has()) { + printer->Print(variables_, + " has$capitalized_name$ = true;\n"); + } + printer->Print( + " break;\n" + "}\n"); + // No default case: in case of invalid value from the wire, preserve old + // field value. Also we are not storing the invalid value into the unknown + // fields, because there is no way to get the value out. +} + +void EnumFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + if (descriptor_->is_required() && !params_.generate_has()) { + // Always serialize a required field if we don't have the 'has' signal. + printer->Print(variables_, + "output.writeInt32($number$, this.$name$);\n"); + } else { + if (params_.generate_has()) { + printer->Print(variables_, + "if (this.$name$ != $default$ || has$capitalized_name$) {\n"); + } else { + printer->Print(variables_, + "if (this.$name$ != $default$) {\n"); + } + printer->Print(variables_, + " output.writeInt32($number$, this.$name$);\n" + "}\n"); + } +} + +void EnumFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + if (descriptor_->is_required() && !params_.generate_has()) { + printer->Print(variables_, + "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .computeInt32Size($number$, this.$name$);\n"); + } else { + if (params_.generate_has()) { + printer->Print(variables_, + "if (this.$name$ != $default$ || has$capitalized_name$) {\n"); + } else { + printer->Print(variables_, + "if (this.$name$ != $default$) {\n"); + } + printer->Print(variables_, + " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .computeInt32Size($number$, this.$name$);\n" + "}\n"); + } +} + +void EnumFieldGenerator::GenerateEqualsCode(io::Printer* printer) const { + if (params_.use_reference_types_for_primitives() + && !params_.reftypes_primitive_enums()) { + printer->Print(variables_, + "if (this.$name$ == null) {\n" + " if (other.$name$ != null) {\n" + " return false;\n" + " }\n" + "} else if (!this.$name$.equals(other.$name$)) {\n" + " return false;" + "}\n"); + } else { + // We define equality as serialized form equality. If generate_has(), + // then if the field value equals the default value in both messages, + // but one's 'has' field is set and the other's is not, the serialized + // forms are different and we should return false. + printer->Print(variables_, + "if (this.$name$ != other.$name$"); + if (params_.generate_has()) { + printer->Print(variables_, + "\n" + " || (this.$name$ == $default$\n" + " && this.has$capitalized_name$ != other.has$capitalized_name$)"); + } + printer->Print(") {\n" + " return false;\n" + "}\n"); + } +} + +void EnumFieldGenerator::GenerateHashCodeCode(io::Printer* printer) const { + printer->Print( + "result = 31 * result + "); + if (params_.use_reference_types_for_primitives() + && !params_.reftypes_primitive_enums()) { + printer->Print(variables_, + "(this.$name$ == null ? 0 : this.$name$)"); + } else { + printer->Print(variables_, + "this.$name$"); + } + printer->Print(";\n"); +} + +// =================================================================== + +AccessorEnumFieldGenerator:: +AccessorEnumFieldGenerator(const FieldDescriptor* descriptor, + const Params& params, int has_bit_index) + : FieldGenerator(params), descriptor_(descriptor) { + SetEnumVariables(params, descriptor, &variables_); + LoadEnumValues(params, descriptor->enum_type(), &canonical_values_); + SetBitOperationVariables("has", has_bit_index, &variables_); +} + +AccessorEnumFieldGenerator::~AccessorEnumFieldGenerator() {} + +void AccessorEnumFieldGenerator:: +GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const { + printer->Print(variables_, + "private int $name$_;\n" + "public int get$capitalized_name$() {\n" + " return $name$_;\n" + "}\n" + "public $message_name$ set$capitalized_name$(int value) {\n" + " $name$_ = value;\n" + " $set_has$;\n" + " return this;\n" + "}\n" + "public boolean has$capitalized_name$() {\n" + " return $get_has$;\n" + "}\n" + "public $message_name$ clear$capitalized_name$() {\n" + " $name$_ = $default$;\n" + " $clear_has$;\n" + " return this;\n" + "}\n"); +} + +void AccessorEnumFieldGenerator:: +GenerateClearCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$_ = $default$;\n"); +} + +void AccessorEnumFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "int value = input.readInt32();\n" + "switch (value) {\n"); + PrintCaseLabels(printer, canonical_values_); + printer->Print(variables_, + " $name$_ = value;\n" + " $set_has$;\n" + " break;\n" + "}\n"); + // No default case: in case of invalid value from the wire, preserve old + // field value. Also we are not storing the invalid value into the unknown + // fields, because there is no way to get the value out. +} + +void AccessorEnumFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($get_has$) {\n" + " output.writeInt32($number$, $name$_);\n" + "}\n"); +} + +void AccessorEnumFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($get_has$) {\n" + " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .computeInt32Size($number$, $name$_);\n" + "}\n"); +} + +void AccessorEnumFieldGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($different_has$\n" + " || $name$_ != other.$name$_) {\n" + " return false;\n" + "}\n"); +} + +void AccessorEnumFieldGenerator:: +GenerateHashCodeCode(io::Printer* printer) const { + printer->Print(variables_, + "result = 31 * result + $name$_;\n"); +} + +// =================================================================== + +RepeatedEnumFieldGenerator:: +RepeatedEnumFieldGenerator(const FieldDescriptor* descriptor, const Params& params) + : FieldGenerator(params), descriptor_(descriptor) { + SetEnumVariables(params, descriptor, &variables_); + LoadEnumValues(params, descriptor->enum_type(), &canonical_values_); +} + +RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {} + +void RepeatedEnumFieldGenerator:: +GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const { + printer->Print(variables_, + "public $type$[] $name$;\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateClearCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$ = $repeated_default$;\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + // First, figure out the maximum length of the array, then parse, + // and finally copy the valid values to the field. + printer->Print(variables_, + "int length = com.google.protobuf.nano.WireFormatNano\n" + " .getRepeatedFieldArrayLength(input, $non_packed_tag$);\n" + "int[] validValues = new int[length];\n" + "int validCount = 0;\n" + "for (int i = 0; i < length; i++) {\n" + " if (i != 0) { // tag for first value already consumed.\n" + " input.readTag();\n" + " }\n" + " int value = input.readInt32();\n" + " switch (value) {\n"); + printer->Indent(); + PrintCaseLabels(printer, canonical_values_); + printer->Outdent(); + printer->Print(variables_, + " validValues[validCount++] = value;\n" + " break;\n" + " }\n" + "}\n" + "if (validCount != 0) {\n" + " int i = this.$name$ == null ? 0 : this.$name$.length;\n" + " if (i == 0 && validCount == validValues.length) {\n" + " this.$name$ = validValues;\n" + " } else {\n" + " int[] newArray = new int[i + validCount];\n" + " if (i != 0) {\n" + " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n" + " }\n" + " java.lang.System.arraycopy(validValues, 0, newArray, i, validCount);\n" + " this.$name$ = newArray;\n" + " }\n" + "}\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateMergingCodeFromPacked(io::Printer* printer) const { + printer->Print(variables_, + "int bytes = input.readRawVarint32();\n" + "int limit = input.pushLimit(bytes);\n" + "// First pass to compute array length.\n" + "int arrayLength = 0;\n" + "int startPos = input.getPosition();\n" + "while (input.getBytesUntilLimit() > 0) {\n" + " switch (input.readInt32()) {\n"); + printer->Indent(); + PrintCaseLabels(printer, canonical_values_); + printer->Outdent(); + printer->Print(variables_, + " arrayLength++;\n" + " break;\n" + " }\n" + "}\n" + "if (arrayLength != 0) {\n" + " input.rewindToPosition(startPos);\n" + " int i = this.$name$ == null ? 0 : this.$name$.length;\n" + " int[] newArray = new int[i + arrayLength];\n" + " if (i != 0) {\n" + " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n" + " }\n" + " while (input.getBytesUntilLimit() > 0) {\n" + " int value = input.readInt32();\n" + " switch (value) {\n"); + printer->Indent(); + printer->Indent(); + PrintCaseLabels(printer, canonical_values_); + printer->Outdent(); + printer->Outdent(); + printer->Print(variables_, + " newArray[i++] = value;\n" + " break;\n" + " }\n" + " }\n" + " this.$name$ = newArray;\n" + "}\n" + "input.popLimit(limit);\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateRepeatedDataSizeCode(io::Printer* printer) const { + // Creates a variable dataSize and puts the serialized size in there. + printer->Print(variables_, + "int dataSize = 0;\n" + "for (int i = 0; i < this.$name$.length; i++) {\n" + " int element = this.$name$[i];\n" + " dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .computeInt32SizeNoTag(element);\n" + "}\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if (this.$name$ != null && this.$name$.length > 0) {\n"); + printer->Indent(); + + if (descriptor_->options().packed()) { + GenerateRepeatedDataSizeCode(printer); + printer->Print(variables_, + "output.writeRawVarint32($tag$);\n" + "output.writeRawVarint32(dataSize);\n" + "for (int i = 0; i < this.$name$.length; i++) {\n" + " output.writeRawVarint32(this.$name$[i]);\n" + "}\n"); + } else { + printer->Print(variables_, + "for (int i = 0; i < this.$name$.length; i++) {\n" + " output.writeInt32($number$, this.$name$[i]);\n" + "}\n"); + } + + printer->Outdent(); + printer->Print(variables_, + "}\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if (this.$name$ != null && this.$name$.length > 0) {\n"); + printer->Indent(); + + GenerateRepeatedDataSizeCode(printer); + + printer->Print( + "size += dataSize;\n"); + if (descriptor_->options().packed()) { + printer->Print(variables_, + "size += $tag_size$;\n" + "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .computeRawVarint32Size(dataSize);\n"); + } else { + printer->Print(variables_, + "size += $tag_size$ * this.$name$.length;\n"); + } + + printer->Outdent(); + + printer->Print( + "}\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + printer->Print(variables_, + "if (!com.google.protobuf.nano.InternalNano.equals(\n" + " this.$name$, other.$name$)) {\n" + " return false;\n" + "}\n"); +} + +void RepeatedEnumFieldGenerator:: +GenerateHashCodeCode(io::Printer* printer) const { + printer->Print(variables_, + "result = 31 * result\n" + " + com.google.protobuf.nano.InternalNano.hashCode(this.$name$);\n"); +} + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.h b/src/google/protobuf/compiler/javanano/javanano_enum_field.h new file mode 100644 index 00000000..00adc61f --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.h @@ -0,0 +1,125 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_FIELD_H__ + +#include <map> +#include <string> +#include <vector> +#include <google/protobuf/compiler/javanano/javanano_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +class EnumFieldGenerator : public FieldGenerator { + public: + explicit EnumFieldGenerator( + const FieldDescriptor* descriptor, const Params& params); + ~EnumFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GenerateMembers(io::Printer* printer, bool lazy_init) const; + void GenerateClearCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCodeCode(io::Printer* printer) const; + + private: + const FieldDescriptor* descriptor_; + map<string, string> variables_; + vector<string> canonical_values_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(EnumFieldGenerator); +}; + +class AccessorEnumFieldGenerator : public FieldGenerator { + public: + explicit AccessorEnumFieldGenerator(const FieldDescriptor* descriptor, + const Params& params, int has_bit_index); + ~AccessorEnumFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GenerateMembers(io::Printer* printer, bool lazy_init) const; + void GenerateClearCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCodeCode(io::Printer* printer) const; + + private: + const FieldDescriptor* descriptor_; + map<string, string> variables_; + vector<string> canonical_values_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AccessorEnumFieldGenerator); +}; + +class RepeatedEnumFieldGenerator : public FieldGenerator { + public: + explicit RepeatedEnumFieldGenerator( + const FieldDescriptor* descriptor, const Params& params); + ~RepeatedEnumFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GenerateMembers(io::Printer* printer, bool lazy_init) const; + void GenerateClearCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateMergingCodeFromPacked(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCodeCode(io::Printer* printer) const; + + private: + void GenerateRepeatedDataSizeCode(io::Printer* printer) const; + + const FieldDescriptor* descriptor_; + map<string, string> variables_; + vector<string> canonical_values_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedEnumFieldGenerator); +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_ENUM_FIELD_H__ diff --git a/src/google/protobuf/compiler/javanano/javanano_extension.cc b/src/google/protobuf/compiler/javanano/javanano_extension.cc new file mode 100644 index 00000000..754ed550 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_extension.cc @@ -0,0 +1,150 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: bduff@google.com (Brian Duff) + +#include <google/protobuf/compiler/javanano/javanano_extension.h> +#include <google/protobuf/compiler/javanano/javanano_helpers.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/wire_format.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { + +const char* GetTypeConstantName(const FieldDescriptor::Type type) { + switch (type) { + case FieldDescriptor::TYPE_INT32 : return "TYPE_INT32" ; + case FieldDescriptor::TYPE_UINT32 : return "TYPE_UINT32" ; + case FieldDescriptor::TYPE_SINT32 : return "TYPE_SINT32" ; + case FieldDescriptor::TYPE_FIXED32 : return "TYPE_FIXED32" ; + case FieldDescriptor::TYPE_SFIXED32: return "TYPE_SFIXED32"; + case FieldDescriptor::TYPE_INT64 : return "TYPE_INT64" ; + case FieldDescriptor::TYPE_UINT64 : return "TYPE_UINT64" ; + case FieldDescriptor::TYPE_SINT64 : return "TYPE_SINT64" ; + case FieldDescriptor::TYPE_FIXED64 : return "TYPE_FIXED64" ; + case FieldDescriptor::TYPE_SFIXED64: return "TYPE_SFIXED64"; + case FieldDescriptor::TYPE_FLOAT : return "TYPE_FLOAT" ; + case FieldDescriptor::TYPE_DOUBLE : return "TYPE_DOUBLE" ; + case FieldDescriptor::TYPE_BOOL : return "TYPE_BOOL" ; + case FieldDescriptor::TYPE_STRING : return "TYPE_STRING" ; + case FieldDescriptor::TYPE_BYTES : return "TYPE_BYTES" ; + case FieldDescriptor::TYPE_ENUM : return "TYPE_ENUM" ; + case FieldDescriptor::TYPE_GROUP : return "TYPE_GROUP" ; + case FieldDescriptor::TYPE_MESSAGE : return "TYPE_MESSAGE" ; + + // No default because we want the compiler to complain if any new + // types are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + +} // namespace + +void SetVariables(const FieldDescriptor* descriptor, const Params params, + map<string, string>* variables) { + (*variables)["extends"] = ClassName(params, descriptor->containing_type()); + (*variables)["name"] = RenameJavaKeywords(UnderscoresToCamelCase(descriptor)); + bool repeated = descriptor->is_repeated(); + (*variables)["repeated"] = repeated ? "Repeated" : ""; + (*variables)["type"] = GetTypeConstantName(descriptor->type()); + JavaType java_type = GetJavaType(descriptor->type()); + string tag = SimpleItoa(WireFormat::MakeTag(descriptor)); + if (java_type == JAVATYPE_MESSAGE) { + (*variables)["ext_type"] = "MessageTyped"; + string message_type = ClassName(params, descriptor->message_type()); + if (repeated) { + message_type += "[]"; + } + (*variables)["class"] = message_type; + // For message typed extensions, tags_params contains a single tag + // for both singular and repeated cases. + (*variables)["tag_params"] = tag; + } else { + (*variables)["ext_type"] = "PrimitiveTyped"; + if (!repeated) { + (*variables)["class"] = BoxedPrimitiveTypeName(java_type); + (*variables)["tag_params"] = tag; + } else { + (*variables)["class"] = PrimitiveTypeName(java_type) + "[]"; + if (!descriptor->is_packable()) { + // Non-packable: nonPackedTag == tag, packedTag == 0 + (*variables)["tag_params"] = tag + ", " + tag + ", 0"; + } else if (descriptor->options().packed()) { + // Packable and packed: tag == packedTag + string non_packed_tag = SimpleItoa(WireFormatLite::MakeTag( + descriptor->number(), + WireFormat::WireTypeForFieldType(descriptor->type()))); + (*variables)["tag_params"] = tag + ", " + non_packed_tag + ", " + tag; + } else { + // Packable and not packed: tag == nonPackedTag + string packed_tag = SimpleItoa(WireFormatLite::MakeTag( + descriptor->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED)); + (*variables)["tag_params"] = tag + ", " + tag + ", " + packed_tag; + } + } + } +} + +ExtensionGenerator:: +ExtensionGenerator(const FieldDescriptor* descriptor, const Params& params) + : params_(params), descriptor_(descriptor) { + SetVariables(descriptor, params, &variables_); +} + +ExtensionGenerator::~ExtensionGenerator() {} + +void ExtensionGenerator::Generate(io::Printer* printer) const { + printer->Print("\n"); + PrintFieldComment(printer, descriptor_); + printer->Print(variables_, + "public static final com.google.protobuf.nano.Extension<\n" + " $extends$,\n" + " $class$> $name$ =\n" + " com.google.protobuf.nano.Extension.create$repeated$$ext_type$(\n" + " com.google.protobuf.nano.Extension.$type$,\n" + " $class$.class,\n" + " $tag_params$);\n"); +} + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google + diff --git a/src/google/protobuf/compiler/javanano/javanano_extension.h b/src/google/protobuf/compiler/javanano/javanano_extension.h new file mode 100644 index 00000000..4843e296 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_extension.h @@ -0,0 +1,74 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: bduff@google.com (Brian Duff) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_EXTENSION_H_ +#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_EXTENSION_H_ + +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/javanano/javanano_params.h> +#include <google/protobuf/descriptor.pb.h> + + +namespace google { +namespace protobuf { + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace javanano { + +class ExtensionGenerator { + public: + explicit ExtensionGenerator(const FieldDescriptor* descriptor, const Params& params); + ~ExtensionGenerator(); + + void Generate(io::Printer* printer) const; + + private: + const Params& params_; + const FieldDescriptor* descriptor_; + map<string, string> variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(ExtensionGenerator); +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_EXTENSION_H_ diff --git a/src/google/protobuf/compiler/javanano/javanano_field.cc b/src/google/protobuf/compiler/javanano/javanano_field.cc new file mode 100644 index 00000000..e3e4cefe --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_field.cc @@ -0,0 +1,143 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <google/protobuf/compiler/javanano/javanano_field.h> +#include <google/protobuf/compiler/javanano/javanano_helpers.h> +#include <google/protobuf/compiler/javanano/javanano_primitive_field.h> +#include <google/protobuf/compiler/javanano/javanano_enum_field.h> +#include <google/protobuf/compiler/javanano/javanano_message_field.h> +#include <google/protobuf/stubs/common.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +FieldGenerator::~FieldGenerator() {} + +bool FieldGenerator::SavedDefaultNeeded() const { + // No saved default for this field by default. + // Subclasses whose instances may need saved defaults will override this + // and return the appropriate value. + return false; +} + +void FieldGenerator::GenerateInitSavedDefaultCode(io::Printer* printer) const { + // No saved default for this field by default. + // Subclasses whose instances may need saved defaults will override this + // and generate the appropriate init code to the printer. +} + +void FieldGenerator::GenerateMergingCodeFromPacked(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, const Params ¶ms) + : descriptor_(descriptor), + field_generators_( + new scoped_ptr<FieldGenerator>[descriptor->field_count()]) { + + int next_has_bit_index = 0; + bool saved_defaults_needed = false; + // Construct all the FieldGenerators. + for (int i = 0; i < descriptor->field_count(); i++) { + FieldGenerator* field_generator = MakeGenerator( + descriptor->field(i), params, &next_has_bit_index); + saved_defaults_needed = saved_defaults_needed + || field_generator->SavedDefaultNeeded(); + field_generators_[i].reset(field_generator); + } + total_bits_ = next_has_bit_index; + saved_defaults_needed_ = saved_defaults_needed; +} + +FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field, + const Params ¶ms, int* next_has_bit_index) { + JavaType java_type = GetJavaType(field); + if (field->is_repeated()) { + switch (java_type) { + case JAVATYPE_MESSAGE: + return new RepeatedMessageFieldGenerator(field, params); + case JAVATYPE_ENUM: + return new RepeatedEnumFieldGenerator(field, params); + default: + return new RepeatedPrimitiveFieldGenerator(field, params); + } + } else if (params.optional_field_accessors() && field->is_optional() + && java_type != JAVATYPE_MESSAGE) { + // We need a has-bit for each primitive/enum field because their default + // values could be same as explicitly set values. But we don't need it + // for a message field because they have no defaults and Nano uses 'null' + // for unset messages, which cannot be set explicitly. + switch (java_type) { + case JAVATYPE_ENUM: + return new AccessorEnumFieldGenerator( + field, params, (*next_has_bit_index)++); + default: + return new AccessorPrimitiveFieldGenerator( + field, params, (*next_has_bit_index)++); + } + } else { + switch (java_type) { + case JAVATYPE_MESSAGE: + return new MessageFieldGenerator(field, params); + case JAVATYPE_ENUM: + return new EnumFieldGenerator(field, params); + default: + return new PrimitiveFieldGenerator(field, params); + } + } +} + +FieldGeneratorMap::~FieldGeneratorMap() {} + +const FieldGenerator& FieldGeneratorMap::get( + const FieldDescriptor* field) const { + GOOGLE_CHECK_EQ(field->containing_type(), descriptor_); + return *field_generators_[field->index()]; +} + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javanano/javanano_field.h b/src/google/protobuf/compiler/javanano/javanano_field.h new file mode 100644 index 00000000..6170c2c0 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_field.h @@ -0,0 +1,119 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_FIELD_H__ + +#include <string> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/compiler/javanano/javanano_params.h> + +namespace google { +namespace protobuf { + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace javanano { + +class FieldGenerator { + public: + FieldGenerator(const Params& params) : params_(params) {} + virtual ~FieldGenerator(); + + virtual bool SavedDefaultNeeded() const; + virtual void GenerateInitSavedDefaultCode(io::Printer* printer) const; + + // Generates code for Java fields and methods supporting this field. + // If this field needs a saved default (SavedDefaultNeeded() is true), + // then @lazy_init controls how the static field for that default value + // and its initialization code should be generated. If @lazy_init is + // true, the static field is not declared final and the initialization + // code is generated only when GenerateInitSavedDefaultCode is called; + // otherwise, the static field is declared final and initialized inline. + // GenerateInitSavedDefaultCode will not be called in the latter case. + virtual void GenerateMembers( + io::Printer* printer, bool lazy_init) const = 0; + + virtual void GenerateClearCode(io::Printer* printer) const = 0; + virtual void GenerateMergingCode(io::Printer* printer) const = 0; + + // Generates code to merge from packed serialized form. The default + // implementation will fail; subclasses which can handle packed serialized + // forms will override this and print appropriate code to the printer. + virtual void GenerateMergingCodeFromPacked(io::Printer* printer) const; + + virtual void GenerateSerializationCode(io::Printer* printer) const = 0; + virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0; + virtual void GenerateEqualsCode(io::Printer* printer) const = 0; + virtual void GenerateHashCodeCode(io::Printer* printer) const = 0; + + protected: + const Params& params_; + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGenerator); +}; + +// Convenience class which constructs FieldGenerators for a Descriptor. +class FieldGeneratorMap { + public: + explicit FieldGeneratorMap(const Descriptor* descriptor, const Params ¶ms); + ~FieldGeneratorMap(); + + const FieldGenerator& get(const FieldDescriptor* field) const; + int total_bits() const { return total_bits_; } + bool saved_defaults_needed() const { return saved_defaults_needed_; } + + private: + const Descriptor* descriptor_; + scoped_array<scoped_ptr<FieldGenerator> > field_generators_; + int total_bits_; + bool saved_defaults_needed_; + + static FieldGenerator* MakeGenerator(const FieldDescriptor* field, + const Params ¶ms, int* next_has_bit_index); + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FieldGeneratorMap); +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_FIELD_H__ diff --git a/src/google/protobuf/compiler/javanano/javanano_file.cc b/src/google/protobuf/compiler/javanano/javanano_file.cc new file mode 100644 index 00000000..3676ab9d --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_file.cc @@ -0,0 +1,263 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <iostream> + +#include <google/protobuf/compiler/javanano/javanano_file.h> +#include <google/protobuf/compiler/javanano/javanano_enum.h> +#include <google/protobuf/compiler/javanano/javanano_extension.h> +#include <google/protobuf/compiler/javanano/javanano_helpers.h> +#include <google/protobuf/compiler/javanano/javanano_message.h> +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +namespace { + +// Recursively searches the given message to see if it contains any extensions. +bool UsesExtensions(const Message& message) { + const Reflection* reflection = message.GetReflection(); + + // We conservatively assume that unknown fields are extensions. + if (reflection->GetUnknownFields(message).field_count() > 0) return true; + + vector<const FieldDescriptor*> fields; + reflection->ListFields(message, &fields); + + for (int i = 0; i < fields.size(); i++) { + if (fields[i]->is_extension()) return true; + + if (fields[i]->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + if (fields[i]->is_repeated()) { + int size = reflection->FieldSize(message, fields[i]); + for (int j = 0; j < size; j++) { + const Message& sub_message = + reflection->GetRepeatedMessage(message, fields[i], j); + if (UsesExtensions(sub_message)) return true; + } + } else { + const Message& sub_message = reflection->GetMessage(message, fields[i]); + if (UsesExtensions(sub_message)) return true; + } + } + } + + return false; +} + +} // namespace + +FileGenerator::FileGenerator(const FileDescriptor* file, const Params& params) + : file_(file), + params_(params), + java_package_(FileJavaPackage(params, file)), + classname_(FileClassName(params, file)) {} + +FileGenerator::~FileGenerator() {} + +bool FileGenerator::Validate(string* error) { + // Check for extensions + FileDescriptorProto file_proto; + file_->CopyTo(&file_proto); + if (UsesExtensions(file_proto) && !params_.store_unknown_fields()) { + error->assign(file_->name()); + error->append( + ": Java NANO_RUNTIME only supports extensions when the " + "'store_unknown_fields' generator option is 'true'."); + return false; + } + + if (file_->service_count() != 0 && !params_.ignore_services()) { + error->assign(file_->name()); + error->append( + ": Java NANO_RUNTIME does not support services\""); + return false; + } + + if (!IsOuterClassNeeded(params_, file_)) { + return true; + } + + // Check whether legacy javanano generator would omit the outer class. + if (!params_.has_java_outer_classname(file_->name()) + && file_->message_type_count() == 1 + && file_->enum_type_count() == 0 && file_->extension_count() == 0) { + cout << "INFO: " << file_->name() << ":" << endl; + cout << "Javanano generator has changed to align with java generator. " + "An outer class will be created for this file and the single message " + "in the file will become a nested class. Use java_multiple_files to " + "skip generating the outer class, or set an explicit " + "java_outer_classname to suppress this message." << endl; + } + + // Check that no class name matches the file's class name. This is a common + // problem that leads to Java compile errors that can be hard to understand. + // It's especially bad when using the java_multiple_files, since we would + // end up overwriting the outer class with one of the inner ones. + bool found_conflict = false; + for (int i = 0; !found_conflict && i < file_->message_type_count(); i++) { + if (file_->message_type(i)->name() == classname_) { + found_conflict = true; + } + } + if (params_.java_enum_style()) { + for (int i = 0; !found_conflict && i < file_->enum_type_count(); i++) { + if (file_->enum_type(i)->name() == classname_) { + found_conflict = true; + } + } + } + if (found_conflict) { + error->assign(file_->name()); + error->append( + ": Cannot generate Java output because the file's outer class name, \""); + error->append(classname_); + error->append( + "\", matches the name of one of the types declared inside it. " + "Please either rename the type or use the java_outer_classname " + "option to specify a different outer class name for the .proto file."); + return false; + } + return true; +} + +void FileGenerator::Generate(io::Printer* printer) { + // We don't import anything because we refer to all classes by their + // fully-qualified names in the generated source. + printer->Print( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"); + if (!java_package_.empty()) { + printer->Print( + "\n" + "package $package$;\n", + "package", java_package_); + } + + // Note: constants (from enums, emitted in the loop below) may have the same names as constants + // in the nested classes. This causes Java warnings, but is not fatal, so we suppress those + // warnings here in the top-most class declaration. + printer->Print( + "\n" + "@SuppressWarnings(\"hiding\")\n" + "public interface $classname$ {\n", + "classname", classname_); + printer->Indent(); + + // ----------------------------------------------------------------- + + // Extensions. + for (int i = 0; i < file_->extension_count(); i++) { + ExtensionGenerator(file_->extension(i), params_).Generate(printer); + } + + // Enums. + for (int i = 0; i < file_->enum_type_count(); i++) { + EnumGenerator(file_->enum_type(i), params_).Generate(printer); + } + + // Messages. + if (!params_.java_multiple_files(file_->name())) { + for (int i = 0; i < file_->message_type_count(); i++) { + MessageGenerator(file_->message_type(i), params_).Generate(printer); + } + } + + // Static variables. + for (int i = 0; i < file_->message_type_count(); i++) { + // TODO(kenton): Reuse MessageGenerator objects? + MessageGenerator(file_->message_type(i), params_).GenerateStaticVariables(printer); + } + + printer->Outdent(); + printer->Print( + "}\n"); +} + +template<typename GeneratorClass, typename DescriptorClass> +static void GenerateSibling(const string& package_dir, + const string& java_package, + const DescriptorClass* descriptor, + GeneratorContext* output_directory, + vector<string>* file_list, + const Params& params) { + string filename = package_dir + descriptor->name() + ".java"; + file_list->push_back(filename); + + scoped_ptr<io::ZeroCopyOutputStream> output( + output_directory->Open(filename)); + io::Printer printer(output.get(), '$'); + + printer.Print( + "// Generated by the protocol buffer compiler. DO NOT EDIT!\n"); + if (!java_package.empty()) { + printer.Print( + "\n" + "package $package$;\n", + "package", java_package); + } + + GeneratorClass(descriptor, params).Generate(&printer); +} + +void FileGenerator::GenerateSiblings(const string& package_dir, + GeneratorContext* output_directory, + vector<string>* file_list) { + if (params_.java_multiple_files(file_->name())) { + for (int i = 0; i < file_->message_type_count(); i++) { + GenerateSibling<MessageGenerator>(package_dir, java_package_, + file_->message_type(i), + output_directory, file_list, params_); + } + + if (params_.java_enum_style()) { + for (int i = 0; i < file_->enum_type_count(); i++) { + GenerateSibling<EnumGenerator>(package_dir, java_package_, + file_->enum_type(i), + output_directory, file_list, params_); + } + } + } +} + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javanano/javanano_file.h b/src/google/protobuf/compiler/javanano/javanano_file.h new file mode 100644 index 00000000..217eafe2 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_file.h @@ -0,0 +1,94 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_FILE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_FILE_H__ + +#include <string> +#include <vector> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/javanano/javanano_params.h> + +namespace google { +namespace protobuf { + class FileDescriptor; // descriptor.h + namespace io { + class Printer; // printer.h + } + namespace compiler { + class GeneratorContext; // code_generator.h + } +} + +namespace protobuf { +namespace compiler { +namespace javanano { + +class FileGenerator { + public: + explicit FileGenerator(const FileDescriptor* file, const Params& params); + ~FileGenerator(); + + // Checks for problems that would otherwise lead to cryptic compile errors. + // Returns true if there are no problems, or writes an error description to + // the given string and returns false otherwise. + bool Validate(string* error); + + void Generate(io::Printer* printer); + + // If we aren't putting everything into one file, this will write all the + // files other than the outer file (i.e. one for each message, enum, and + // service type). + void GenerateSiblings(const string& package_dir, + GeneratorContext* output_directory, + vector<string>* file_list); + + const string& java_package() { return java_package_; } + const string& classname() { return classname_; } + + private: + const FileDescriptor* file_; + const Params& params_; + string java_package_; + string classname_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(FileGenerator); +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_FILE_H__ diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc new file mode 100644 index 00000000..b5fbcd5f --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc @@ -0,0 +1,219 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <google/protobuf/compiler/javanano/javanano_params.h> +#include <google/protobuf/compiler/javanano/javanano_generator.h> +#include <google/protobuf/compiler/javanano/javanano_file.h> +#include <google/protobuf/compiler/javanano/javanano_helpers.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +namespace { + +string TrimString(const string& s) { + string::size_type start = s.find_first_not_of(" \n\r\t"); + if (start == string::npos) { + return ""; + } + string::size_type end = s.find_last_not_of(" \n\r\t") + 1; + return s.substr(start, end - start); +} + +} // namespace + +void UpdateParamsRecursively(Params& params, + const FileDescriptor* file) { + // Add any parameters for this file + if (file->options().has_java_outer_classname()) { + params.set_java_outer_classname( + file->name(), file->options().java_outer_classname()); + } + if (file->options().has_java_package()) { + params.set_java_package( + file->name(), file->options().java_package()); + } + if (file->options().has_java_multiple_files()) { + params.set_java_multiple_files( + file->name(), file->options().java_multiple_files()); + } + + // Loop through all dependent files recursively + // adding dep + for (int i = 0; i < file->dependency_count(); i++) { + UpdateParamsRecursively(params, file->dependency(i)); + } +} + +JavaNanoGenerator::JavaNanoGenerator() {} +JavaNanoGenerator::~JavaNanoGenerator() {} + +bool JavaNanoGenerator::Generate(const FileDescriptor* file, + const string& parameter, + GeneratorContext* output_directory, + string* error) const { + vector<pair<string, string> > options; + + ParseGeneratorParameter(parameter, &options); + + // ----------------------------------------------------------------- + // parse generator options + + // Name a file where we will write a list of generated file names, one + // per line. + string output_list_file; + Params params(file->name()); + + // Update per file params + UpdateParamsRecursively(params, file); + + // Replace any existing options with ones from command line + for (int i = 0; i < options.size(); i++) { + string option_name = TrimString(options[i].first); + string option_value = TrimString(options[i].second); + if (option_name == "output_list_file") { + output_list_file = option_value; + } else if (option_name == "java_package") { + vector<string> parts; + SplitStringUsing(option_value, "|", &parts); + if (parts.size() != 2) { + *error = "Bad java_package, expecting filename|PackageName found '" + + option_value + "'"; + return false; + } + params.set_java_package(parts[0], parts[1]); + } else if (option_name == "java_outer_classname") { + vector<string> parts; + SplitStringUsing(option_value, "|", &parts); + if (parts.size() != 2) { + *error = "Bad java_outer_classname, " + "expecting filename|ClassName found '" + + option_value + "'"; + return false; + } + params.set_java_outer_classname(parts[0], parts[1]); + } else if (option_name == "store_unknown_fields") { + params.set_store_unknown_fields(option_value == "true"); + } else if (option_name == "java_multiple_files") { + params.set_override_java_multiple_files(option_value == "true"); + } else if (option_name == "java_nano_generate_has") { + params.set_generate_has(option_value == "true"); + } else if (option_name == "enum_style") { + params.set_java_enum_style(option_value == "java"); + } else if (option_name == "optional_field_style") { + params.set_optional_field_accessors(option_value == "accessors"); + params.set_use_reference_types_for_primitives(option_value == "reftypes" + || option_value == "reftypes_compat_mode"); + params.set_reftypes_primitive_enums( + option_value == "reftypes_compat_mode"); + if (option_value == "reftypes_compat_mode") { + params.set_generate_clear(false); + } + } else if (option_name == "generate_equals") { + params.set_generate_equals(option_value == "true"); + } else if (option_name == "ignore_services") { + params.set_ignore_services(option_value == "true"); + } else if (option_name == "parcelable_messages") { + params.set_parcelable_messages(option_value == "true"); + } else { + *error = "Ignore unknown javanano generator option: " + option_name; + } + } + + // Check illegal parameter combinations + // Note: the enum-like optional_field_style generator param ensures + // that we can never have illegal combinations of field styles + // (e.g. reftypes and accessors can't be on at the same time). + if (params.generate_has() + && (params.optional_field_accessors() + || params.use_reference_types_for_primitives())) { + error->assign("java_nano_generate_has=true cannot be used in conjunction" + " with optional_field_style=accessors or optional_field_style=reftypes"); + return false; + } + + // ----------------------------------------------------------------- + + FileGenerator file_generator(file, params); + if (!file_generator.Validate(error)) { + return false; + } + + string package_dir = + StringReplace(file_generator.java_package(), ".", "/", true); + if (!package_dir.empty()) package_dir += "/"; + + vector<string> all_files; + + if (IsOuterClassNeeded(params, file)) { + string java_filename = package_dir; + java_filename += file_generator.classname(); + java_filename += ".java"; + all_files.push_back(java_filename); + + // Generate main java file. + scoped_ptr<io::ZeroCopyOutputStream> output( + output_directory->Open(java_filename)); + io::Printer printer(output.get(), '$'); + file_generator.Generate(&printer); + } + + // Generate sibling files. + file_generator.GenerateSiblings(package_dir, output_directory, &all_files); + + // Generate output list if requested. + if (!output_list_file.empty()) { + // Generate output list. This is just a simple text file placed in a + // deterministic location which lists the .java files being generated. + scoped_ptr<io::ZeroCopyOutputStream> srclist_raw_output( + output_directory->Open(output_list_file)); + io::Printer srclist_printer(srclist_raw_output.get(), '$'); + for (int i = 0; i < all_files.size(); i++) { + srclist_printer.Print("$filename$\n", "filename", all_files[i]); + } + } + + return true; +} + +} // namespace java +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.h b/src/google/protobuf/compiler/javanano/javanano_generator.h new file mode 100644 index 00000000..6f9f7f2a --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_generator.h @@ -0,0 +1,72 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. +// +// Generates Java nano code for a given .proto file. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_NANO_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_NANO_GENERATOR_H__ + +#include <string> +#include <google/protobuf/compiler/code_generator.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +// CodeGenerator implementation which generates Java nano code. If you create your +// own protocol compiler binary and you want it to support Java output for the +// nano runtime, you can do so by registering an instance of this CodeGenerator with +// the CommandLineInterface in your main() function. +class LIBPROTOC_EXPORT JavaNanoGenerator : public CodeGenerator { + public: + JavaNanoGenerator(); + ~JavaNanoGenerator(); + + // implements CodeGenerator ---------------------------------------- + bool Generate(const FileDescriptor* file, + const string& parameter, + GeneratorContext* output_directory, + string* error) const; + + private: + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(JavaNanoGenerator); +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_NANO_GENERATOR_H__ diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.cc b/src/google/protobuf/compiler/javanano/javanano_helpers.cc new file mode 100644 index 00000000..2149418a --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_helpers.cc @@ -0,0 +1,566 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <limits> +#include <vector> + +#include <google/protobuf/compiler/javanano/javanano_helpers.h> +#include <google/protobuf/compiler/javanano/javanano_params.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/stubs/hash.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/substitute.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +const char kThickSeparator[] = + "// ===================================================================\n"; +const char kThinSeparator[] = + "// -------------------------------------------------------------------\n"; + +class RenameKeywords { + private: + hash_set<string> java_keywords_set_; + + public: + RenameKeywords() { + static const char* kJavaKeywordsList[] = { + // Reserved Java Keywords + "abstract", "assert", "boolean", "break", "byte", "case", "catch", + "char", "class", "const", "continue", "default", "do", "double", "else", + "enum", "extends", "final", "finally", "float", "for", "goto", "if", + "implements", "import", "instanceof", "int", "interface", "long", + "native", "new", "package", "private", "protected", "public", "return", + "short", "static", "strictfp", "super", "switch", "synchronized", + "this", "throw", "throws", "transient", "try", "void", "volatile", "while", + + // Reserved Keywords for Literals + "false", "null", "true" + }; + + for (int i = 0; i < GOOGLE_ARRAYSIZE(kJavaKeywordsList); i++) { + java_keywords_set_.insert(kJavaKeywordsList[i]); + } + } + + // Used to rename the a field name if it's a java keyword. Specifically + // this is used to rename the ["name"] or ["capitalized_name"] field params. + // (http://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html) + string RenameJavaKeywordsImpl(const string& input) { + string result = input; + + if (java_keywords_set_.find(result) != java_keywords_set_.end()) { + result += "_"; + } + + return result; + } + +}; + +static RenameKeywords sRenameKeywords; + +namespace { + +const char* kDefaultPackage = ""; + +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) { + return field->message_type()->name(); + } else { + return field->name(); + } +} + +string UnderscoresToCamelCaseImpl(const string& input, bool cap_next_letter) { + string result; + // Note: I distrust ctype.h due to locales. + for (int i = 0; i < input.size(); i++) { + if ('a' <= input[i] && input[i] <= 'z') { + if (cap_next_letter) { + result += input[i] + ('A' - 'a'); + } else { + result += input[i]; + } + cap_next_letter = false; + } else if ('A' <= input[i] && input[i] <= 'Z') { + if (i == 0 && !cap_next_letter) { + // Force first letter to lower-case unless explicitly told to + // capitalize it. + result += input[i] + ('a' - 'A'); + } else { + // Capital letters after the first are left as-is. + result += input[i]; + } + cap_next_letter = false; + } else if ('0' <= input[i] && input[i] <= '9') { + result += input[i]; + cap_next_letter = true; + } else { + cap_next_letter = true; + } + } + return result; +} + +} // namespace + +string UnderscoresToCamelCase(const FieldDescriptor* field) { + return UnderscoresToCamelCaseImpl(FieldName(field), false); +} + +string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field) { + return UnderscoresToCamelCaseImpl(FieldName(field), true); +} + +string UnderscoresToCamelCase(const MethodDescriptor* method) { + return UnderscoresToCamelCaseImpl(method->name(), false); +} + +string RenameJavaKeywords(const string& input) { + return sRenameKeywords.RenameJavaKeywordsImpl(input); +} + +string StripProto(const string& filename) { + if (HasSuffixString(filename, ".protodevel")) { + return StripSuffixString(filename, ".protodevel"); + } else { + return StripSuffixString(filename, ".proto"); + } +} + +string FileClassName(const Params& params, const FileDescriptor* file) { + if (params.has_java_outer_classname(file->name())) { + return params.java_outer_classname(file->name()); + } else { + // Use the filename itself with underscores removed + // and a CamelCase style name. + string basename; + string::size_type last_slash = file->name().find_last_of('/'); + if (last_slash == string::npos) { + basename = file->name(); + } else { + basename = file->name().substr(last_slash + 1); + } + return UnderscoresToCamelCaseImpl(StripProto(basename), true); + } +} + +string FileJavaPackage(const Params& params, const FileDescriptor* file) { + if (params.has_java_package(file->name())) { + return params.java_package(file->name()); + } else { + string result = kDefaultPackage; + if (!file->package().empty()) { + if (!result.empty()) result += '.'; + result += file->package(); + } + return result; + } +} + +bool IsOuterClassNeeded(const Params& params, const FileDescriptor* file) { + // If java_multiple_files is false, the outer class is always needed. + if (!params.java_multiple_files(file->name())) { + return true; + } + + // File-scope extensions need the outer class as the scope. + if (file->extension_count() != 0) { + return true; + } + + // If container interfaces are not generated, file-scope enums need the + // outer class as the scope. + if (file->enum_type_count() != 0 && !params.java_enum_style()) { + return true; + } + + return false; +} + +string ToJavaName(const Params& params, const string& name, bool is_class, + const Descriptor* parent, const FileDescriptor* file) { + string result; + if (parent != NULL) { + result.append(ClassName(params, parent)); + } else if (is_class && params.java_multiple_files(file->name())) { + result.append(FileJavaPackage(params, file)); + } else { + result.append(ClassName(params, file)); + } + if (!result.empty()) result.append(1, '.'); + result.append(RenameJavaKeywords(name)); + return result; +} + +string ClassName(const Params& params, const FileDescriptor* descriptor) { + string result = FileJavaPackage(params, descriptor); + if (!result.empty()) result += '.'; + result += FileClassName(params, descriptor); + return result; +} + +string ClassName(const Params& params, const EnumDescriptor* descriptor) { + const Descriptor* parent = descriptor->containing_type(); + // When using Java enum style, an enum's class name contains the enum name. + // Use the standard ToJavaName translation. + if (params.java_enum_style()) { + return ToJavaName(params, descriptor->name(), true, parent, + descriptor->file()); + } + // Otherwise the enum members are accessed from the enclosing class. + if (parent != NULL) { + return ClassName(params, parent); + } else { + return ClassName(params, descriptor->file()); + } +} + +string FieldConstantName(const FieldDescriptor *field) { + string name = field->name() + "_FIELD_NUMBER"; + UpperString(&name); + return name; +} + +string FieldDefaultConstantName(const FieldDescriptor *field) { + return "_" + RenameJavaKeywords(UnderscoresToCamelCase(field)) + "Default"; +} + +void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field) { + // We don't want to print group bodies so we cut off after the first line + // (the second line for extensions). + string def = field->DebugString(); + string::size_type first_line_end = def.find_first_of('\n'); + printer->Print("// $def$\n", + "def", def.substr(0, first_line_end)); + if (field->is_extension()) { + string::size_type second_line_start = first_line_end + 1; + string::size_type second_line_length = + def.find('\n', second_line_start) - second_line_start; + printer->Print("// $def$\n", + "def", def.substr(second_line_start, second_line_length)); + } +} + +JavaType GetJavaType(FieldDescriptor::Type field_type) { + switch (field_type) { + case FieldDescriptor::TYPE_INT32: + case FieldDescriptor::TYPE_UINT32: + case FieldDescriptor::TYPE_SINT32: + case FieldDescriptor::TYPE_FIXED32: + case FieldDescriptor::TYPE_SFIXED32: + return JAVATYPE_INT; + + case FieldDescriptor::TYPE_INT64: + case FieldDescriptor::TYPE_UINT64: + case FieldDescriptor::TYPE_SINT64: + case FieldDescriptor::TYPE_FIXED64: + case FieldDescriptor::TYPE_SFIXED64: + return JAVATYPE_LONG; + + case FieldDescriptor::TYPE_FLOAT: + return JAVATYPE_FLOAT; + + case FieldDescriptor::TYPE_DOUBLE: + return JAVATYPE_DOUBLE; + + case FieldDescriptor::TYPE_BOOL: + return JAVATYPE_BOOLEAN; + + case FieldDescriptor::TYPE_STRING: + return JAVATYPE_STRING; + + case FieldDescriptor::TYPE_BYTES: + return JAVATYPE_BYTES; + + case FieldDescriptor::TYPE_ENUM: + return JAVATYPE_ENUM; + + case FieldDescriptor::TYPE_GROUP: + case FieldDescriptor::TYPE_MESSAGE: + return JAVATYPE_MESSAGE; + + // No default because we want the compiler to complain if any new + // types are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return JAVATYPE_INT; +} + +string PrimitiveTypeName(JavaType type) { + switch (type) { + case JAVATYPE_INT : return "int"; + case JAVATYPE_LONG : return "long"; + case JAVATYPE_FLOAT : return "float"; + case JAVATYPE_DOUBLE : return "double"; + case JAVATYPE_BOOLEAN: return "boolean"; + case JAVATYPE_STRING : return "java.lang.String"; + case JAVATYPE_BYTES : return "byte[]"; + case JAVATYPE_ENUM : return "int"; + case JAVATYPE_MESSAGE: return ""; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return ""; +} + +string BoxedPrimitiveTypeName(JavaType type) { + switch (type) { + case JAVATYPE_INT : return "java.lang.Integer"; + case JAVATYPE_LONG : return "java.lang.Long"; + case JAVATYPE_FLOAT : return "java.lang.Float"; + case JAVATYPE_DOUBLE : return "java.lang.Double"; + case JAVATYPE_BOOLEAN: return "java.lang.Boolean"; + case JAVATYPE_STRING : return "java.lang.String"; + case JAVATYPE_BYTES : return "byte[]"; + case JAVATYPE_ENUM : return "java.lang.Integer"; + case JAVATYPE_MESSAGE: return ""; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return ""; +} + +string EmptyArrayName(const Params& params, const FieldDescriptor* field) { + switch (GetJavaType(field)) { + case JAVATYPE_INT : return "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY"; + case JAVATYPE_LONG : return "com.google.protobuf.nano.WireFormatNano.EMPTY_LONG_ARRAY"; + case JAVATYPE_FLOAT : return "com.google.protobuf.nano.WireFormatNano.EMPTY_FLOAT_ARRAY"; + case JAVATYPE_DOUBLE : return "com.google.protobuf.nano.WireFormatNano.EMPTY_DOUBLE_ARRAY"; + case JAVATYPE_BOOLEAN: return "com.google.protobuf.nano.WireFormatNano.EMPTY_BOOLEAN_ARRAY"; + case JAVATYPE_STRING : return "com.google.protobuf.nano.WireFormatNano.EMPTY_STRING_ARRAY"; + case JAVATYPE_BYTES : return "com.google.protobuf.nano.WireFormatNano.EMPTY_BYTES_ARRAY"; + case JAVATYPE_ENUM : return "com.google.protobuf.nano.WireFormatNano.EMPTY_INT_ARRAY"; + case JAVATYPE_MESSAGE: return ClassName(params, field->message_type()) + ".EMPTY_ARRAY"; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return ""; +} + +string DefaultValue(const Params& params, const FieldDescriptor* field) { + if (field->label() == FieldDescriptor::LABEL_REPEATED) { + return EmptyArrayName(params, field); + } + + if (params.use_reference_types_for_primitives()) { + if (params.reftypes_primitive_enums() + && field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + return "Integer.MIN_VALUE"; + } + return "null"; + } + + // Switch on cpp_type since we need to know which default_value_* method + // of FieldDescriptor to call. + switch (field->cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + return SimpleItoa(field->default_value_int32()); + case FieldDescriptor::CPPTYPE_UINT32: + // Need to print as a signed int since Java has no unsigned. + return SimpleItoa(static_cast<int32>(field->default_value_uint32())); + case FieldDescriptor::CPPTYPE_INT64: + return SimpleItoa(field->default_value_int64()) + "L"; + case FieldDescriptor::CPPTYPE_UINT64: + return SimpleItoa(static_cast<int64>(field->default_value_uint64())) + + "L"; + case FieldDescriptor::CPPTYPE_DOUBLE: { + double value = field->default_value_double(); + if (value == numeric_limits<double>::infinity()) { + return "Double.POSITIVE_INFINITY"; + } else if (value == -numeric_limits<double>::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<float>::infinity()) { + return "Float.POSITIVE_INFINITY"; + } else if (value == -numeric_limits<float>::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->default_value_string().empty()) { + // Point it to the static final in the generated code. + return FieldDefaultConstantName(field); + } else { + if (field->type() == FieldDescriptor::TYPE_BYTES) { + return "com.google.protobuf.nano.WireFormatNano.EMPTY_BYTES"; + } else { + return "\"\""; + } + } + + case FieldDescriptor::CPPTYPE_ENUM: + return ClassName(params, field->enum_type()) + "." + + RenameJavaKeywords(field->default_value_enum()->name()); + + case FieldDescriptor::CPPTYPE_MESSAGE: + return "null"; + + // No default because we want the compiler to complain if any new + // types are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return ""; +} + + +static const char* kBitMasks[] = { + "0x00000001", + "0x00000002", + "0x00000004", + "0x00000008", + "0x00000010", + "0x00000020", + "0x00000040", + "0x00000080", + + "0x00000100", + "0x00000200", + "0x00000400", + "0x00000800", + "0x00001000", + "0x00002000", + "0x00004000", + "0x00008000", + + "0x00010000", + "0x00020000", + "0x00040000", + "0x00080000", + "0x00100000", + "0x00200000", + "0x00400000", + "0x00800000", + + "0x01000000", + "0x02000000", + "0x04000000", + "0x08000000", + "0x10000000", + "0x20000000", + "0x40000000", + "0x80000000", +}; + +string GetBitFieldName(int index) { + string var_name = "bitField"; + var_name += SimpleItoa(index); + var_name += "_"; + return var_name; +} + +string GetBitFieldNameForBit(int bit_index) { + return GetBitFieldName(bit_index / 32); +} + +string GenerateGetBit(int bit_index) { + string var_name = GetBitFieldNameForBit(bit_index); + int bit_in_var_index = bit_index % 32; + + string mask = kBitMasks[bit_in_var_index]; + string result = "((" + var_name + " & " + mask + ") != 0)"; + return result; +} + +string GenerateSetBit(int bit_index) { + string var_name = GetBitFieldNameForBit(bit_index); + int bit_in_var_index = bit_index % 32; + + string mask = kBitMasks[bit_in_var_index]; + string result = var_name + " |= " + mask; + return result; +} + +string GenerateClearBit(int bit_index) { + string var_name = GetBitFieldNameForBit(bit_index); + int bit_in_var_index = bit_index % 32; + + string mask = kBitMasks[bit_in_var_index]; + string result = var_name + " = (" + var_name + " & ~" + mask + ")"; + return result; +} + +string GenerateDifferentBit(int bit_index) { + string var_name = GetBitFieldNameForBit(bit_index); + int bit_in_var_index = bit_index % 32; + + string mask = kBitMasks[bit_in_var_index]; + string result = "((" + var_name + " & " + mask + + ") != (other." + var_name + " & " + mask + "))"; + return result; +} + +void SetBitOperationVariables(const string name, + int bitIndex, map<string, string>* variables) { + (*variables)["get_" + name] = GenerateGetBit(bitIndex); + (*variables)["set_" + name] = GenerateSetBit(bitIndex); + (*variables)["clear_" + name] = GenerateClearBit(bitIndex); + (*variables)["different_" + name] = GenerateDifferentBit(bitIndex); +} + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.h b/src/google/protobuf/compiler/javanano/javanano_helpers.h new file mode 100644 index 00000000..29310743 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_helpers.h @@ -0,0 +1,189 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_HELPERS_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_HELPERS_H__ + +#include <string> +#include <google/protobuf/compiler/javanano/javanano_params.h> +#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/io/printer.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +// Commonly-used separator comments. Thick is a line of '=', thin is a line +// of '-'. +extern const char kThickSeparator[]; +extern const char kThinSeparator[]; + +// Converts the field's name to camel-case, e.g. "foo_bar_baz" becomes +// "fooBarBaz" or "FooBarBaz", respectively. +string UnderscoresToCamelCase(const FieldDescriptor* field); +string UnderscoresToCapitalizedCamelCase(const FieldDescriptor* field); + +// Appends an "_" to the end of a field where the name is a reserved java +// keyword. For example int32 public = 1 will generate int public_. +string RenameJavaKeywords(const string& input); + +// Similar, but for method names. (Typically, this merely has the effect +// of lower-casing the first letter of the name.) +string UnderscoresToCamelCase(const MethodDescriptor* method); + +// Strips ".proto" or ".protodevel" from the end of a filename. +string StripProto(const string& filename); + +// Gets the unqualified class name for the file. Each .proto file becomes a +// single Java class, with all its contents nested in that class. +string FileClassName(const Params& params, const FileDescriptor* file); + +// Returns the file's Java package name. +string FileJavaPackage(const Params& params, const FileDescriptor* file); + +// Returns whether the Java outer class is needed, i.e. whether the option +// java_multiple_files is false, or the proto file contains any file-scope +// enums/extensions. +bool IsOuterClassNeeded(const Params& params, const FileDescriptor* file); + +// Converts the given simple name of a proto entity to its fully-qualified name +// in the Java namespace, given that it is in the given file enclosed in the +// given parent message (or NULL for file-scope entities). Whether the file's +// outer class name should be included in the return value depends on factors +// inferrable from the given arguments, including is_class which indicates +// whether the entity translates to a Java class. +string ToJavaName(const Params& params, const string& name, bool is_class, + const Descriptor* parent, const FileDescriptor* file); + +// These return the fully-qualified class name corresponding to the given +// descriptor. +inline string ClassName(const Params& params, const Descriptor* descriptor) { + return ToJavaName(params, descriptor->name(), true, + descriptor->containing_type(), descriptor->file()); +} +string ClassName(const Params& params, const EnumDescriptor* descriptor); +inline string ClassName(const Params& params, + const ServiceDescriptor* descriptor) { + return ToJavaName(params, descriptor->name(), true, NULL, descriptor->file()); +} +inline string ExtensionIdentifierName(const Params& params, + const FieldDescriptor* descriptor) { + return ToJavaName(params, descriptor->name(), false, + descriptor->extension_scope(), descriptor->file()); +} +string ClassName(const Params& params, const FileDescriptor* descriptor); + +// Get the unqualified name that should be used for a field's field +// number constant. +string FieldConstantName(const FieldDescriptor *field); + +string FieldDefaultConstantName(const FieldDescriptor *field); + +// Print the field's proto-syntax definition as a comment. +void PrintFieldComment(io::Printer* printer, const FieldDescriptor* field); + +enum JavaType { + JAVATYPE_INT, + JAVATYPE_LONG, + JAVATYPE_FLOAT, + JAVATYPE_DOUBLE, + JAVATYPE_BOOLEAN, + JAVATYPE_STRING, + JAVATYPE_BYTES, + JAVATYPE_ENUM, + JAVATYPE_MESSAGE +}; + +JavaType GetJavaType(FieldDescriptor::Type field_type); + +inline JavaType GetJavaType(const FieldDescriptor* field) { + return GetJavaType(field->type()); +} + +string PrimitiveTypeName(JavaType type); + +// 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 +// types. +string BoxedPrimitiveTypeName(JavaType type); + +string EmptyArrayName(const Params& params, const FieldDescriptor* field); + +string DefaultValue(const Params& params, const FieldDescriptor* field); + + +// Methods for shared bitfields. + +// Gets the name of the shared bitfield for the given field index. +string GetBitFieldName(int index); + +// Gets the name of the shared bitfield for the given bit index. +// Effectively, GetBitFieldName(bit_index / 32) +string GetBitFieldNameForBit(int bit_index); + +// Generates the java code for the expression that returns whether the bit at +// the given bit index is set. +// Example: "((bitField1_ & 0x04000000) != 0)" +string GenerateGetBit(int bit_index); + +// Generates the java code for the expression that sets the bit at the given +// bit index. +// Example: "bitField1_ |= 0x04000000" +string GenerateSetBit(int bit_index); + +// Generates the java code for the expression that clears the bit at the given +// bit index. +// Example: "bitField1_ = (bitField1_ & ~0x04000000)" +string GenerateClearBit(int bit_index); + +// Generates the java code for the expression that returns whether the bit at +// the given bit index contains different values in the current object and +// another object accessible via the variable 'other'. +// Example: "((bitField1_ & 0x04000000) != (other.bitField1_ & 0x04000000))" +string GenerateDifferentBit(int bit_index); + +// Sets the 'get_*', 'set_*', 'clear_*' and 'different_*' variables, where * is +// the given name of the bit, to the appropriate Java expressions for the given +// bit index. +void SetBitOperationVariables(const string name, + int bitIndex, map<string, string>* variables); + +} // namespace javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_HELPERS_H__ diff --git a/src/google/protobuf/compiler/javanano/javanano_message.cc b/src/google/protobuf/compiler/javanano/javanano_message.cc new file mode 100644 index 00000000..7c52ca31 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_message.cc @@ -0,0 +1,555 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <algorithm> +#include <google/protobuf/stubs/hash.h> +#include <google/protobuf/compiler/javanano/javanano_message.h> +#include <google/protobuf/compiler/javanano/javanano_enum.h> +#include <google/protobuf/compiler/javanano/javanano_extension.h> +#include <google/protobuf/compiler/javanano/javanano_helpers.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/coded_stream.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/descriptor.pb.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { + +struct FieldOrderingByNumber { + inline bool operator()(const FieldDescriptor* a, + const FieldDescriptor* b) const { + return a->number() < b->number(); + } +}; + +// Sort the fields of the given Descriptor by number into a new[]'d array +// and return it. +const FieldDescriptor** SortFieldsByNumber(const Descriptor* descriptor) { + const FieldDescriptor** fields = + new const FieldDescriptor*[descriptor->field_count()]; + for (int i = 0; i < descriptor->field_count(); i++) { + fields[i] = descriptor->field(i); + } + sort(fields, fields + descriptor->field_count(), + FieldOrderingByNumber()); + return fields; +} + +} // namespace + +// =================================================================== + +MessageGenerator::MessageGenerator(const Descriptor* descriptor, const Params& params) + : params_(params), + descriptor_(descriptor), + field_generators_(descriptor, params) { +} + +MessageGenerator::~MessageGenerator() {} + +void MessageGenerator::GenerateStaticVariables(io::Printer* printer) { + // Generate static members for all nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // TODO(kenton): Reuse MessageGenerator objects? + MessageGenerator(descriptor_->nested_type(i), params_) + .GenerateStaticVariables(printer); + } +} + +void MessageGenerator::GenerateStaticVariableInitializers( + io::Printer* printer) { + // Generate static member initializers for all nested types. + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + // TODO(kenton): Reuse MessageGenerator objects? + MessageGenerator(descriptor_->nested_type(i), params_) + .GenerateStaticVariableInitializers(printer); + } +} + +void MessageGenerator::Generate(io::Printer* printer) { + if (!params_.store_unknown_fields() && + (descriptor_->extension_count() != 0 || descriptor_->extension_range_count() != 0)) { + GOOGLE_LOG(FATAL) << "Extensions are only supported in NANO_RUNTIME if the " + "'store_unknown_fields' generator option is 'true'\n"; + } + + const string& file_name = descriptor_->file()->name(); + bool is_own_file = + params_.java_multiple_files(file_name) + && descriptor_->containing_type() == NULL; + + if (is_own_file) { + // Note: constants (from enums and fields requiring stored defaults, emitted in the loop below) + // may have the same names as constants in the nested classes. This causes Java warnings, but + // is not fatal, so we suppress those warnings here in the top-most class declaration. + printer->Print( + "\n" + "@SuppressWarnings(\"hiding\")\n" + "public final class $classname$ extends\n", + "classname", descriptor_->name()); + } else { + printer->Print( + "\n" + "public static final class $classname$ extends\n", + "classname", descriptor_->name()); + } + if (params_.store_unknown_fields() && params_.parcelable_messages()) { + printer->Print( + " com.google.protobuf.nano.android.ParcelableExtendableMessageNano<$classname$> {\n", + "classname", descriptor_->name()); + } else if (params_.store_unknown_fields()) { + printer->Print( + " com.google.protobuf.nano.ExtendableMessageNano<$classname$> {\n", + "classname", descriptor_->name()); + } else if (params_.parcelable_messages()) { + printer->Print( + " com.google.protobuf.nano.android.ParcelableMessageNano {\n"); + } else { + printer->Print( + " com.google.protobuf.nano.MessageNano {\n"); + } + printer->Indent(); + + // Nested types and extensions + for (int i = 0; i < descriptor_->extension_count(); i++) { + ExtensionGenerator(descriptor_->extension(i), params_).Generate(printer); + } + + for (int i = 0; i < descriptor_->enum_type_count(); i++) { + EnumGenerator(descriptor_->enum_type(i), params_).Generate(printer); + } + + for (int i = 0; i < descriptor_->nested_type_count(); i++) { + MessageGenerator(descriptor_->nested_type(i), params_).Generate(printer); + } + + // Lazy initialization of otherwise static final fields can help prevent the + // class initializer from being generated. We want to prevent it because it + // stops ProGuard from inlining any methods in this class into call sites and + // therefore reducing the method count. However, extensions are best kept as + // public static final fields with initializers, so with their existence we + // won't bother with lazy initialization. + bool lazy_init = descriptor_->extension_count() == 0; + + // Empty array + if (lazy_init) { + printer->Print( + "\n" + "private static volatile $classname$[] _emptyArray;\n" + "public static $classname$[] emptyArray() {\n" + " // Lazily initializes the empty array\n" + " if (_emptyArray == null) {\n" + " synchronized (\n" + " com.google.protobuf.nano.InternalNano.LAZY_INIT_LOCK) {\n" + " if (_emptyArray == null) {\n" + " _emptyArray = new $classname$[0];\n" + " }\n" + " }\n" + " }\n" + " return _emptyArray;\n" + "}\n", + "classname", descriptor_->name()); + } else { + printer->Print( + "\n" + "private static final $classname$[] EMPTY_ARRAY = {};\n" + "public static $classname$[] emptyArray() {\n" + " return EMPTY_ARRAY;\n" + "}\n", + "classname", descriptor_->name()); + } + + // Integers for bit fields + int totalInts = (field_generators_.total_bits() + 31) / 32; + if (totalInts > 0) { + printer->Print("\n"); + for (int i = 0; i < totalInts; i++) { + printer->Print("private int $bit_field_name$;\n", + "bit_field_name", GetBitFieldName(i)); + } + } + + // Fields and maybe their default values + for (int i = 0; i < descriptor_->field_count(); i++) { + printer->Print("\n"); + PrintFieldComment(printer, descriptor_->field(i)); + field_generators_.get(descriptor_->field(i)).GenerateMembers( + printer, lazy_init); + } + + // Constructor, with lazy init code if needed + if (lazy_init && field_generators_.saved_defaults_needed()) { + printer->Print( + "\n" + "private static volatile boolean _classInitialized;\n" + "\n" + "public $classname$() {\n" + " // Lazily initializes the field defaults\n" + " if (!_classInitialized) {\n" + " synchronized (\n" + " com.google.protobuf.nano.InternalNano.LAZY_INIT_LOCK) {\n" + " if (!_classInitialized) {\n", + "classname", descriptor_->name()); + printer->Indent(); + printer->Indent(); + printer->Indent(); + printer->Indent(); + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(descriptor_->field(i)) + .GenerateInitSavedDefaultCode(printer); + } + printer->Outdent(); + printer->Outdent(); + printer->Outdent(); + printer->Outdent(); + printer->Print( + " _classInitialized = true;\n" + " }\n" + " }\n" + " }\n"); + if (params_.generate_clear()) { + printer->Print(" clear();\n"); + } + printer->Print("}\n"); + } else { + if (params_.generate_clear()) { + printer->Print( + "\n" + "public $classname$() {\n" + " clear();\n" + "}\n", + "classname", descriptor_->name()); + } + } + + // Other methods in this class + + GenerateClear(printer); + + if (params_.generate_equals()) { + GenerateEquals(printer); + GenerateHashCode(printer); + } + + GenerateMessageSerializationMethods(printer); + GenerateMergeFromMethods(printer); + GenerateParseFromMethods(printer); + + printer->Outdent(); + printer->Print("}\n"); +} + +// =================================================================== + +void MessageGenerator:: +GenerateMessageSerializationMethods(io::Printer* printer) { + // Rely on the parent implementations of writeTo() and getSerializedSize() + // if there are no fields to serialize in this message. + if (descriptor_->field_count() == 0) { + return; + } + + scoped_array<const FieldDescriptor*> sorted_fields( + SortFieldsByNumber(descriptor_)); + + printer->Print( + "\n" + "@Override\n" + "public void writeTo(com.google.protobuf.nano.CodedOutputByteBufferNano output)\n" + " throws java.io.IOException {\n"); + printer->Indent(); + + // Output the fields in sorted order + for (int i = 0; i < descriptor_->field_count(); i++) { + GenerateSerializeOneField(printer, sorted_fields[i]); + } + + // The parent implementation will write any unknown fields if necessary. + printer->Print( + "super.writeTo(output);\n"); + + printer->Outdent(); + printer->Print("}\n"); + + // The parent implementation will get the serialized size for unknown + // fields if necessary. + printer->Print( + "\n" + "@Override\n" + "protected int computeSerializedSize() {\n" + " int size = super.computeSerializedSize();\n"); + printer->Indent(); + + for (int i = 0; i < descriptor_->field_count(); i++) { + field_generators_.get(sorted_fields[i]).GenerateSerializedSizeCode(printer); + } + + printer->Outdent(); + printer->Print( + " return size;\n" + "}\n"); +} + +void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) { + scoped_array<const FieldDescriptor*> sorted_fields( + SortFieldsByNumber(descriptor_)); + + printer->Print( + "\n" + "@Override\n" + "public $classname$ mergeFrom(\n" + " com.google.protobuf.nano.CodedInputByteBufferNano input)\n" + " throws java.io.IOException {\n", + "classname", descriptor_->name()); + + printer->Indent(); + + printer->Print( + "while (true) {\n"); + printer->Indent(); + + printer->Print( + "int tag = input.readTag();\n" + "switch (tag) {\n"); + printer->Indent(); + + printer->Print( + "case 0:\n" // zero signals EOF / limit reached + " return this;\n" + "default: {\n"); + + printer->Indent(); + if (params_.store_unknown_fields()) { + printer->Print( + "if (!storeUnknownField(input, tag)) {\n" + " return this;\n" + "}\n"); + } else { + printer->Print( + "if (!com.google.protobuf.nano.WireFormatNano.parseUnknownField(input, tag)) {\n" + " return this;\n" // it's an endgroup tag + "}\n"); + } + printer->Print("break;\n"); + printer->Outdent(); + printer->Print("}\n"); + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = sorted_fields[i]; + uint32 tag = WireFormatLite::MakeTag(field->number(), + WireFormat::WireTypeForFieldType(field->type())); + + printer->Print( + "case $tag$: {\n", + "tag", SimpleItoa(tag)); + printer->Indent(); + + field_generators_.get(field).GenerateMergingCode(printer); + + printer->Outdent(); + 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).GenerateMergingCodeFromPacked(printer); + + printer->Outdent(); + printer->Print( + " break;\n" + "}\n"); + } + } + + printer->Outdent(); + printer->Outdent(); + printer->Outdent(); + printer->Print( + " }\n" // switch (tag) + " }\n" // while (true) + "}\n"); +} + +void MessageGenerator:: +GenerateParseFromMethods(io::Printer* printer) { + // Note: These are separate from GenerateMessageSerializationMethods() + // because they need to be generated even for messages that are optimized + // for code size. + printer->Print( + "\n" + "public static $classname$ parseFrom(byte[] data)\n" + " throws com.google.protobuf.nano.InvalidProtocolBufferNanoException {\n" + " return com.google.protobuf.nano.MessageNano.mergeFrom(new $classname$(), data);\n" + "}\n" + "\n" + "public static $classname$ parseFrom(\n" + " com.google.protobuf.nano.CodedInputByteBufferNano input)\n" + " throws java.io.IOException {\n" + " return new $classname$().mergeFrom(input);\n" + "}\n", + "classname", descriptor_->name()); +} + +void MessageGenerator::GenerateSerializeOneField( + io::Printer* printer, const FieldDescriptor* field) { + field_generators_.get(field).GenerateSerializationCode(printer); +} + +void MessageGenerator::GenerateClear(io::Printer* printer) { + if (!params_.generate_clear()) { + return; + } + printer->Print( + "\n" + "public $classname$ clear() {\n", + "classname", descriptor_->name()); + printer->Indent(); + + // Clear bit fields. + int totalInts = (field_generators_.total_bits() + 31) / 32; + for (int i = 0; i < totalInts; i++) { + printer->Print("$bit_field_name$ = 0;\n", + "bit_field_name", GetBitFieldName(i)); + } + + // Call clear for all of the fields. + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + field_generators_.get(field).GenerateClearCode(printer); + } + + // Clear unknown fields. + if (params_.store_unknown_fields()) { + printer->Print("unknownFieldData = null;\n"); + } + + printer->Outdent(); + printer->Print( + " cachedSize = -1;\n" + " return this;\n" + "}\n"); +} + +void MessageGenerator::GenerateEquals(io::Printer* printer) { + // Don't override if there are no fields. We could generate an + // equals method that compares types, but often empty messages + // are used as namespaces. + if (descriptor_->field_count() == 0 && !params_.store_unknown_fields()) { + return; + } + + printer->Print( + "\n" + "@Override\n" + "public boolean equals(Object o) {\n"); + printer->Indent(); + printer->Print( + "if (o == this) {\n" + " return true;\n" + "}\n" + "if (!(o instanceof $classname$)) {\n" + " return false;\n" + "}\n" + "$classname$ other = ($classname$) o;\n", + "classname", descriptor_->name()); + + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + field_generators_.get(field).GenerateEqualsCode(printer); + } + + if (params_.store_unknown_fields()) { + printer->Print( + "return unknownFieldDataEquals(other);\n"); + } else { + printer->Print( + "return true;\n"); + } + + printer->Outdent(); + printer->Print("}\n"); +} + +void MessageGenerator::GenerateHashCode(io::Printer* printer) { + if (descriptor_->field_count() == 0 && !params_.store_unknown_fields()) { + return; + } + + printer->Print( + "\n" + "@Override\n" + "public int hashCode() {\n"); + printer->Indent(); + + printer->Print("int result = 17;\n"); + printer->Print("result = 31 * result + getClass().getName().hashCode();\n"); + for (int i = 0; i < descriptor_->field_count(); i++) { + const FieldDescriptor* field = descriptor_->field(i); + field_generators_.get(field).GenerateHashCodeCode(printer); + } + + if (params_.store_unknown_fields()) { + printer->Print( + "result = 31 * result + unknownFieldDataHashCode();\n"); + } + + printer->Print("return result;\n"); + + printer->Outdent(); + printer->Print("}\n"); +} + +// =================================================================== + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javanano/javanano_message.h b/src/google/protobuf/compiler/javanano/javanano_message.h new file mode 100644 index 00000000..6f25a3a0 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_message.h @@ -0,0 +1,95 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_H__ + +#include <string> +#include <google/protobuf/compiler/javanano/javanano_helpers.h> +#include <google/protobuf/compiler/javanano/javanano_field.h> +#include <google/protobuf/compiler/javanano/javanano_params.h> +#include <google/protobuf/stubs/common.h> + +namespace google { +namespace protobuf { + namespace io { + class Printer; // printer.h + } +} + +namespace protobuf { +namespace compiler { +namespace javanano { + +class MessageGenerator { + public: + explicit MessageGenerator(const Descriptor* descriptor, const Params& params); + ~MessageGenerator(); + + // All static variables have to be declared at the top-level of the file + // so that we can control initialization order, which is important for + // DescriptorProto bootstrapping to work. + void GenerateStaticVariables(io::Printer* printer); + + // Output code which initializes the static variables generated by + // GenerateStaticVariables(). + void GenerateStaticVariableInitializers(io::Printer* printer); + + // Generate the class itself. + void Generate(io::Printer* printer); + + private: + void GenerateMessageSerializationMethods(io::Printer* printer); + void GenerateMergeFromMethods(io::Printer* printer); + void GenerateParseFromMethods(io::Printer* printer); + void GenerateSerializeOneField(io::Printer* printer, + const FieldDescriptor* field); + + void GenerateClear(io::Printer* printer); + void GenerateEquals(io::Printer* printer); + void GenerateHashCode(io::Printer* printer); + + const Params& params_; + const Descriptor* descriptor_; + FieldGeneratorMap field_generators_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageGenerator); +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_H__ diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.cc b/src/google/protobuf/compiler/javanano/javanano_message_field.cc new file mode 100644 index 00000000..a46081d0 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_message_field.cc @@ -0,0 +1,259 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <map> +#include <string> + +#include <google/protobuf/compiler/javanano/javanano_message_field.h> +#include <google/protobuf/compiler/javanano/javanano_helpers.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { + +// TODO(kenton): Factor out a "SetCommonFieldVariables()" to get rid of +// repeat code between this and the other field types. +void SetMessageVariables(const Params& params, + const FieldDescriptor* descriptor, map<string, string>* variables) { + (*variables)["name"] = + RenameJavaKeywords(UnderscoresToCamelCase(descriptor)); + (*variables)["capitalized_name"] = + RenameJavaKeywords(UnderscoresToCapitalizedCamelCase(descriptor)); + (*variables)["number"] = SimpleItoa(descriptor->number()); + (*variables)["type"] = ClassName(params, descriptor->message_type()); + (*variables)["group_or_message"] = + (descriptor->type() == FieldDescriptor::TYPE_GROUP) ? + "Group" : "Message"; + (*variables)["message_name"] = descriptor->containing_type()->name(); + //(*variables)["message_type"] = descriptor->message_type()->name(); + (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); +} + +} // namespace + +// =================================================================== + +MessageFieldGenerator:: +MessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params) + : FieldGenerator(params), descriptor_(descriptor) { + SetMessageVariables(params, descriptor, &variables_); +} + +MessageFieldGenerator::~MessageFieldGenerator() {} + +void MessageFieldGenerator:: +GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const { + printer->Print(variables_, + "public $type$ $name$;\n"); +} + +void MessageFieldGenerator:: +GenerateClearCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$ = null;\n"); +} + +void MessageFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "if (this.$name$ == null) {\n" + " this.$name$ = new $type$();\n" + "}\n"); + + if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { + printer->Print(variables_, + "input.readGroup(this.$name$, $number$);\n"); + } else { + printer->Print(variables_, + "input.readMessage(this.$name$);\n"); + } +} + +void MessageFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if (this.$name$ != null) {\n" + " output.write$group_or_message$($number$, this.$name$);\n" + "}\n"); +} + +void MessageFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if (this.$name$ != null) {\n" + " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .compute$group_or_message$Size($number$, this.$name$);\n" + "}\n"); +} + +void MessageFieldGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + printer->Print(variables_, + "if (this.$name$ == null) { \n" + " if (other.$name$ != null) {\n" + " return false;\n" + " }\n" + "} else {\n" + " if (!this.$name$.equals(other.$name$)) {\n" + " return false;\n" + " }\n" + "}\n"); +} + +void MessageFieldGenerator:: +GenerateHashCodeCode(io::Printer* printer) const { + printer->Print(variables_, + "result = 31 * result +\n" + " (this.$name$ == null ? 0 : this.$name$.hashCode());\n"); +} + +// =================================================================== + +RepeatedMessageFieldGenerator:: +RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, const Params& params) + : FieldGenerator(params), descriptor_(descriptor) { + SetMessageVariables(params, descriptor, &variables_); +} + +RepeatedMessageFieldGenerator::~RepeatedMessageFieldGenerator() {} + +void RepeatedMessageFieldGenerator:: +GenerateMembers(io::Printer* printer, bool /* unused lazy_init */) const { + printer->Print(variables_, + "public $type$[] $name$;\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateClearCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$ = $type$.emptyArray();\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + // First, figure out the length of the array, then parse. + printer->Print(variables_, + "int arrayLength = com.google.protobuf.nano.WireFormatNano\n" + " .getRepeatedFieldArrayLength(input, $tag$);\n" + "int i = this.$name$ == null ? 0 : this.$name$.length;\n" + "$type$[] newArray =\n" + " new $type$[i + arrayLength];\n" + "if (i != 0) {\n" + " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n" + "}\n" + "for (; i < newArray.length - 1; i++) {\n" + " newArray[i] = new $type$();\n"); + + if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { + printer->Print(variables_, + " input.readGroup(newArray[i], $number$);\n"); + } else { + printer->Print(variables_, + " input.readMessage(newArray[i]);\n"); + } + + printer->Print(variables_, + " input.readTag();\n" + "}\n" + "// Last one without readTag.\n" + "newArray[i] = new $type$();\n"); + + if (descriptor_->type() == FieldDescriptor::TYPE_GROUP) { + printer->Print(variables_, + "input.readGroup(newArray[i], $number$);\n"); + } else { + printer->Print(variables_, + "input.readMessage(newArray[i]);\n"); + } + + printer->Print(variables_, + "this.$name$ = newArray;\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if (this.$name$ != null && this.$name$.length > 0) {\n" + " for (int i = 0; i < this.$name$.length; i++) {\n" + " $type$ element = this.$name$[i];\n" + " if (element != null) {\n" + " output.write$group_or_message$($number$, element);\n" + " }\n" + " }\n" + "}\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if (this.$name$ != null && this.$name$.length > 0) {\n" + " for (int i = 0; i < this.$name$.length; i++) {\n" + " $type$ element = this.$name$[i];\n" + " if (element != null) {\n" + " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .compute$group_or_message$Size($number$, element);\n" + " }\n" + " }\n" + "}\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + printer->Print(variables_, + "if (!com.google.protobuf.nano.InternalNano.equals(\n" + " this.$name$, other.$name$)) {\n" + " return false;\n" + "}\n"); +} + +void RepeatedMessageFieldGenerator:: +GenerateHashCodeCode(io::Printer* printer) const { + printer->Print(variables_, + "result = 31 * result\n" + " + com.google.protobuf.nano.InternalNano.hashCode(this.$name$);\n"); +} + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.h b/src/google/protobuf/compiler/javanano/javanano_message_field.h new file mode 100644 index 00000000..5d35fd24 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_message_field.h @@ -0,0 +1,96 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_FIELD_H__ + +#include <map> +#include <string> +#include <google/protobuf/compiler/javanano/javanano_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +class MessageFieldGenerator : public FieldGenerator { + public: + explicit MessageFieldGenerator( + const FieldDescriptor* descriptor, const Params& params); + ~MessageFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GenerateMembers(io::Printer* printer, bool lazy_init) const; + void GenerateClearCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCodeCode(io::Printer* printer) const; + + private: + const FieldDescriptor* descriptor_; + map<string, string> variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MessageFieldGenerator); +}; + +class RepeatedMessageFieldGenerator : public FieldGenerator { + public: + explicit RepeatedMessageFieldGenerator(const FieldDescriptor* descriptor, + const Params& params); + ~RepeatedMessageFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GenerateMembers(io::Printer* printer, bool lazy_init) const; + void GenerateClearCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCodeCode(io::Printer* printer) const; + + private: + const FieldDescriptor* descriptor_; + map<string, string> variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedMessageFieldGenerator); +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_MESSAGE_FIELD_H__ diff --git a/src/google/protobuf/compiler/javanano/javanano_params.h b/src/google/protobuf/compiler/javanano/javanano_params.h new file mode 100644 index 00000000..4691f360 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_params.h @@ -0,0 +1,240 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2010 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: wink@google.com (Wink Saville) + +#ifndef PROTOBUF_COMPILER_JAVANANO_JAVANANO_PARAMS_H_ +#define PROTOBUF_COMPILER_JAVANANO_JAVANANO_PARAMS_H_ + +#include <map> +#include <set> +#include <google/protobuf/stubs/strutil.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +enum eMultipleFiles { JAVANANO_MUL_UNSET, JAVANANO_MUL_FALSE, JAVANANO_MUL_TRUE }; + +// Parameters for used by the generators +class Params { + public: + typedef map<string, string> NameMap; + typedef set<string> NameSet; + private: + string empty_; + string base_name_; + eMultipleFiles override_java_multiple_files_; + bool store_unknown_fields_; + NameMap java_packages_; + NameMap java_outer_classnames_; + NameSet java_multiple_files_; + bool generate_has_; + bool java_enum_style_; + bool optional_field_accessors_; + bool use_reference_types_for_primitives_; + bool generate_equals_; + bool ignore_services_; + bool parcelable_messages_; + bool reftypes_primitive_enums_; + bool generate_clear_; + + public: + Params(const string & base_name) : + empty_(""), + base_name_(base_name), + override_java_multiple_files_(JAVANANO_MUL_UNSET), + store_unknown_fields_(false), + generate_has_(false), + java_enum_style_(false), + optional_field_accessors_(false), + use_reference_types_for_primitives_(false), + generate_equals_(false), + ignore_services_(false), + parcelable_messages_(false), + reftypes_primitive_enums_(false), + generate_clear_(true) { + } + + const string& base_name() const { + return base_name_; + } + + bool has_java_package(const string& file_name) const { + return java_packages_.find(file_name) + != java_packages_.end(); + } + void set_java_package(const string& file_name, + const string& java_package) { + java_packages_[file_name] = java_package; + } + const string& java_package(const string& file_name) const { + NameMap::const_iterator itr; + + itr = java_packages_.find(file_name); + if (itr == java_packages_.end()) { + return empty_; + } else { + return itr->second; + } + } + const NameMap& java_packages() { + return java_packages_; + } + + bool has_java_outer_classname(const string& file_name) const { + return java_outer_classnames_.find(file_name) + != java_outer_classnames_.end(); + } + void set_java_outer_classname(const string& file_name, + const string& java_outer_classname) { + java_outer_classnames_[file_name] = java_outer_classname; + } + const string& java_outer_classname(const string& file_name) const { + NameMap::const_iterator itr; + + itr = java_outer_classnames_.find(file_name); + if (itr == java_outer_classnames_.end()) { + return empty_; + } else { + return itr->second; + } + } + const NameMap& java_outer_classnames() { + return java_outer_classnames_; + } + + void set_override_java_multiple_files(bool java_multiple_files) { + if (java_multiple_files) { + override_java_multiple_files_ = JAVANANO_MUL_TRUE; + } else { + override_java_multiple_files_ = JAVANANO_MUL_FALSE; + } + } + void clear_override_java_multiple_files() { + override_java_multiple_files_ = JAVANANO_MUL_UNSET; + } + + void set_java_multiple_files(const string& file_name, bool value) { + if (value) { + java_multiple_files_.insert(file_name); + } else { + java_multiple_files_.erase(file_name); + } + } + bool java_multiple_files(const string& file_name) const { + switch (override_java_multiple_files_) { + case JAVANANO_MUL_FALSE: + return false; + case JAVANANO_MUL_TRUE: + return true; + default: + return java_multiple_files_.find(file_name) + != java_multiple_files_.end(); + } + } + + void set_store_unknown_fields(bool value) { + store_unknown_fields_ = value; + } + bool store_unknown_fields() const { + return store_unknown_fields_; + } + + void set_generate_has(bool value) { + generate_has_ = value; + } + bool generate_has() const { + return generate_has_; + } + + void set_java_enum_style(bool value) { + java_enum_style_ = value; + } + bool java_enum_style() const { + return java_enum_style_; + } + + void set_optional_field_accessors(bool value) { + optional_field_accessors_ = value; + } + bool optional_field_accessors() const { + return optional_field_accessors_; + } + + void set_use_reference_types_for_primitives(bool value) { + use_reference_types_for_primitives_ = value; + } + bool use_reference_types_for_primitives() const { + return use_reference_types_for_primitives_; + } + + void set_generate_equals(bool value) { + generate_equals_ = value; + } + bool generate_equals() const { + return generate_equals_; + } + + void set_ignore_services(bool value) { + ignore_services_ = value; + } + bool ignore_services() const { + return ignore_services_; + } + + void set_parcelable_messages(bool value) { + parcelable_messages_ = value; + } + bool parcelable_messages() const { + return parcelable_messages_; + } + + void set_reftypes_primitive_enums(bool value) { + reftypes_primitive_enums_ = value; + } + bool reftypes_primitive_enums() const { + return reftypes_primitive_enums_; + } + + void set_generate_clear(bool value) { + generate_clear_ = value; + } + bool generate_clear() const { + return generate_clear_; + } +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google +#endif // PROTOBUF_COMPILER_JAVANANO_JAVANANO_PARAMS_H_ diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc new file mode 100644 index 00000000..a3bc3a84 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc @@ -0,0 +1,910 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#include <map> +#include <math.h> +#include <string> + +#include <google/protobuf/compiler/javanano/javanano_primitive_field.h> +#include <google/protobuf/stubs/common.h> +#include <google/protobuf/compiler/javanano/javanano_helpers.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/wire_format.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/substitute.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +using internal::WireFormat; +using internal::WireFormatLite; + +namespace { + +bool IsReferenceType(JavaType type) { + switch (type) { + case JAVATYPE_INT : return false; + case JAVATYPE_LONG : return false; + case JAVATYPE_FLOAT : return false; + case JAVATYPE_DOUBLE : return false; + case JAVATYPE_BOOLEAN: return false; + case JAVATYPE_STRING : return true; + case JAVATYPE_BYTES : return true; + case JAVATYPE_ENUM : return false; + case JAVATYPE_MESSAGE: return true; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return false; +} + +bool IsArrayType(JavaType type) { + switch (type) { + case JAVATYPE_INT : return false; + case JAVATYPE_LONG : return false; + case JAVATYPE_FLOAT : return false; + case JAVATYPE_DOUBLE : return false; + case JAVATYPE_BOOLEAN: return false; + case JAVATYPE_STRING : return false; + case JAVATYPE_BYTES : return true; + case JAVATYPE_ENUM : return false; + case JAVATYPE_MESSAGE: return false; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return false; +} + +const char* GetCapitalizedType(const FieldDescriptor* field) { + switch (field->type()) { + case FieldDescriptor::TYPE_INT32 : return "Int32" ; + case FieldDescriptor::TYPE_UINT32 : return "UInt32" ; + case FieldDescriptor::TYPE_SINT32 : return "SInt32" ; + case FieldDescriptor::TYPE_FIXED32 : return "Fixed32" ; + case FieldDescriptor::TYPE_SFIXED32: return "SFixed32"; + case FieldDescriptor::TYPE_INT64 : return "Int64" ; + case FieldDescriptor::TYPE_UINT64 : return "UInt64" ; + case FieldDescriptor::TYPE_SINT64 : return "SInt64" ; + case FieldDescriptor::TYPE_FIXED64 : return "Fixed64" ; + case FieldDescriptor::TYPE_SFIXED64: return "SFixed64"; + case FieldDescriptor::TYPE_FLOAT : return "Float" ; + case FieldDescriptor::TYPE_DOUBLE : return "Double" ; + case FieldDescriptor::TYPE_BOOL : return "Bool" ; + case FieldDescriptor::TYPE_STRING : return "String" ; + case FieldDescriptor::TYPE_BYTES : return "Bytes" ; + case FieldDescriptor::TYPE_ENUM : return "Enum" ; + case FieldDescriptor::TYPE_GROUP : return "Group" ; + case FieldDescriptor::TYPE_MESSAGE : return "Message" ; + + // No default because we want the compiler to complain if any new + // types are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return NULL; +} + +// For encodings with fixed sizes, returns that size in bytes. Otherwise +// returns -1. +int FixedSize(FieldDescriptor::Type type) { + switch (type) { + case FieldDescriptor::TYPE_INT32 : return -1; + case FieldDescriptor::TYPE_INT64 : return -1; + case FieldDescriptor::TYPE_UINT32 : return -1; + case FieldDescriptor::TYPE_UINT64 : return -1; + case FieldDescriptor::TYPE_SINT32 : return -1; + case FieldDescriptor::TYPE_SINT64 : return -1; + case FieldDescriptor::TYPE_FIXED32 : return WireFormatLite::kFixed32Size; + case FieldDescriptor::TYPE_FIXED64 : return WireFormatLite::kFixed64Size; + case FieldDescriptor::TYPE_SFIXED32: return WireFormatLite::kSFixed32Size; + case FieldDescriptor::TYPE_SFIXED64: return WireFormatLite::kSFixed64Size; + case FieldDescriptor::TYPE_FLOAT : return WireFormatLite::kFloatSize; + case FieldDescriptor::TYPE_DOUBLE : return WireFormatLite::kDoubleSize; + + case FieldDescriptor::TYPE_BOOL : return WireFormatLite::kBoolSize; + case FieldDescriptor::TYPE_ENUM : return -1; + + case FieldDescriptor::TYPE_STRING : return -1; + case FieldDescriptor::TYPE_BYTES : return -1; + case FieldDescriptor::TYPE_GROUP : return -1; + case FieldDescriptor::TYPE_MESSAGE : return -1; + + // No default because we want the compiler to complain if any new + // types are added. + } + GOOGLE_LOG(FATAL) << "Can't get here."; + return -1; +} + +// Return true if the type is a that has variable length +// for instance String's. +bool IsVariableLenType(JavaType type) { + switch (type) { + case JAVATYPE_INT : return false; + case JAVATYPE_LONG : return false; + case JAVATYPE_FLOAT : return false; + case JAVATYPE_DOUBLE : return false; + case JAVATYPE_BOOLEAN: return false; + case JAVATYPE_STRING : return true; + case JAVATYPE_BYTES : return true; + case JAVATYPE_ENUM : return false; + case JAVATYPE_MESSAGE: return true; + + // No default because we want the compiler to complain if any new + // JavaTypes are added. + } + + GOOGLE_LOG(FATAL) << "Can't get here."; + return false; +} + +bool AllAscii(const string& text) { + for (int i = 0; i < text.size(); i++) { + if ((text[i] & 0x80) != 0) { + return false; + } + } + return true; +} + +void SetPrimitiveVariables(const FieldDescriptor* descriptor, const Params params, + map<string, string>* variables) { + (*variables)["name"] = + RenameJavaKeywords(UnderscoresToCamelCase(descriptor)); + (*variables)["capitalized_name"] = + RenameJavaKeywords(UnderscoresToCapitalizedCamelCase(descriptor)); + (*variables)["number"] = SimpleItoa(descriptor->number()); + if (params.use_reference_types_for_primitives() + && !descriptor->is_repeated()) { + (*variables)["type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor)); + } else { + (*variables)["type"] = PrimitiveTypeName(GetJavaType(descriptor)); + } + // Deals with defaults. For C++-string types (string and bytes), + // we might need to have the generated code do the unicode decoding + // (see comments in InternalNano.java for gory details.). We would + // like to do this once into a static field and re-use that from + // then on. + if (descriptor->cpp_type() == FieldDescriptor::CPPTYPE_STRING && + !descriptor->default_value_string().empty() && + !params.use_reference_types_for_primitives()) { + if (descriptor->type() == FieldDescriptor::TYPE_BYTES) { + (*variables)["default"] = DefaultValue(params, descriptor); + (*variables)["default_constant"] = FieldDefaultConstantName(descriptor); + (*variables)["default_constant_value"] = strings::Substitute( + "com.google.protobuf.nano.InternalNano.bytesDefaultValue(\"$0\")", + CEscape(descriptor->default_value_string())); + (*variables)["default_copy_if_needed"] = + (*variables)["default"] + ".clone()"; + } else if (AllAscii(descriptor->default_value_string())) { + // All chars are ASCII. In this case directly referencing a + // CEscape()'d string literal works fine. + (*variables)["default"] = + "\"" + CEscape(descriptor->default_value_string()) + "\""; + (*variables)["default_copy_if_needed"] = (*variables)["default"]; + } else { + // Strings where some chars are non-ASCII. We need to save the + // default value. + (*variables)["default"] = DefaultValue(params, descriptor); + (*variables)["default_constant"] = FieldDefaultConstantName(descriptor); + (*variables)["default_constant_value"] = strings::Substitute( + "com.google.protobuf.nano.InternalNano.stringDefaultValue(\"$0\")", + CEscape(descriptor->default_value_string())); + (*variables)["default_copy_if_needed"] = (*variables)["default"]; + } + } else { + // Non-string, non-bytes field. Defaults are literals. + (*variables)["default"] = DefaultValue(params, descriptor); + (*variables)["default_copy_if_needed"] = (*variables)["default"]; + } + (*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor)); + (*variables)["capitalized_type"] = GetCapitalizedType(descriptor); + (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor)); + (*variables)["tag_size"] = SimpleItoa( + WireFormat::TagSize(descriptor->number(), descriptor->type())); + (*variables)["non_packed_tag"] = SimpleItoa( + internal::WireFormatLite::MakeTag(descriptor->number(), + internal::WireFormat::WireTypeForFieldType(descriptor->type()))); + int fixed_size = FixedSize(descriptor->type()); + if (fixed_size != -1) { + (*variables)["fixed_size"] = SimpleItoa(fixed_size); + } + (*variables)["message_name"] = descriptor->containing_type()->name(); + (*variables)["empty_array_name"] = EmptyArrayName(params, descriptor); +} +} // namespace + +// =================================================================== + +PrimitiveFieldGenerator:: +PrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params) + : FieldGenerator(params), descriptor_(descriptor) { + SetPrimitiveVariables(descriptor, params, &variables_); +} + +PrimitiveFieldGenerator::~PrimitiveFieldGenerator() {} + +bool PrimitiveFieldGenerator::SavedDefaultNeeded() const { + return variables_.find("default_constant") != variables_.end(); +} + +void PrimitiveFieldGenerator::GenerateInitSavedDefaultCode(io::Printer* printer) const { + if (variables_.find("default_constant") != variables_.end()) { + printer->Print(variables_, + "$default_constant$ = $default_constant_value$;\n"); + } +} + +void PrimitiveFieldGenerator:: +GenerateMembers(io::Printer* printer, bool lazy_init) const { + if (variables_.find("default_constant") != variables_.end()) { + // Those primitive types that need a saved default. + if (lazy_init) { + printer->Print(variables_, + "private static $type$ $default_constant$;\n"); + } else { + printer->Print(variables_, + "private static final $type$ $default_constant$ =\n" + " $default_constant_value$;\n"); + } + } + + printer->Print(variables_, + "public $type$ $name$;\n"); + + if (params_.generate_has()) { + printer->Print(variables_, + "public boolean has$capitalized_name$;\n"); + } +} + +void PrimitiveFieldGenerator:: +GenerateClearCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$ = $default_copy_if_needed$;\n"); + + if (params_.generate_has()) { + printer->Print(variables_, + "has$capitalized_name$ = false;\n"); + } +} + +void PrimitiveFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "this.$name$ = input.read$capitalized_type$();\n"); + + if (params_.generate_has()) { + printer->Print(variables_, + "has$capitalized_name$ = true;\n"); + } +} + +void PrimitiveFieldGenerator:: +GenerateSerializationConditional(io::Printer* printer) const { + if (params_.use_reference_types_for_primitives()) { + // For reference type mode, serialize based on equality + // to null. + printer->Print(variables_, + "if (this.$name$ != null) {\n"); + return; + } + if (params_.generate_has()) { + printer->Print(variables_, + "if (has$capitalized_name$ || "); + } else { + printer->Print(variables_, + "if ("); + } + JavaType java_type = GetJavaType(descriptor_); + if (IsArrayType(java_type)) { + printer->Print(variables_, + "!java.util.Arrays.equals(this.$name$, $default$)) {\n"); + } else if (IsReferenceType(java_type)) { + printer->Print(variables_, + "!this.$name$.equals($default$)) {\n"); + } else if (java_type == JAVATYPE_FLOAT) { + printer->Print(variables_, + "java.lang.Float.floatToIntBits(this.$name$)\n" + " != java.lang.Float.floatToIntBits($default$)) {\n"); + } else if (java_type == JAVATYPE_DOUBLE) { + printer->Print(variables_, + "java.lang.Double.doubleToLongBits(this.$name$)\n" + " != java.lang.Double.doubleToLongBits($default$)) {\n"); + } else { + printer->Print(variables_, + "this.$name$ != $default$) {\n"); + } +} + +void PrimitiveFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + if (descriptor_->is_required() && !params_.generate_has()) { + // Always serialize a required field if we don't have the 'has' signal. + printer->Print(variables_, + "output.write$capitalized_type$($number$, this.$name$);\n"); + } else { + GenerateSerializationConditional(printer); + printer->Print(variables_, + " output.write$capitalized_type$($number$, this.$name$);\n" + "}\n"); + } +} + +void PrimitiveFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + if (descriptor_->is_required() && !params_.generate_has()) { + printer->Print(variables_, + "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .compute$capitalized_type$Size($number$, this.$name$);\n"); + } else { + GenerateSerializationConditional(printer); + printer->Print(variables_, + " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .compute$capitalized_type$Size($number$, this.$name$);\n" + "}\n"); + } +} + +void PrimitiveFieldGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + // We define equality as serialized form equality. If generate_has(), + // then if the field value equals the default value in both messages, + // but one's 'has' field is set and the other's is not, the serialized + // forms are different and we should return false. + JavaType java_type = GetJavaType(descriptor_); + if (java_type == JAVATYPE_BYTES) { + printer->Print(variables_, + "if (!java.util.Arrays.equals(this.$name$, other.$name$)"); + if (params_.generate_has()) { + printer->Print(variables_, + "\n" + " || (java.util.Arrays.equals(this.$name$, $default$)\n" + " && this.has$capitalized_name$ != other.has$capitalized_name$)"); + } + printer->Print(") {\n" + " return false;\n" + "}\n"); + } else if (java_type == JAVATYPE_STRING + || params_.use_reference_types_for_primitives()) { + printer->Print(variables_, + "if (this.$name$ == null) {\n" + " if (other.$name$ != null) {\n" + " return false;\n" + " }\n" + "} else if (!this.$name$.equals(other.$name$)"); + if (params_.generate_has()) { + printer->Print(variables_, + "\n" + " || (this.$name$.equals($default$)\n" + " && this.has$capitalized_name$ != other.has$capitalized_name$)"); + } + printer->Print(") {\n" + " return false;\n" + "}\n"); + } else if (java_type == JAVATYPE_FLOAT) { + printer->Print(variables_, + "{\n" + " int bits = java.lang.Float.floatToIntBits(this.$name$);\n" + " if (bits != java.lang.Float.floatToIntBits(other.$name$)"); + if (params_.generate_has()) { + printer->Print(variables_, + "\n" + " || (bits == java.lang.Float.floatToIntBits($default$)\n" + " && this.has$capitalized_name$ != other.has$capitalized_name$)"); + } + printer->Print(") {\n" + " return false;\n" + " }\n" + "}\n"); + } else if (java_type == JAVATYPE_DOUBLE) { + printer->Print(variables_, + "{\n" + " long bits = java.lang.Double.doubleToLongBits(this.$name$);\n" + " if (bits != java.lang.Double.doubleToLongBits(other.$name$)"); + if (params_.generate_has()) { + printer->Print(variables_, + "\n" + " || (bits == java.lang.Double.doubleToLongBits($default$)\n" + " && this.has$capitalized_name$ != other.has$capitalized_name$)"); + } + printer->Print(") {\n" + " return false;\n" + " }\n" + "}\n"); + } else { + printer->Print(variables_, + "if (this.$name$ != other.$name$"); + if (params_.generate_has()) { + printer->Print(variables_, + "\n" + " || (this.$name$ == $default$\n" + " && this.has$capitalized_name$ != other.has$capitalized_name$)"); + } + printer->Print(") {\n" + " return false;\n" + "}\n"); + } +} + +void PrimitiveFieldGenerator:: +GenerateHashCodeCode(io::Printer* printer) const { + JavaType java_type = GetJavaType(descriptor_); + if (java_type == JAVATYPE_BYTES) { + printer->Print(variables_, + "result = 31 * result + java.util.Arrays.hashCode(this.$name$);\n"); + } else if (java_type == JAVATYPE_STRING + || params_.use_reference_types_for_primitives()) { + printer->Print(variables_, + "result = 31 * result\n" + " + (this.$name$ == null ? 0 : this.$name$.hashCode());\n"); + } else { + switch (java_type) { + // For all Java primitive types below, the hash codes match the + // results of BoxedType.valueOf(primitiveValue).hashCode(). + case JAVATYPE_INT: + printer->Print(variables_, + "result = 31 * result + this.$name$;\n"); + break; + case JAVATYPE_LONG: + printer->Print(variables_, + "result = 31 * result\n" + " + (int) (this.$name$ ^ (this.$name$ >>> 32));\n"); + break; + case JAVATYPE_FLOAT: + printer->Print(variables_, + "result = 31 * result\n" + " + java.lang.Float.floatToIntBits(this.$name$);\n"); + break; + case JAVATYPE_DOUBLE: + printer->Print(variables_, + "{\n" + " long v = java.lang.Double.doubleToLongBits(this.$name$);\n" + " result = 31 * result + (int) (v ^ (v >>> 32));\n" + "}\n"); + break; + case JAVATYPE_BOOLEAN: + printer->Print(variables_, + "result = 31 * result + (this.$name$ ? 1231 : 1237);\n"); + break; + default: + GOOGLE_LOG(ERROR) << "unknown java type for primitive field"; + break; + } + } +} + +// =================================================================== + +AccessorPrimitiveFieldGenerator:: +AccessorPrimitiveFieldGenerator(const FieldDescriptor* descriptor, + const Params& params, int has_bit_index) + : FieldGenerator(params), descriptor_(descriptor) { + SetPrimitiveVariables(descriptor, params, &variables_); + SetBitOperationVariables("has", has_bit_index, &variables_); +} + +AccessorPrimitiveFieldGenerator::~AccessorPrimitiveFieldGenerator() {} + +bool AccessorPrimitiveFieldGenerator::SavedDefaultNeeded() const { + return variables_.find("default_constant") != variables_.end(); +} + +void AccessorPrimitiveFieldGenerator:: +GenerateInitSavedDefaultCode(io::Printer* printer) const { + if (variables_.find("default_constant") != variables_.end()) { + printer->Print(variables_, + "$default_constant$ = $default_constant_value$;\n"); + } +} + +void AccessorPrimitiveFieldGenerator:: +GenerateMembers(io::Printer* printer, bool lazy_init) const { + if (variables_.find("default_constant") != variables_.end()) { + // Those primitive types that need a saved default. + if (lazy_init) { + printer->Print(variables_, + "private static $type$ $default_constant$;\n"); + } else { + printer->Print(variables_, + "private static final $type$ $default_constant$ =\n" + " $default_constant_value$;\n"); + } + } + printer->Print(variables_, + "private $type$ $name$_;\n" + "public $type$ get$capitalized_name$() {\n" + " return $name$_;\n" + "}\n" + "public $message_name$ set$capitalized_name$($type$ value) {\n"); + if (IsReferenceType(GetJavaType(descriptor_))) { + printer->Print(variables_, + " if (value == null) {\n" + " throw new java.lang.NullPointerException();\n" + " }\n"); + } + printer->Print(variables_, + " $name$_ = value;\n" + " $set_has$;\n" + " return this;\n" + "}\n" + "public boolean has$capitalized_name$() {\n" + " return $get_has$;\n" + "}\n" + "public $message_name$ clear$capitalized_name$() {\n" + " $name$_ = $default_copy_if_needed$;\n" + " $clear_has$;\n" + " return this;\n" + "}\n"); +} + +void AccessorPrimitiveFieldGenerator:: +GenerateClearCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$_ = $default_copy_if_needed$;\n"); +} + +void AccessorPrimitiveFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$_ = input.read$capitalized_type$();\n" + "$set_has$;\n"); +} + +void AccessorPrimitiveFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($get_has$) {\n" + " output.write$capitalized_type$($number$, $name$_);\n" + "}\n"); +} + +void AccessorPrimitiveFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if ($get_has$) {\n" + " size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .compute$capitalized_type$Size($number$, $name$_);\n" + "}\n"); +} + +void AccessorPrimitiveFieldGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + switch (GetJavaType(descriptor_)) { + // For all Java primitive types below, the equality checks match the + // results of BoxedType.valueOf(primitiveValue).equals(otherValue). + case JAVATYPE_FLOAT: + printer->Print(variables_, + "if ($different_has$\n" + " || java.lang.Float.floatToIntBits($name$_)\n" + " != java.lang.Float.floatToIntBits(other.$name$_)) {\n" + " return false;\n" + "}\n"); + break; + case JAVATYPE_DOUBLE: + printer->Print(variables_, + "if ($different_has$\n" + " || java.lang.Double.doubleToLongBits($name$_)\n" + " != java.lang.Double.doubleToLongBits(other.$name$_)) {\n" + " return false;\n" + "}\n"); + break; + case JAVATYPE_INT: + case JAVATYPE_LONG: + case JAVATYPE_BOOLEAN: + printer->Print(variables_, + "if ($different_has$\n" + " || $name$_ != other.$name$_) {\n" + " return false;\n" + "}\n"); + break; + case JAVATYPE_STRING: + // Accessor style would guarantee $name$_ non-null + printer->Print(variables_, + "if ($different_has$\n" + " || !$name$_.equals(other.$name$_)) {\n" + " return false;\n" + "}\n"); + break; + case JAVATYPE_BYTES: + // Accessor style would guarantee $name$_ non-null + printer->Print(variables_, + "if ($different_has$\n" + " || !java.util.Arrays.equals($name$_, other.$name$_)) {\n" + " return false;\n" + "}\n"); + break; + default: + GOOGLE_LOG(ERROR) << "unknown java type for primitive field"; + break; + } +} + +void AccessorPrimitiveFieldGenerator:: +GenerateHashCodeCode(io::Printer* printer) const { + switch (GetJavaType(descriptor_)) { + // For all Java primitive types below, the hash codes match the + // results of BoxedType.valueOf(primitiveValue).hashCode(). + case JAVATYPE_INT: + printer->Print(variables_, + "result = 31 * result + $name$_;\n"); + break; + case JAVATYPE_LONG: + printer->Print(variables_, + "result = 31 * result + (int) ($name$_ ^ ($name$_ >>> 32));\n"); + break; + case JAVATYPE_FLOAT: + printer->Print(variables_, + "result = 31 * result +\n" + " java.lang.Float.floatToIntBits($name$_);\n"); + break; + case JAVATYPE_DOUBLE: + printer->Print(variables_, + "{\n" + " long v = java.lang.Double.doubleToLongBits($name$_);\n" + " result = 31 * result + (int) (v ^ (v >>> 32));\n" + "}\n"); + break; + case JAVATYPE_BOOLEAN: + printer->Print(variables_, + "result = 31 * result + ($name$_ ? 1231 : 1237);\n"); + break; + case JAVATYPE_STRING: + // Accessor style would guarantee $name$_ non-null + printer->Print(variables_, + "result = 31 * result + $name$_.hashCode();\n"); + break; + case JAVATYPE_BYTES: + // Accessor style would guarantee $name$_ non-null + printer->Print(variables_, + "result = 31 * result + java.util.Arrays.hashCode($name$_);\n"); + break; + default: + GOOGLE_LOG(ERROR) << "unknown java type for primitive field"; + break; + } +} + +// =================================================================== + +RepeatedPrimitiveFieldGenerator:: +RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params) + : FieldGenerator(params), descriptor_(descriptor) { + SetPrimitiveVariables(descriptor, params, &variables_); +} + +RepeatedPrimitiveFieldGenerator::~RepeatedPrimitiveFieldGenerator() {} + +void RepeatedPrimitiveFieldGenerator:: +GenerateMembers(io::Printer* printer, bool /*unused init_defaults*/) const { + printer->Print(variables_, + "public $type$[] $name$;\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateClearCode(io::Printer* printer) const { + printer->Print(variables_, + "$name$ = $default$;\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateMergingCode(io::Printer* printer) const { + // First, figure out the length of the array, then parse. + printer->Print(variables_, + "int arrayLength = com.google.protobuf.nano.WireFormatNano\n" + " .getRepeatedFieldArrayLength(input, $non_packed_tag$);\n" + "int i = this.$name$ == null ? 0 : this.$name$.length;\n"); + + if (GetJavaType(descriptor_) == JAVATYPE_BYTES) { + printer->Print(variables_, + "byte[][] newArray = new byte[i + arrayLength][];\n"); + } else { + printer->Print(variables_, + "$type$[] newArray = new $type$[i + arrayLength];\n"); + } + printer->Print(variables_, + "if (i != 0) {\n" + " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n" + "}\n" + "for (; i < newArray.length - 1; i++) {\n" + " newArray[i] = input.read$capitalized_type$();\n" + " input.readTag();\n" + "}\n" + "// Last one without readTag.\n" + "newArray[i] = input.read$capitalized_type$();\n" + "this.$name$ = newArray;\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateMergingCodeFromPacked(io::Printer* printer) const { + printer->Print( + "int length = input.readRawVarint32();\n" + "int limit = input.pushLimit(length);\n"); + + // If we know the elements will all be of the same size, the arrayLength + // can be calculated much more easily. However, FixedSize() returns 1 for + // repeated bool fields, which are guaranteed to have the fixed size of + // 1 byte per value only if we control the output. On the wire they can + // legally appear as variable-size integers, so we need to use the slow + // way for repeated bool fields. + if (descriptor_->type() == FieldDescriptor::TYPE_BOOL + || FixedSize(descriptor_->type()) == -1) { + printer->Print(variables_, + "// First pass to compute array length.\n" + "int arrayLength = 0;\n" + "int startPos = input.getPosition();\n" + "while (input.getBytesUntilLimit() > 0) {\n" + " input.read$capitalized_type$();\n" + " arrayLength++;\n" + "}\n" + "input.rewindToPosition(startPos);\n"); + } else { + printer->Print(variables_, + "int arrayLength = length / $fixed_size$;\n"); + } + + printer->Print(variables_, + "int i = this.$name$ == null ? 0 : this.$name$.length;\n" + "$type$[] newArray = new $type$[i + arrayLength];\n" + "if (i != 0) {\n" + " java.lang.System.arraycopy(this.$name$, 0, newArray, 0, i);\n" + "}\n" + "for (; i < newArray.length; i++) {\n" + " newArray[i] = input.read$capitalized_type$();\n" + "}\n" + "this.$name$ = newArray;\n" + "input.popLimit(limit);\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateRepeatedDataSizeCode(io::Printer* printer) const { + // Creates a variable dataSize and puts the serialized size in there. + // If the element type is a Java reference type, also generates + // dataCount which stores the number of non-null elements in the field. + if (IsReferenceType(GetJavaType(descriptor_))) { + printer->Print(variables_, + "int dataCount = 0;\n" + "int dataSize = 0;\n" + "for (int i = 0; i < this.$name$.length; i++) {\n" + " $type$ element = this.$name$[i];\n" + " if (element != null) {\n" + " dataCount++;\n" + " dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .compute$capitalized_type$SizeNoTag(element);\n" + " }\n" + "}\n"); + } else if (FixedSize(descriptor_->type()) == -1) { + printer->Print(variables_, + "int dataSize = 0;\n" + "for (int i = 0; i < this.$name$.length; i++) {\n" + " $type$ element = this.$name$[i];\n" + " dataSize += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .compute$capitalized_type$SizeNoTag(element);\n" + "}\n"); + } else { + printer->Print(variables_, + "int dataSize = $fixed_size$ * this.$name$.length;\n"); + } +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateSerializationCode(io::Printer* printer) const { + printer->Print(variables_, + "if (this.$name$ != null && this.$name$.length > 0) {\n"); + printer->Indent(); + + if (descriptor_->is_packable() && descriptor_->options().packed()) { + GenerateRepeatedDataSizeCode(printer); + printer->Print(variables_, + "output.writeRawVarint32($tag$);\n" + "output.writeRawVarint32(dataSize);\n" + "for (int i = 0; i < this.$name$.length; i++) {\n" + " output.write$capitalized_type$NoTag(this.$name$[i]);\n" + "}\n"); + } else if (IsReferenceType(GetJavaType(descriptor_))) { + printer->Print(variables_, + "for (int i = 0; i < this.$name$.length; i++) {\n" + " $type$ element = this.$name$[i];\n" + " if (element != null) {\n" + " output.write$capitalized_type$($number$, element);\n" + " }\n" + "}\n"); + } else { + printer->Print(variables_, + "for (int i = 0; i < this.$name$.length; i++) {\n" + " output.write$capitalized_type$($number$, this.$name$[i]);\n" + "}\n"); + } + + printer->Outdent(); + printer->Print("}\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateSerializedSizeCode(io::Printer* printer) const { + printer->Print(variables_, + "if (this.$name$ != null && this.$name$.length > 0) {\n"); + printer->Indent(); + + GenerateRepeatedDataSizeCode(printer); + + printer->Print( + "size += dataSize;\n"); + if (descriptor_->is_packable() && descriptor_->options().packed()) { + printer->Print(variables_, + "size += $tag_size$;\n" + "size += com.google.protobuf.nano.CodedOutputByteBufferNano\n" + " .computeRawVarint32Size(dataSize);\n"); + } else if (IsReferenceType(GetJavaType(descriptor_))) { + printer->Print(variables_, + "size += $tag_size$ * dataCount;\n"); + } else { + printer->Print(variables_, + "size += $tag_size$ * this.$name$.length;\n"); + } + + printer->Outdent(); + + printer->Print( + "}\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateEqualsCode(io::Printer* printer) const { + printer->Print(variables_, + "if (!com.google.protobuf.nano.InternalNano.equals(\n" + " this.$name$, other.$name$)) {\n" + " return false;\n" + "}\n"); +} + +void RepeatedPrimitiveFieldGenerator:: +GenerateHashCodeCode(io::Printer* printer) const { + printer->Print(variables_, + "result = 31 * result\n" + " + com.google.protobuf.nano.InternalNano.hashCode(this.$name$);\n"); +} + +} // namespace javanano +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.h b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h new file mode 100644 index 00000000..c04a19b7 --- /dev/null +++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h @@ -0,0 +1,126 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// http://code.google.com/p/protobuf/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: kenton@google.com (Kenton Varda) +// Based on original Protocol Buffers design by +// Sanjay Ghemawat, Jeff Dean, and others. + +#ifndef GOOGLE_PROTOBUF_COMPILER_JAVANANO_PRIMITIVE_FIELD_H__ +#define GOOGLE_PROTOBUF_COMPILER_JAVANANO_PRIMITIVE_FIELD_H__ + +#include <map> +#include <string> +#include <google/protobuf/compiler/javanano/javanano_field.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace javanano { + +class PrimitiveFieldGenerator : public FieldGenerator { + public: + explicit PrimitiveFieldGenerator( + const FieldDescriptor* descriptor, const Params ¶ms); + ~PrimitiveFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + bool SavedDefaultNeeded() const; + void GenerateInitSavedDefaultCode(io::Printer* printer) const; + void GenerateMembers(io::Printer* printer, bool lazy_init) const; + void GenerateClearCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCodeCode(io::Printer* printer) const; + + private: + void GenerateSerializationConditional(io::Printer* printer) const; + + const FieldDescriptor* descriptor_; + map<string, string> variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PrimitiveFieldGenerator); +}; + +class AccessorPrimitiveFieldGenerator : public FieldGenerator { + public: + explicit AccessorPrimitiveFieldGenerator(const FieldDescriptor* descriptor, + const Params ¶ms, int has_bit_index); + ~AccessorPrimitiveFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + bool SavedDefaultNeeded() const; + void GenerateInitSavedDefaultCode(io::Printer* printer) const; + void GenerateMembers(io::Printer* printer, bool lazy_init) const; + void GenerateClearCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCodeCode(io::Printer* printer) const; + + private: + const FieldDescriptor* descriptor_; + map<string, string> variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(AccessorPrimitiveFieldGenerator); +}; + +class RepeatedPrimitiveFieldGenerator : public FieldGenerator { + public: + explicit RepeatedPrimitiveFieldGenerator(const FieldDescriptor* descriptor, const Params& params); + ~RepeatedPrimitiveFieldGenerator(); + + // implements FieldGenerator --------------------------------------- + void GenerateMembers(io::Printer* printer, bool lazy_init) const; + void GenerateClearCode(io::Printer* printer) const; + void GenerateMergingCode(io::Printer* printer) const; + void GenerateMergingCodeFromPacked(io::Printer* printer) const; + void GenerateSerializationCode(io::Printer* printer) const; + void GenerateSerializedSizeCode(io::Printer* printer) const; + void GenerateEqualsCode(io::Printer* printer) const; + void GenerateHashCodeCode(io::Printer* printer) const; + + private: + void GenerateRepeatedDataSizeCode(io::Printer* printer) const; + + const FieldDescriptor* descriptor_; + map<string, string> variables_; + + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(RepeatedPrimitiveFieldGenerator); +}; + +} // namespace javanano +} // namespace compiler +} // namespace protobuf + +} // namespace google +#endif // GOOGLE_PROTOBUF_COMPILER_JAVANANO_PRIMITIVE_FIELD_H__ diff --git a/src/google/protobuf/compiler/main.cc b/src/google/protobuf/compiler/main.cc index 2f5bdaf7..9f2127bb 100644 --- a/src/google/protobuf/compiler/main.cc +++ b/src/google/protobuf/compiler/main.cc @@ -34,6 +34,7 @@ #include <google/protobuf/compiler/cpp/cpp_generator.h> #include <google/protobuf/compiler/python/python_generator.h> #include <google/protobuf/compiler/java/java_generator.h> +#include <google/protobuf/compiler/javanano/javanano_generator.h> int main(int argc, char* argv[]) { @@ -57,5 +58,10 @@ int main(int argc, char* argv[]) { cli.RegisterGenerator("--python_out", &py_generator, "Generate Python source file."); + // Java Nano + google::protobuf::compiler::javanano::JavaNanoGenerator javanano_generator; + cli.RegisterGenerator("--javanano_out", &javanano_generator, + "Generate Java Nano source file."); + return cli.Run(argc, argv); } diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc index 41b73678..fe697acf 100644 --- a/src/google/protobuf/compiler/parser.cc +++ b/src/google/protobuf/compiler/parser.cc @@ -1636,6 +1636,9 @@ bool Parser::ParseServiceMethod(MethodDescriptorProto* method, // Parse input type. DO(Consume("(")); { + if (TryConsume("stream")) { + method->set_client_streaming(true); + } LocationRecorder location(method_location, MethodDescriptorProto::kInputTypeFieldNumber); location.RecordLegacyLocation( @@ -1648,6 +1651,9 @@ bool Parser::ParseServiceMethod(MethodDescriptorProto* method, DO(Consume("returns")); DO(Consume("(")); { + if (TryConsume("stream")) { + method->set_server_streaming(true); + } LocationRecorder location(method_location, MethodDescriptorProto::kOutputTypeFieldNumber); location.RecordLegacyLocation( diff --git a/src/google/protobuf/compiler/plugin.pb.cc b/src/google/protobuf/compiler/plugin.pb.cc index f33d716c..5118de15 100644 --- a/src/google/protobuf/compiler/plugin.pb.cc +++ b/src/google/protobuf/compiler/plugin.pb.cc @@ -56,7 +56,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { -1, -1, sizeof(CodeGeneratorRequest), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorRequest, _internal_metadata_), + -1); CodeGeneratorResponse_descriptor_ = file->message_type(1); static const int CodeGeneratorResponse_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, error_), @@ -71,7 +72,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { -1, -1, sizeof(CodeGeneratorResponse), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse, _internal_metadata_), + -1); CodeGeneratorResponse_File_descriptor_ = CodeGeneratorResponse_descriptor_->nested_type(0); static const int CodeGeneratorResponse_File_offsets_[3] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, name_), @@ -87,7 +89,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fcompiler_2fplugin_2eproto() { -1, -1, sizeof(CodeGeneratorResponse_File), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(CodeGeneratorResponse_File, _internal_metadata_), + -1); } namespace { diff --git a/src/google/protobuf/compiler/plugin.pb.h b/src/google/protobuf/compiler/plugin.pb.h index 581fccf0..35a0a899 100644 --- a/src/google/protobuf/compiler/plugin.pb.h +++ b/src/google/protobuf/compiler/plugin.pb.h @@ -5,7 +5,6 @@ #define PROTOBUF_google_2fprotobuf_2fcompiler_2fplugin_2eproto__INCLUDED #include <string> -#include <stdint.h> #include <google/protobuf/stubs/common.h> diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc index d3a60045..7bc172a8 100644 --- a/src/google/protobuf/descriptor.cc +++ b/src/google/protobuf/descriptor.cc @@ -1843,6 +1843,13 @@ void MethodDescriptor::CopyTo(MethodDescriptorProto* proto) const { if (&options() != &MethodOptions::default_instance()) { proto->mutable_options()->CopyFrom(options()); } + + if (client_streaming_) { + proto->set_client_streaming(true); + } + if (server_streaming_) { + proto->set_server_streaming(true); + } } // DebugString methods =============================================== @@ -2395,10 +2402,12 @@ void MethodDescriptor::DebugString(int depth, string *contents, comment_printer(this, prefix, debug_string_options); comment_printer.AddPreComment(contents); - strings::SubstituteAndAppend(contents, "$0rpc $1(.$2) returns (.$3)", + strings::SubstituteAndAppend(contents, "$0rpc $1($4.$2) returns ($5.$3)", prefix, name(), input_type()->full_name(), - output_type()->full_name()); + output_type()->full_name(), + client_streaming() ? "stream " : "", + server_streaming() ? "stream " : ""); string formatted_options; if (FormatLineOptions(depth, options(), &formatted_options)) { @@ -4393,6 +4402,9 @@ void DescriptorBuilder::BuildMethod(const MethodDescriptorProto& proto, AllocateOptions(proto.options(), result); } + result->client_streaming_ = proto.client_streaming(); + result->server_streaming_ = proto.server_streaming(); + AddSymbol(result->full_name(), parent, result->name(), proto, Symbol(result)); } diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h index 0ee0a3f9..52df47f3 100644 --- a/src/google/protobuf/descriptor.h +++ b/src/google/protobuf/descriptor.h @@ -990,6 +990,11 @@ class LIBPROTOBUF_EXPORT MethodDescriptor { // Gets the type of protocol message which this message produces as output. const Descriptor* output_type() const; + // Gets whether the client streams multiple requests. + bool client_streaming() const; + // Gets whether the server streams multiple responses. + bool server_streaming() const; + // Get options for this method. These are specified in the .proto file by // placing lines like "option foo = 1234;" in curly-braces after a method // declaration. Allowed options are defined by MethodOptions in @@ -1031,6 +1036,8 @@ class LIBPROTOBUF_EXPORT MethodDescriptor { const Descriptor* input_type_; const Descriptor* output_type_; const MethodOptions* options_; + bool client_streaming_; + bool server_streaming_; // IMPORTANT: If you add a new field, make sure to search for all instances // of Allocate<MethodDescriptor>() and AllocateArray<MethodDescriptor>() in // descriptor.cc and update them to initialize the field. @@ -1623,6 +1630,9 @@ PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, service, const ServiceDescriptor*) PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, input_type, const Descriptor*) PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, output_type, const Descriptor*) PROTOBUF_DEFINE_OPTIONS_ACCESSOR(MethodDescriptor, MethodOptions); +PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, client_streaming, bool) +PROTOBUF_DEFINE_ACCESSOR(MethodDescriptor, server_streaming, bool) + PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, name) PROTOBUF_DEFINE_STRING_ACCESSOR(FileDescriptor, package) PROTOBUF_DEFINE_ACCESSOR(FileDescriptor, pool, const DescriptorPool*) diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc index 6a67fef8..97121fa9 100644 --- a/src/google/protobuf/descriptor.pb.cc +++ b/src/google/protobuf/descriptor.pb.cc @@ -111,7 +111,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(FileDescriptorSet), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorSet, _internal_metadata_), + -1); FileDescriptorProto_descriptor_ = file->message_type(1); static const int FileDescriptorProto_offsets_[12] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, name_), @@ -136,7 +137,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(FileDescriptorProto), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileDescriptorProto, _internal_metadata_), + -1); DescriptorProto_descriptor_ = file->message_type(2); static const int DescriptorProto_offsets_[8] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, name_), @@ -157,7 +159,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(DescriptorProto), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto, _internal_metadata_), + -1); DescriptorProto_ExtensionRange_descriptor_ = DescriptorProto_descriptor_->nested_type(0); static const int DescriptorProto_ExtensionRange_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, start_), @@ -172,7 +175,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(DescriptorProto_ExtensionRange), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(DescriptorProto_ExtensionRange, _internal_metadata_), + -1); FieldDescriptorProto_descriptor_ = file->message_type(3); static const int FieldDescriptorProto_offsets_[9] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, name_), @@ -194,7 +198,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(FieldDescriptorProto), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldDescriptorProto, _internal_metadata_), + -1); FieldDescriptorProto_Type_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(0); FieldDescriptorProto_Label_descriptor_ = FieldDescriptorProto_descriptor_->enum_type(1); OneofDescriptorProto_descriptor_ = file->message_type(4); @@ -210,7 +215,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(OneofDescriptorProto), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(OneofDescriptorProto, _internal_metadata_), + -1); EnumDescriptorProto_descriptor_ = file->message_type(5); static const int EnumDescriptorProto_offsets_[3] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, name_), @@ -226,7 +232,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(EnumDescriptorProto), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumDescriptorProto, _internal_metadata_), + -1); EnumValueDescriptorProto_descriptor_ = file->message_type(6); static const int EnumValueDescriptorProto_offsets_[3] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, name_), @@ -242,7 +249,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(EnumValueDescriptorProto), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueDescriptorProto, _internal_metadata_), + -1); ServiceDescriptorProto_descriptor_ = file->message_type(7); static const int ServiceDescriptorProto_offsets_[3] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, name_), @@ -258,13 +266,16 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(ServiceDescriptorProto), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceDescriptorProto, _internal_metadata_), + -1); MethodDescriptorProto_descriptor_ = file->message_type(8); - static const int MethodDescriptorProto_offsets_[4] = { + static const int MethodDescriptorProto_offsets_[6] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, name_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, input_type_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, output_type_), GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, options_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, client_streaming_), + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, server_streaming_), }; MethodDescriptorProto_reflection_ = ::google::protobuf::internal::GeneratedMessageReflection::NewGeneratedMessageReflection( @@ -275,7 +286,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(MethodDescriptorProto), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodDescriptorProto, _internal_metadata_), + -1); FileOptions_descriptor_ = file->message_type(9); static const int FileOptions_offsets_[13] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, java_package_), @@ -301,7 +313,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _extensions_), sizeof(FileOptions), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FileOptions, _internal_metadata_), + -1); FileOptions_OptimizeMode_descriptor_ = FileOptions_descriptor_->enum_type(0); MessageOptions_descriptor_ = file->message_type(10); static const int MessageOptions_offsets_[5] = { @@ -320,7 +333,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _extensions_), sizeof(MessageOptions), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MessageOptions, _internal_metadata_), + -1); FieldOptions_descriptor_ = file->message_type(11); static const int FieldOptions_offsets_[6] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, ctype_), @@ -339,7 +353,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _extensions_), sizeof(FieldOptions), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, _internal_metadata_), + -1); FieldOptions_CType_descriptor_ = FieldOptions_descriptor_->enum_type(0); EnumOptions_descriptor_ = file->message_type(12); static const int EnumOptions_offsets_[3] = { @@ -356,7 +371,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _extensions_), sizeof(EnumOptions), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumOptions, _internal_metadata_), + -1); EnumValueOptions_descriptor_ = file->message_type(13); static const int EnumValueOptions_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, deprecated_), @@ -371,7 +387,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _extensions_), sizeof(EnumValueOptions), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(EnumValueOptions, _internal_metadata_), + -1); ServiceOptions_descriptor_ = file->message_type(14); static const int ServiceOptions_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, deprecated_), @@ -386,7 +403,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _extensions_), sizeof(ServiceOptions), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(ServiceOptions, _internal_metadata_), + -1); MethodOptions_descriptor_ = file->message_type(15); static const int MethodOptions_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, deprecated_), @@ -401,7 +419,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _extensions_), sizeof(MethodOptions), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(MethodOptions, _internal_metadata_), + -1); UninterpretedOption_descriptor_ = file->message_type(16); static const int UninterpretedOption_offsets_[7] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, name_), @@ -421,7 +440,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(UninterpretedOption), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption, _internal_metadata_), + -1); UninterpretedOption_NamePart_descriptor_ = UninterpretedOption_descriptor_->nested_type(0); static const int UninterpretedOption_NamePart_offsets_[2] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, name_part_), @@ -436,7 +456,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(UninterpretedOption_NamePart), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(UninterpretedOption_NamePart, _internal_metadata_), + -1); SourceCodeInfo_descriptor_ = file->message_type(17); static const int SourceCodeInfo_offsets_[1] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, location_), @@ -450,7 +471,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(SourceCodeInfo), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo, _internal_metadata_), + -1); SourceCodeInfo_Location_descriptor_ = SourceCodeInfo_descriptor_->nested_type(0); static const int SourceCodeInfo_Location_offsets_[4] = { GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, path_), @@ -467,7 +489,8 @@ void protobuf_AssignDesc_google_2fprotobuf_2fdescriptor_2eproto() { -1, -1, sizeof(SourceCodeInfo_Location), - GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, _internal_metadata_)); + GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(SourceCodeInfo_Location, _internal_metadata_), + -1); } namespace { @@ -633,64 +656,65 @@ void protobuf_AddDesc_google_2fprotobuf_2fdescriptor_2eproto() { "riptorProto\022\014\n\004name\030\001 \001(\t\0226\n\006method\030\002 \003(" "\0132&.google.protobuf.MethodDescriptorProt" "o\0220\n\007options\030\003 \001(\0132\037.google.protobuf.Ser" - "viceOptions\"\177\n\025MethodDescriptorProto\022\014\n\004" - "name\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.pr" - "otobuf.MethodOptions\"\314\004\n\013FileOptions\022\024\n\014" - "java_package\030\001 \001(\t\022\034\n\024java_outer_classna" - "me\030\010 \001(\t\022\"\n\023java_multiple_files\030\n \001(\010:\005f" - "alse\022,\n\035java_generate_equals_and_hash\030\024 " - "\001(\010:\005false\022%\n\026java_string_check_utf8\030\033 \001" - "(\010:\005false\022F\n\014optimize_for\030\t \001(\0162).google" - ".protobuf.FileOptions.OptimizeMode:\005SPEE" - "D\022\022\n\ngo_package\030\013 \001(\t\022\"\n\023cc_generic_serv" - "ices\030\020 \001(\010:\005false\022$\n\025java_generic_servic" - "es\030\021 \001(\010:\005false\022\"\n\023py_generic_services\030\022" - " \001(\010:\005false\022\031\n\ndeprecated\030\027 \001(\010:\005false\022\037" - "\n\020cc_enable_arenas\030\037 \001(\010:\005false\022C\n\024unint" + "viceOptions\"\301\001\n\025MethodDescriptorProto\022\014\n" + "\004name\030\001 \001(\t\022\022\n\ninput_type\030\002 \001(\t\022\023\n\013outpu" + "t_type\030\003 \001(\t\022/\n\007options\030\004 \001(\0132\036.google.p" + "rotobuf.MethodOptions\022\037\n\020client_streamin" + "g\030\005 \001(\010:\005false\022\037\n\020server_streaming\030\006 \001(\010" + ":\005false\"\314\004\n\013FileOptions\022\024\n\014java_package\030" + "\001 \001(\t\022\034\n\024java_outer_classname\030\010 \001(\t\022\"\n\023j" + "ava_multiple_files\030\n \001(\010:\005false\022,\n\035java_" + "generate_equals_and_hash\030\024 \001(\010:\005false\022%\n" + "\026java_string_check_utf8\030\033 \001(\010:\005false\022F\n\014" + "optimize_for\030\t \001(\0162).google.protobuf.Fil" + "eOptions.OptimizeMode:\005SPEED\022\022\n\ngo_packa" + "ge\030\013 \001(\t\022\"\n\023cc_generic_services\030\020 \001(\010:\005f" + "alse\022$\n\025java_generic_services\030\021 \001(\010:\005fal" + "se\022\"\n\023py_generic_services\030\022 \001(\010:\005false\022\031" + "\n\ndeprecated\030\027 \001(\010:\005false\022\037\n\020cc_enable_a" + "renas\030\037 \001(\010:\005false\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\"\346" + "\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\022\031\n\ndeprecated\030" + "\003 \001(\010:\005false\022\021\n\tmap_entry\030\007 \001(\010\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\"\346\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\022\031" - "\n\ndeprecated\030\003 \001(\010:\005false\022\021\n\tmap_entry\030\007" - " \001(\010\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.go" - "ogle.protobuf.UninterpretedOption*\t\010\350\007\020\200" - "\200\200\200\002\"\240\002\n\014FieldOptions\022:\n\005ctype\030\001 \001(\0162#.g" - "oogle.protobuf.FieldOptions.CType:\006STRIN" - "G\022\016\n\006packed\030\002 \001(\010\022\023\n\004lazy\030\005 \001(\010:\005false\022\031" - "\n\ndeprecated\030\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:" - "\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132$." - "google.protobuf.UninterpretedOption\"/\n\005C" - "Type\022\n\n\006STRING\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIE" - "CE\020\002*\t\010\350\007\020\200\200\200\200\002\"\215\001\n\013EnumOptions\022\023\n\013allow" - "_alias\030\002 \001(\010\022\031\n\ndeprecated\030\003 \001(\010:\005false\022" - "C\n\024uninterpreted_option\030\347\007 \003(\0132$.google." - "protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"" - "}\n\020EnumValueOptions\022\031\n\ndeprecated\030\001 \001(\010:" - "\005false\022C\n\024uninterpreted_option\030\347\007 \003(\0132$." - "google.protobuf.UninterpretedOption*\t\010\350\007" - "\020\200\200\200\200\002\"{\n\016ServiceOptions\022\031\n\ndeprecated\030!" - " \001(\010:\005false\022C\n\024uninterpreted_option\030\347\007 \003" - "(\0132$.google.protobuf.UninterpretedOption" - "*\t\010\350\007\020\200\200\200\200\002\"z\n\rMethodOptions\022\031\n\ndeprecat" - "ed\030! \001(\010:\005false\022C\n\024uninterpreted_option\030" - "\347\007 \003(\0132$.google.protobuf.UninterpretedOp" - "tion*\t\010\350\007\020\200\200\200\200\002\"\236\002\n\023UninterpretedOption\022" - ";\n\004name\030\002 \003(\0132-.google.protobuf.Uninterp" - "retedOption.NamePart\022\030\n\020identifier_value" - "\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001(\004\022\032\n\022ne" - "gative_int_value\030\005 \001(\003\022\024\n\014double_value\030\006" - " \001(\001\022\024\n\014string_value\030\007 \001(\014\022\027\n\017aggregate_" - "value\030\010 \001(\t\0323\n\010NamePart\022\021\n\tname_part\030\001 \002" - "(\t\022\024\n\014is_extension\030\002 \002(\010\"\261\001\n\016SourceCodeI" - "nfo\022:\n\010location\030\001 \003(\0132(.google.protobuf." - "SourceCodeInfo.Location\032c\n\010Location\022\020\n\004p" - "ath\030\001 \003(\005B\002\020\001\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020leadi" - "ng_comments\030\003 \001(\t\022\031\n\021trailing_comments\030\004" - " \001(\tB)\n\023com.google.protobufB\020DescriptorP" - "rotosH\001", 4487); + ".UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"\240\002\n\014Fiel" + "dOptions\022:\n\005ctype\030\001 \001(\0162#.google.protobu" + "f.FieldOptions.CType:\006STRING\022\016\n\006packed\030\002" + " \001(\010\022\023\n\004lazy\030\005 \001(\010:\005false\022\031\n\ndeprecated\030" + "\003 \001(\010:\005false\022\023\n\004weak\030\n \001(\010:\005false\022C\n\024uni" + "nterpreted_option\030\347\007 \003(\0132$.google.protob" + "uf.UninterpretedOption\"/\n\005CType\022\n\n\006STRIN" + "G\020\000\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002*\t\010\350\007\020\200\200\200" + "\200\002\"\215\001\n\013EnumOptions\022\023\n\013allow_alias\030\002 \001(\010\022" + "\031\n\ndeprecated\030\003 \001(\010:\005false\022C\n\024uninterpre" + "ted_option\030\347\007 \003(\0132$.google.protobuf.Unin" + "terpretedOption*\t\010\350\007\020\200\200\200\200\002\"}\n\020EnumValueO" + "ptions\022\031\n\ndeprecated\030\001 \001(\010:\005false\022C\n\024uni" + "nterpreted_option\030\347\007 \003(\0132$.google.protob" + "uf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"{\n\016Ser" + "viceOptions\022\031\n\ndeprecated\030! \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\"z" + "\n\rMethodOptions\022\031\n\ndeprecated\030! \001(\010:\005fal" + "se\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goog" + "le.protobuf.UninterpretedOption*\t\010\350\007\020\200\200\200" + "\200\002\"\236\002\n\023UninterpretedOption\022;\n\004name\030\002 \003(\013" + "2-.google.protobuf.UninterpretedOption.N" + "amePart\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022pos" + "itive_int_value\030\004 \001(\004\022\032\n\022negative_int_va" + "lue\030\005 \001(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014strin" + "g_value\030\007 \001(\014\022\027\n\017aggregate_value\030\010 \001(\t\0323" + "\n\010NamePart\022\021\n\tname_part\030\001 \002(\t\022\024\n\014is_exte" + "nsion\030\002 \002(\010\"\261\001\n\016SourceCodeInfo\022:\n\010locati" + "on\030\001 \003(\0132(.google.protobuf.SourceCodeInf" + "o.Location\032c\n\010Location\022\020\n\004path\030\001 \003(\005B\002\020\001" + "\022\020\n\004span\030\002 \003(\005B\002\020\001\022\030\n\020leading_comments\030\003" + " \001(\t\022\031\n\021trailing_comments\030\004 \001(\tB)\n\023com.g" + "oogle.protobufB\020DescriptorProtosH\001", 4554); ::google::protobuf::MessageFactory::InternalRegisterGeneratedFile( "google/protobuf/descriptor.proto", &protobuf_RegisterTypes); FileDescriptorSet::default_instance_ = new FileDescriptorSet(); @@ -4560,6 +4584,8 @@ const int MethodDescriptorProto::kNameFieldNumber; const int MethodDescriptorProto::kInputTypeFieldNumber; const int MethodDescriptorProto::kOutputTypeFieldNumber; const int MethodDescriptorProto::kOptionsFieldNumber; +const int MethodDescriptorProto::kClientStreamingFieldNumber; +const int MethodDescriptorProto::kServerStreamingFieldNumber; #endif // !_MSC_VER MethodDescriptorProto::MethodDescriptorProto() @@ -4587,6 +4613,8 @@ void MethodDescriptorProto::SharedCtor() { input_type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); output_type_.UnsafeSetDefault(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); options_ = NULL; + client_streaming_ = false; + server_streaming_ = false; ::memset(_has_bits_, 0, sizeof(_has_bits_)); } @@ -4630,7 +4658,18 @@ MethodDescriptorProto* MethodDescriptorProto::New(::google::protobuf::Arena* are } void MethodDescriptorProto::Clear() { - if (_has_bits_[0 / 32] & 15) { +#define OFFSET_OF_FIELD_(f) (reinterpret_cast<char*>( \ + &reinterpret_cast<MethodDescriptorProto*>(16)->f) - \ + reinterpret_cast<char*>(16)) + +#define ZR_(first, last) do { \ + size_t f = OFFSET_OF_FIELD_(first); \ + size_t n = OFFSET_OF_FIELD_(last) - f + sizeof(last); \ + ::memset(&first, 0, n); \ + } while (0) + + if (_has_bits_[0 / 32] & 63) { + ZR_(client_streaming_, server_streaming_); if (has_name()) { name_.ClearToEmptyNoArena(&::google::protobuf::internal::GetEmptyStringAlreadyInited()); } @@ -4644,6 +4683,10 @@ void MethodDescriptorProto::Clear() { if (options_ != NULL) options_->::google::protobuf::MethodOptions::Clear(); } } + +#undef OFFSET_OF_FIELD_ +#undef ZR_ + ::memset(_has_bits_, 0, sizeof(_has_bits_)); if (_internal_metadata_.have_unknown_fields()) { mutable_unknown_fields()->Clear(); @@ -4719,6 +4762,36 @@ bool MethodDescriptorProto::MergePartialFromCodedStream( } else { goto handle_unusual; } + if (input->ExpectTag(40)) goto parse_client_streaming; + break; + } + + // optional bool client_streaming = 5 [default = false]; + case 5: { + if (tag == 40) { + parse_client_streaming: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &client_streaming_))); + set_has_client_streaming(); + } else { + goto handle_unusual; + } + if (input->ExpectTag(48)) goto parse_server_streaming; + break; + } + + // optional bool server_streaming = 6 [default = false]; + case 6: { + if (tag == 48) { + parse_server_streaming: + DO_((::google::protobuf::internal::WireFormatLite::ReadPrimitive< + bool, ::google::protobuf::internal::WireFormatLite::TYPE_BOOL>( + input, &server_streaming_))); + set_has_server_streaming(); + } else { + goto handle_unusual; + } if (input->ExpectAtEnd()) goto success; break; } @@ -4784,6 +4857,16 @@ void MethodDescriptorProto::SerializeWithCachedSizes( 4, *this->options_, output); } + // optional bool client_streaming = 5 [default = false]; + if (has_client_streaming()) { + ::google::protobuf::internal::WireFormatLite::WriteBool(5, this->client_streaming(), output); + } + + // optional bool server_streaming = 6 [default = false]; + if (has_server_streaming()) { + ::google::protobuf::internal::WireFormatLite::WriteBool(6, this->server_streaming(), output); + } + if (_internal_metadata_.have_unknown_fields()) { ::google::protobuf::internal::WireFormat::SerializeUnknownFields( unknown_fields(), output); @@ -4834,6 +4917,16 @@ void MethodDescriptorProto::SerializeWithCachedSizes( 4, *this->options_, target); } + // optional bool client_streaming = 5 [default = false]; + if (has_client_streaming()) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(5, this->client_streaming(), target); + } + + // optional bool server_streaming = 6 [default = false]; + if (has_server_streaming()) { + target = ::google::protobuf::internal::WireFormatLite::WriteBoolToArray(6, this->server_streaming(), target); + } + if (_internal_metadata_.have_unknown_fields()) { target = ::google::protobuf::internal::WireFormat::SerializeUnknownFieldsToArray( unknown_fields(), target); @@ -4845,7 +4938,7 @@ void MethodDescriptorProto::SerializeWithCachedSizes( int MethodDescriptorProto::ByteSize() const { int total_size = 0; - if (_has_bits_[0 / 32] & 15) { + if (_has_bits_[0 / 32] & 63) { // optional string name = 1; if (has_name()) { total_size += 1 + @@ -4874,6 +4967,16 @@ int MethodDescriptorProto::ByteSize() const { *this->options_); } + // optional bool client_streaming = 5 [default = false]; + if (has_client_streaming()) { + total_size += 1 + 1; + } + + // optional bool server_streaming = 6 [default = false]; + if (has_server_streaming()) { + total_size += 1 + 1; + } + } if (_internal_metadata_.have_unknown_fields()) { total_size += @@ -4916,6 +5019,12 @@ void MethodDescriptorProto::MergeFrom(const MethodDescriptorProto& from) { if (from.has_options()) { mutable_options()->::google::protobuf::MethodOptions::MergeFrom(from.options()); } + if (from.has_client_streaming()) { + set_client_streaming(from.client_streaming()); + } + if (from.has_server_streaming()) { + set_server_streaming(from.server_streaming()); + } } if (from._internal_metadata_.have_unknown_fields()) { mutable_unknown_fields()->MergeFrom(from.unknown_fields()); @@ -4951,6 +5060,8 @@ void MethodDescriptorProto::InternalSwap(MethodDescriptorProto* other) { input_type_.Swap(&other->input_type_); output_type_.Swap(&other->output_type_); std::swap(options_, other->options_); + std::swap(client_streaming_, other->client_streaming_); + std::swap(server_streaming_, other->server_streaming_); std::swap(_has_bits_[0], other->_has_bits_[0]); _internal_metadata_.Swap(&other->_internal_metadata_); std::swap(_cached_size_, other->_cached_size_); diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h index c55cd376..6bb5c6a6 100644 --- a/src/google/protobuf/descriptor.pb.h +++ b/src/google/protobuf/descriptor.pb.h @@ -5,7 +5,6 @@ #define PROTOBUF_google_2fprotobuf_2fdescriptor_2eproto__INCLUDED #include <string> -#include <stdint.h> #include <google/protobuf/stubs/common.h> @@ -1591,6 +1590,20 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess inline ::google::protobuf::MethodOptions* release_options(); inline void set_allocated_options(::google::protobuf::MethodOptions* options); + // optional bool client_streaming = 5 [default = false]; + inline bool has_client_streaming() const; + inline void clear_client_streaming(); + static const int kClientStreamingFieldNumber = 5; + inline bool client_streaming() const; + inline void set_client_streaming(bool value); + + // optional bool server_streaming = 6 [default = false]; + inline bool has_server_streaming() const; + inline void clear_server_streaming(); + static const int kServerStreamingFieldNumber = 6; + inline bool server_streaming() const; + inline void set_server_streaming(bool value); + // @@protoc_insertion_point(class_scope:google.protobuf.MethodDescriptorProto) private: inline void set_has_name(); @@ -1601,6 +1614,10 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess inline void clear_has_output_type(); inline void set_has_options(); inline void clear_has_options(); + inline void set_has_client_streaming(); + inline void clear_has_client_streaming(); + inline void set_has_server_streaming(); + inline void clear_has_server_streaming(); ::google::protobuf::internal::InternalMetadataWithArena _internal_metadata_; ::google::protobuf::uint32 _has_bits_[1]; @@ -1609,6 +1626,8 @@ class LIBPROTOBUF_EXPORT MethodDescriptorProto : public ::google::protobuf::Mess ::google::protobuf::internal::ArenaStringPtr input_type_; ::google::protobuf::internal::ArenaStringPtr output_type_; ::google::protobuf::MethodOptions* options_; + bool client_streaming_; + bool server_streaming_; 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(); @@ -4969,6 +4988,54 @@ inline void MethodDescriptorProto::set_allocated_options(::google::protobuf::Met // @@protoc_insertion_point(field_set_allocated:google.protobuf.MethodDescriptorProto.options) } +// optional bool client_streaming = 5 [default = false]; +inline bool MethodDescriptorProto::has_client_streaming() const { + return (_has_bits_[0] & 0x00000010u) != 0; +} +inline void MethodDescriptorProto::set_has_client_streaming() { + _has_bits_[0] |= 0x00000010u; +} +inline void MethodDescriptorProto::clear_has_client_streaming() { + _has_bits_[0] &= ~0x00000010u; +} +inline void MethodDescriptorProto::clear_client_streaming() { + client_streaming_ = false; + clear_has_client_streaming(); +} +inline bool MethodDescriptorProto::client_streaming() const { + // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.client_streaming) + return client_streaming_; +} +inline void MethodDescriptorProto::set_client_streaming(bool value) { + set_has_client_streaming(); + client_streaming_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.client_streaming) +} + +// optional bool server_streaming = 6 [default = false]; +inline bool MethodDescriptorProto::has_server_streaming() const { + return (_has_bits_[0] & 0x00000020u) != 0; +} +inline void MethodDescriptorProto::set_has_server_streaming() { + _has_bits_[0] |= 0x00000020u; +} +inline void MethodDescriptorProto::clear_has_server_streaming() { + _has_bits_[0] &= ~0x00000020u; +} +inline void MethodDescriptorProto::clear_server_streaming() { + server_streaming_ = false; + clear_has_server_streaming(); +} +inline bool MethodDescriptorProto::server_streaming() const { + // @@protoc_insertion_point(field_get:google.protobuf.MethodDescriptorProto.server_streaming) + return server_streaming_; +} +inline void MethodDescriptorProto::set_server_streaming(bool value) { + set_has_server_streaming(); + server_streaming_ = value; + // @@protoc_insertion_point(field_set:google.protobuf.MethodDescriptorProto.server_streaming) +} + // ------------------------------------------------------------------- // FileOptions diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto index 0874c4e4..e17c0cc8 100644 --- a/src/google/protobuf/descriptor.proto +++ b/src/google/protobuf/descriptor.proto @@ -220,6 +220,11 @@ message MethodDescriptorProto { optional string output_type = 3; optional MethodOptions options = 4; + + // Identifies if client streams multiple client messages + optional bool client_streaming = 5 [default=false]; + // Identifies if server streams multiple server messages + optional bool server_streaming = 6 [default=false]; } diff --git a/src/google/protobuf/dynamic_message.cc b/src/google/protobuf/dynamic_message.cc index 565afaab..318ce6f9 100644 --- a/src/google/protobuf/dynamic_message.cc +++ b/src/google/protobuf/dynamic_message.cc @@ -218,6 +218,7 @@ class DynamicMessage : public Message { int oneof_case_offset; int unknown_fields_offset; int extensions_offset; + int is_default_instance_offset; // Not owned by the TypeInfo. DynamicMessageFactory* factory; // The factory that created this object. @@ -316,6 +317,11 @@ void DynamicMessage::SharedCtor() { uint32(0); } + if (type_info_->is_default_instance_offset != -1) { + *reinterpret_cast<bool*>( + OffsetToPointer(type_info_->is_default_instance_offset)) = false; + } + new(OffsetToPointer(type_info_->unknown_fields_offset)) UnknownFieldSet; if (type_info_->extensions_offset != -1) { @@ -532,6 +538,14 @@ void DynamicMessage::CrossLinkPrototypes() { factory->GetPrototypeNoLock(field->message_type()); } } + + // Set as the default instance -- this affects field-presence semantics for + // proto3. + if (type_info_->is_default_instance_offset != -1) { + void* is_default_instance_ptr = + OffsetToPointer(type_info_->is_default_instance_offset); + *reinterpret_cast<bool*>(is_default_instance_ptr) = true; + } } Message* DynamicMessage::New() const { @@ -641,11 +655,24 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( size = AlignOffset(size); // Next the has_bits, which is an array of uint32s. - type_info->has_bits_offset = size; - int has_bits_array_size = - DivideRoundingUp(type->field_count(), bitsizeof(uint32)); - size += has_bits_array_size * sizeof(uint32); - size = AlignOffset(size); + if (type->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { + type_info->has_bits_offset = -1; + } else { + type_info->has_bits_offset = size; + int has_bits_array_size = + DivideRoundingUp(type->field_count(), bitsizeof(uint32)); + size += has_bits_array_size * sizeof(uint32); + size = AlignOffset(size); + } + + // The is_default_instance member, if any. + if (type->file()->syntax() == FileDescriptor::SYNTAX_PROTO3) { + type_info->is_default_instance_offset = size; + size += sizeof(bool); + size = AlignOffset(size); + } else { + type_info->is_default_instance_offset = -1; + } // The oneof_case, if any. It is an array of uint32s. if (type->oneof_decl_count() > 0) { @@ -731,7 +758,8 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( type_info->pool, this, type_info->size, - -1 /* arena_offset */)); + -1 /* arena_offset */, + type_info->is_default_instance_offset)); } else { type_info->reflection.reset( new GeneratedMessageReflection( @@ -744,7 +772,8 @@ const Message* DynamicMessageFactory::GetPrototypeNoLock( type_info->pool, this, type_info->size, - -1 /* arena_offset */)); + -1 /* arena_offset */, + type_info->is_default_instance_offset)); } // Cross link prototypes. prototype->CrossLinkPrototypes(); diff --git a/src/google/protobuf/dynamic_message_unittest.cc b/src/google/protobuf/dynamic_message_unittest.cc index 6353ecbf..522a092a 100644 --- a/src/google/protobuf/dynamic_message_unittest.cc +++ b/src/google/protobuf/dynamic_message_unittest.cc @@ -46,6 +46,7 @@ #include <google/protobuf/descriptor.pb.h> #include <google/protobuf/test_util.h> #include <google/protobuf/unittest.pb.h> +#include <google/protobuf/unittest_no_field_presence.pb.h> #include <google/protobuf/testing/googletest.h> #include <gtest/gtest.h> @@ -65,6 +66,8 @@ class DynamicMessageTest : public testing::Test { const Message* packed_prototype_; const Descriptor* oneof_descriptor_; const Message* oneof_prototype_; + const Descriptor* proto3_descriptor_; + const Message* proto3_prototype_; DynamicMessageTest(): factory_(&pool_) {} @@ -76,16 +79,20 @@ class DynamicMessageTest : public testing::Test { FileDescriptorProto unittest_file; FileDescriptorProto unittest_import_file; FileDescriptorProto unittest_import_public_file; + FileDescriptorProto unittest_no_field_presence_file; unittest::TestAllTypes::descriptor()->file()->CopyTo(&unittest_file); unittest_import::ImportMessage::descriptor()->file()->CopyTo( &unittest_import_file); unittest_import::PublicImportMessage::descriptor()->file()->CopyTo( &unittest_import_public_file); + proto2_nofieldpresence_unittest::TestAllTypes::descriptor()-> + file()->CopyTo(&unittest_no_field_presence_file); ASSERT_TRUE(pool_.BuildFile(unittest_import_public_file) != NULL); ASSERT_TRUE(pool_.BuildFile(unittest_import_file) != NULL); ASSERT_TRUE(pool_.BuildFile(unittest_file) != NULL); + ASSERT_TRUE(pool_.BuildFile(unittest_no_field_presence_file) != NULL); descriptor_ = pool_.FindMessageTypeByName("protobuf_unittest.TestAllTypes"); ASSERT_TRUE(descriptor_ != NULL); @@ -105,6 +112,12 @@ class DynamicMessageTest : public testing::Test { pool_.FindMessageTypeByName("protobuf_unittest.TestOneof2"); ASSERT_TRUE(oneof_descriptor_ != NULL); oneof_prototype_ = factory_.GetPrototype(oneof_descriptor_); + + proto3_descriptor_ = + pool_.FindMessageTypeByName( + "proto2_nofieldpresence_unittest.TestAllTypes"); + ASSERT_TRUE(proto3_descriptor_ != NULL); + proto3_prototype_ = factory_.GetPrototype(proto3_descriptor_); } }; @@ -233,6 +246,40 @@ TEST_F(DynamicMessageTest, Arena) { // Return without freeing: should not leak. } +TEST_F(DynamicMessageTest, Proto3) { + Message* message = proto3_prototype_->New(); + const Reflection* refl = message->GetReflection(); + const Descriptor* desc = message->GetDescriptor(); + + // Just test a single primtive and single message field here to make sure we + // are getting the no-field-presence semantics elsewhere. DynamicMessage uses + // GeneratedMessageReflection under the hood, so the rest should be fine as + // long as GMR recognizes that we're using a proto3 message. + const FieldDescriptor* optional_int32 = + desc->FindFieldByName("optional_int32"); + const FieldDescriptor* optional_msg = + desc->FindFieldByName("optional_nested_message"); + EXPECT_TRUE(optional_int32 != NULL); + EXPECT_TRUE(optional_msg != NULL); + + EXPECT_EQ(false, refl->HasField(*message, optional_int32)); + refl->SetInt32(message, optional_int32, 42); + EXPECT_EQ(true, refl->HasField(*message, optional_int32)); + refl->SetInt32(message, optional_int32, 0); + EXPECT_EQ(false, refl->HasField(*message, optional_int32)); + + EXPECT_EQ(false, refl->HasField(*message, optional_msg)); + refl->MutableMessage(message, optional_msg); + EXPECT_EQ(true, refl->HasField(*message, optional_msg)); + delete refl->ReleaseMessage(message, optional_msg); + EXPECT_EQ(false, refl->HasField(*message, optional_msg)); + + // Also ensure that the default instance handles field presence properly. + EXPECT_EQ(false, refl->HasField(*proto3_prototype_, optional_msg)); + + delete message; +} + } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index a20e362c..b4e98acd 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc @@ -193,7 +193,8 @@ GeneratedMessageReflection::GeneratedMessageReflection( const DescriptorPool* descriptor_pool, MessageFactory* factory, int object_size, - int arena_offset) + int arena_offset, + int is_default_instance_offset) : descriptor_ (descriptor), default_instance_ (default_instance), offsets_ (offsets), @@ -201,6 +202,7 @@ GeneratedMessageReflection::GeneratedMessageReflection( unknown_fields_offset_(unknown_fields_offset), extensions_offset_(extensions_offset), arena_offset_ (arena_offset), + is_default_instance_offset_(is_default_instance_offset), object_size_ (object_size), descriptor_pool_ ((descriptor_pool == NULL) ? DescriptorPool::generated_pool() : @@ -220,7 +222,8 @@ GeneratedMessageReflection::GeneratedMessageReflection( const DescriptorPool* descriptor_pool, MessageFactory* factory, int object_size, - int arena_offset) + int arena_offset, + int is_default_instance_offset) : descriptor_ (descriptor), default_instance_ (default_instance), default_oneof_instance_ (default_oneof_instance), @@ -230,6 +233,7 @@ GeneratedMessageReflection::GeneratedMessageReflection( unknown_fields_offset_(unknown_fields_offset), extensions_offset_(extensions_offset), arena_offset_ (arena_offset), + is_default_instance_offset_(is_default_instance_offset), object_size_ (object_size), descriptor_pool_ ((descriptor_pool == NULL) ? DescriptorPool::generated_pool() : @@ -1829,6 +1833,17 @@ GeneratedMessageReflection::MutableInternalMetadataWithArena( return reinterpret_cast<InternalMetadataWithArena*>(ptr); } +inline bool +GeneratedMessageReflection::GetIsDefaultInstance( + const Message& message) const { + if (is_default_instance_offset_ == kHasNoDefaultInstanceField) { + return false; + } + const void* ptr = reinterpret_cast<const uint8*>(&message) + + is_default_instance_offset_; + return *reinterpret_cast<const bool*>(ptr); +} + // Simple accessors for manipulating has_bits_. inline bool GeneratedMessageReflection::HasBit( const Message& message, const FieldDescriptor* field) const { @@ -1836,7 +1851,8 @@ inline bool GeneratedMessageReflection::HasBit( // proto3: no has-bits. All fields present except messages, which are // present only if their message-field pointer is non-NULL. if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { - return GetRaw<const Message*>(message, field) != NULL; + return !GetIsDefaultInstance(message) && + GetRaw<const Message*>(message, field) != NULL; } else { // Non-message field (and non-oneof, since that was handled in HasField() // before calling us), and singular (again, checked in HasField). So, this @@ -2082,7 +2098,8 @@ GeneratedMessageReflection::NewGeneratedMessageReflection( const void* default_oneof_instance, int oneof_case_offset, int object_size, - int arena_offset) { + int arena_offset, + int is_default_instance_offset) { return new GeneratedMessageReflection(descriptor, default_instance, offsets, @@ -2094,7 +2111,8 @@ GeneratedMessageReflection::NewGeneratedMessageReflection( DescriptorPool::generated_pool(), MessageFactory::generated_factory(), object_size, - arena_offset); + arena_offset, + is_default_instance_offset); } GeneratedMessageReflection* @@ -2106,7 +2124,8 @@ GeneratedMessageReflection::NewGeneratedMessageReflection( int unknown_fields_offset, int extensions_offset, int object_size, - int arena_offset) { + int arena_offset, + int is_default_instance_offset) { return new GeneratedMessageReflection(descriptor, default_instance, offsets, @@ -2116,7 +2135,8 @@ GeneratedMessageReflection::NewGeneratedMessageReflection( DescriptorPool::generated_pool(), MessageFactory::generated_factory(), object_size, - arena_offset); + arena_offset, + is_default_instance_offset); } } // namespace internal diff --git a/src/google/protobuf/generated_message_reflection.h b/src/google/protobuf/generated_message_reflection.h index 306809da..4dddf6c7 100644 --- a/src/google/protobuf/generated_message_reflection.h +++ b/src/google/protobuf/generated_message_reflection.h @@ -136,7 +136,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const DescriptorPool* pool, MessageFactory* factory, int object_size, - int arena_offset); + int arena_offset, + int is_default_instance_offset = -1); // Similar with the construction above. Call this construction if the // message has oneof definition. @@ -173,7 +174,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const DescriptorPool* pool, MessageFactory* factory, int object_size, - int arena_offset); + int arena_offset, + int is_default_instance_offset = -1); ~GeneratedMessageReflection(); // Shorter-to-call helpers for the above two constructions that work if the @@ -190,7 +192,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { const void* default_oneof_instance, int oneof_case_offset, int object_size, - int arena_offset); + int arena_offset, + int is_default_instance_offset = -1); static GeneratedMessageReflection* NewGeneratedMessageReflection( const Descriptor* descriptor, @@ -200,7 +203,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { int unknown_fields_offset, int extensions_offset, int object_size, - int arena_offset); + int arena_offset, + int is_default_instance_offset = -1); // implements Reflection ------------------------------------------- @@ -414,8 +418,11 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { int unknown_fields_offset_; int extensions_offset_; int arena_offset_; + int is_default_instance_offset_; int object_size_; + static const int kHasNoDefaultInstanceField = -1; + const DescriptorPool* descriptor_pool_; MessageFactory* message_factory_; @@ -446,6 +453,8 @@ class LIBPROTOBUF_EXPORT GeneratedMessageReflection : public Reflection { inline internal::InternalMetadataWithArena* MutableInternalMetadataWithArena(Message* message) const; + inline bool GetIsDefaultInstance(const Message& message) const; + inline bool HasBit(const Message& message, const FieldDescriptor* field) const; inline void SetBit(Message* message, diff --git a/src/google/protobuf/io/zero_copy_stream_impl_lite.h b/src/google/protobuf/io/zero_copy_stream_impl_lite.h index a517161d..3e25edfa 100644 --- a/src/google/protobuf/io/zero_copy_stream_impl_lite.h +++ b/src/google/protobuf/io/zero_copy_stream_impl_lite.h @@ -127,8 +127,10 @@ class LIBPROTOBUF_EXPORT ArrayOutputStream : public ZeroCopyOutputStream { class LIBPROTOBUF_EXPORT StringOutputStream : public ZeroCopyOutputStream { public: // Create a StringOutputStream which appends bytes to the given string. - // The string remains property of the caller, but it MUST NOT be accessed - // in any way until the stream is destroyed. + // The string remains property of the caller, but it is mutated in arbitrary + // ways and MUST NOT be accessed in any way until you're done with the + // stream. Either be sure there's no further usage, or (safest) destroy the + // stream before using the contents. // // Hint: If you call target->reserve(n) before creating the stream, // the first call to Next() will return at least n bytes of buffer diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index f99c5a73..f6ae3e52 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h @@ -31,10 +31,10 @@ #ifndef GOOGLE_PROTOBUF_MAP_H__ #define GOOGLE_PROTOBUF_MAP_H__ -#include <vector> +#include <iterator> +#include <google/protobuf/stubs/hash.h> #include <google/protobuf/map_type_handler.h> -#include <google/protobuf/stubs/hash.h> namespace google { namespace protobuf { @@ -48,7 +48,7 @@ namespace internal { template <typename K, typename V, FieldDescriptor::Type KeyProto, FieldDescriptor::Type ValueProto, int default_enum_value> class MapField; -} +} // namespace internal // This is the class for google::protobuf::Map's internal value_type. Instead of using // std::pair as value_type, we use this class which provides us more control of @@ -56,25 +56,24 @@ class MapField; template <typename Key, typename T> class MapPair { public: - typedef Key first_type; + typedef const Key first_type; typedef T second_type; MapPair(const Key& other_first, const T& other_second) : first(other_first), second(other_second) {} - MapPair(const Key& other_first) : first(other_first), second() {} + explicit MapPair(const Key& other_first) : first(other_first), second() {} MapPair(const MapPair& other) : first(other.first), second(other.second) {} - MapPair& operator=(const MapPair& other) { - first = other.first; - second = other.second; - return *this; - } - ~MapPair() {} + // Implicitly convertible to std::pair. + operator std::pair<const Key, T>() const { + return std::pair<const Key, T>(first, second); + } + const Key first; T second; @@ -82,52 +81,13 @@ class MapPair { friend class Map<Key, T>; }; -// STL-like iterator implementation for google::protobuf::Map. Users should not refer to -// this class directly; use google::protobuf::Map<Key, T>::iterator instead. -template <typename Key, typename T> -class MapIterator { - public: - typedef MapPair<Key, T> value_type; - typedef value_type* pointer; - typedef value_type& reference; - typedef MapIterator iterator; - - // constructor - MapIterator(const typename hash_map<Key, value_type*>::iterator& it) - : it_(it) {} - MapIterator(const MapIterator& other) : it_(other.it_) {} - MapIterator& operator=(const MapIterator& other) { - it_ = other.it_; - return *this; - } - - // deferenceable - reference operator*() const { return *it_->second; } - pointer operator->() const { return it_->second; } - - // incrementable - 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_; } - - private: - typename hash_map<Key, value_type*>::iterator it_; - - friend Map<Key, T>; -}; - // google::protobuf::Map is an associative container type used to store protobuf map // fields. Its interface is similar to std::unordered_map. Users should use this // interface directly to visit or change map fields. template <typename Key, typename T> class Map { typedef internal::MapCppTypeHandler<T> ValueTypeHandler; + public: typedef Key key_type; typedef T mapped_type; @@ -138,9 +98,6 @@ class Map { typedef value_type& reference; typedef const value_type& const_reference; - typedef MapIterator<Key, T> iterator; - typedef MapIterator<Key, T> const_iterator; - typedef size_t size_type; typedef hash<Key> hasher; @@ -153,16 +110,70 @@ class Map { ~Map() { clear(); } // Iterators + class LIBPROTOBUF_EXPORT const_iterator + : public std::iterator<std::forward_iterator_tag, value_type, ptrdiff_t, + const value_type*, const value_type&> { + typedef typename hash_map<Key, value_type*>::const_iterator InnerIt; + + public: + const_iterator() {} + explicit const_iterator(const InnerIt& it) : it_(it) {} + + const_reference operator*() const { return *it_->second; } + const_pointer operator->() const { return it_->second; } + + const_iterator& operator++() { + ++it_; + return *this; + } + const_iterator operator++(int) { return const_iterator(it_++); } + + friend bool operator==(const const_iterator& a, const const_iterator& b) { + return a.it_ == b.it_; + } + friend bool operator!=(const const_iterator& a, const const_iterator& b) { + return a.it_ != b.it_; + } + + private: + InnerIt it_; + }; + + class LIBPROTOBUF_EXPORT iterator : public std::iterator<std::forward_iterator_tag, value_type> { + typedef typename hash_map<Key, value_type*>::iterator InnerIt; + + public: + iterator() {} + explicit iterator(const InnerIt& it) : it_(it) {} + + reference operator*() const { return *it_->second; } + pointer operator->() const { return it_->second; } + + iterator& operator++() { + ++it_; + return *this; + } + iterator operator++(int) { return iterator(it_++); } + + // Implicitly convertible to const_iterator. + operator const_iterator() const { return const_iterator(it_); } + + friend bool operator==(const iterator& a, const iterator& b) { + return a.it_ == b.it_; + } + friend bool operator!=(const iterator& a, const iterator& b) { + return a.it_ != b.it_; + } + + private: + friend class Map; + InnerIt it_; + }; + iterator begin() { return iterator(elements_.begin()); } iterator end() { return iterator(elements_.end()); } - const_iterator begin() const { - return const_iterator( - const_cast<hash_map<Key, value_type*>&>(elements_).begin()); - } - const_iterator end() const { - return const_iterator( - const_cast<hash_map<Key, value_type*>&>(elements_).end()); - } + const_iterator begin() const { return const_iterator(elements_.begin()); } + const_iterator end() const { return const_iterator(elements_.end()); } const_iterator cbegin() const { return begin(); } const_iterator cend() const { return end(); } @@ -197,16 +208,30 @@ class Map { return elements_.count(key); } const_iterator find(const key_type& key) const { - // When elements_ is a const instance, find(key) returns a const iterator. - // However, to reduce code complexity, we use MapIterator for Map's both - // const and non-const iterator, which only takes non-const iterator to - // construct. - return const_iterator( - const_cast<hash_map<Key, value_type*>&>(elements_).find(key)); + return const_iterator(elements_.find(key)); } iterator find(const key_type& key) { return iterator(elements_.find(key)); } + std::pair<const_iterator, const_iterator> equal_range( + const key_type& key) const { + const_iterator it = find(key); + if (it == end()) { + return std::pair<const_iterator, const_iterator>(it, it); + } else { + const_iterator begin = it++; + return std::pair<const_iterator, const_iterator>(begin, it); + } + } + std::pair<iterator, iterator> equal_range(const key_type& key) { + iterator it = find(key); + if (it == end()) { + return std::pair<iterator, iterator>(it, it); + } else { + iterator begin = it++; + return std::pair<iterator, iterator>(begin, it); + } + } // insert std::pair<iterator, bool> insert(const value_type& value) { @@ -214,8 +239,9 @@ class Map { if (it != end()) { return std::pair<iterator, bool>(it, false); } else { - return elements_.insert( - std::pair<Key, value_type*>(value.first, new value_type(value))); + return std::pair<iterator, bool>( + iterator(elements_.insert(std::pair<Key, value_type*>( + value.first, new value_type(value))).first), true); } } template <class InputIt> @@ -258,7 +284,10 @@ class Map { // Assign Map& operator=(const Map& other) { - insert(other.begin(), other.end()); + if (this != &other) { + clear(); + insert(other.begin(), other.end()); + } return *this; } diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h index 4ceaf4a0..0fad1351 100644 --- a/src/google/protobuf/map_field.h +++ b/src/google/protobuf/map_field.h @@ -213,6 +213,13 @@ class LIBPROTOBUF_EXPORT MapField : public MapFieldBase { mutable const EntryType* default_entry_; }; +// True if IsInitialized() is true for value field in all elements of t. T is +// expected to be message. It's useful to have this helper here to keep the +// protobuf compiler from ever having to emit loops in IsInitialized() methods. +// We want the C++ compiler to inline this or not as it sees fit. +template <typename Key, typename T> +bool AllAreInitialized(const Map<Key, T>& t); + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/map_field_inl.h b/src/google/protobuf/map_field_inl.h index 6f17df95..79302e48 100644 --- a/src/google/protobuf/map_field_inl.h +++ b/src/google/protobuf/map_field_inl.h @@ -262,6 +262,15 @@ void MapField<Key, T, KeyProto, ValueProto, } } +template <typename Key, typename T> +bool AllAreInitialized(const Map<Key, T>& t) { + for (typename Map<Key, T>::const_iterator it = t.begin(); it != t.end(); + ++it) { + if (!it->second.IsInitialized()) return false; + } + return true; +} + } // namespace internal } // namespace protobuf diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc index 9d4016d3..c680ccb2 100644 --- a/src/google/protobuf/map_test.cc +++ b/src/google/protobuf/map_test.cc @@ -85,7 +85,7 @@ class MapImplTest : public ::testing::Test { EXPECT_TRUE(map_.empty()); EXPECT_EQ(0, map_.size()); } - ~MapImplTest() override {} + ~MapImplTest() {} void ExpectSingleElement(int32 key, int32 value) { EXPECT_FALSE(map_.empty()); @@ -237,6 +237,57 @@ TEST_F(MapImplTest, GetReferenceFromIterator) { } } +TEST_F(MapImplTest, IteratorBasic) { + map_[0] = 0; + + // Default constructible (per forward iterator requirements). + Map<int, int>::const_iterator cit; + Map<int, int>::iterator it; + + it = map_.begin(); + cit = it; // Converts to const_iterator + + // Can compare between them. + EXPECT_TRUE(it == cit); + EXPECT_FALSE(cit != it); + + // Pre increment. + EXPECT_FALSE(it == ++cit); + + // Post increment. + EXPECT_FALSE(it++ == cit); + EXPECT_TRUE(it == cit); +} + +template <typename T> +bool IsConstHelper(T& /*t*/) { // NOLINT. We want to catch non-const refs here. + return false; +} +template <typename T> +bool IsConstHelper(const T& /*t*/) { + return true; +} + +TEST_F(MapImplTest, IteratorConstness) { + map_[0] = 0; + EXPECT_TRUE(IsConstHelper(*map_.cbegin())); + EXPECT_TRUE(IsConstHelper(*const_map_.begin())); + EXPECT_FALSE(IsConstHelper(*map_.begin())); +} + +bool IsForwardIteratorHelper(std::forward_iterator_tag /*tag*/) { return true; } +template <typename T> +bool IsForwardIteratorHelper(T /*t*/) { + return false; +} + +TEST_F(MapImplTest, IteratorCategory) { + EXPECT_TRUE(IsForwardIteratorHelper( + std::iterator_traits<Map<int, int>::iterator>::iterator_category())); + EXPECT_TRUE(IsForwardIteratorHelper(std::iterator_traits< + Map<int, int>::const_iterator>::iterator_category())); +} + TEST_F(MapImplTest, InsertSingle) { int32 key = 0; int32 value1 = 100; @@ -433,11 +484,23 @@ TEST_F(MapImplTest, Assigner) { map_.insert(map.begin(), map.end()); Map<int32, int32> other; + int32 key_other = 123; + int32 value_other = 321; + other[key_other] = value_other; + EXPECT_EQ(1, other.size()); + other = map_; EXPECT_EQ(2, other.size()); EXPECT_EQ(value1, other.at(key1)); EXPECT_EQ(value2, other.at(key2)); + EXPECT_TRUE(other.find(key_other) == other.end()); + + // Self assign + other = other; + EXPECT_EQ(2, other.size()); + EXPECT_EQ(value1, other.at(key1)); + EXPECT_EQ(value2, other.at(key2)); } TEST_F(MapImplTest, Rehash) { @@ -457,6 +520,37 @@ TEST_F(MapImplTest, Rehash) { EXPECT_TRUE(map_.empty()); } +TEST_F(MapImplTest, EqualRange) { + int key = 100, key_missing = 101; + map_[key] = 100; + + std::pair<google::protobuf::Map<int32, int32>::iterator, + google::protobuf::Map<int32, int32>::iterator> range = map_.equal_range(key); + EXPECT_TRUE(map_.find(key) == range.first); + EXPECT_TRUE(++map_.find(key) == range.second); + + range = map_.equal_range(key_missing); + EXPECT_TRUE(map_.end() == range.first); + EXPECT_TRUE(map_.end() == range.second); + + std::pair<google::protobuf::Map<int32, int32>::const_iterator, + google::protobuf::Map<int32, int32>::const_iterator> const_range = + const_map_.equal_range(key); + EXPECT_TRUE(const_map_.find(key) == const_range.first); + EXPECT_TRUE(++const_map_.find(key) == const_range.second); + + const_range = const_map_.equal_range(key_missing); + EXPECT_TRUE(const_map_.end() == const_range.first); + EXPECT_TRUE(const_map_.end() == const_range.second); +} + +TEST_F(MapImplTest, ConvertToStdMap) { + map_[100] = 101; + std::map<int32, int32> std_map(map_.begin(), map_.end()); + EXPECT_EQ(1, std_map.size()); + EXPECT_EQ(101, std_map[100]); +} + // Map Field Reflection Test ======================================== static int Func(int i, int j) { @@ -879,15 +973,14 @@ TEST_F(MapFieldReflectionTest, RepeatedFieldRefForRegularFields) { entry_int32_double.get(), fd_map_int32_double->message_type()->field(1), Func(key, -2)); entry_string_string->GetReflection()->SetString( - entry_string_string.get(), fd_map_string_string->message_type()->field(0), - StrFunc(key, 1)); + entry_string_string.get(), + fd_map_string_string->message_type()->field(0), StrFunc(key, 1)); entry_string_string->GetReflection()->SetString( - entry_string_string.get(), fd_map_string_string->message_type()->field(1), - StrFunc(key, -5)); + entry_string_string.get(), + fd_map_string_string->message_type()->field(1), StrFunc(key, -5)); entry_int32_foreign_message->GetReflection()->SetInt32( entry_int32_foreign_message.get(), - fd_map_int32_foreign_message->message_type()->field(0), - key); + fd_map_int32_foreign_message->message_type()->field(0), key); Message* value_message = entry_int32_foreign_message->GetReflection()->MutableMessage( entry_int32_foreign_message.get(), @@ -896,10 +989,10 @@ TEST_F(MapFieldReflectionTest, RepeatedFieldRefForRegularFields) { value_message, value_message->GetDescriptor()->FindFieldByName("c"), Func(key, -6)); - mmf_int32_int32.Set(i, *entry_int32_int32.get()); - mmf_int32_double.Set(i, *entry_int32_double.get()); - mmf_string_string.Set(i, *entry_string_string.get()); - mmf_int32_foreign_message.Set(i, *entry_int32_foreign_message.get()); + mmf_int32_int32.Set(i, *entry_int32_int32); + mmf_int32_double.Set(i, *entry_int32_double); + mmf_string_string.Set(i, *entry_string_string); + mmf_int32_foreign_message.Set(i, *entry_int32_foreign_message); } for (int i = 0; i < 10; i++) { @@ -1654,6 +1747,20 @@ TEST(GeneratedMapFieldTest, MessageLiteMap) { EXPECT_EQ(1, to.map_field().at(1)); } +TEST(GeneratedMapFieldTest, IsInitialized) { + unittest::TestRequiredMessageMap map_message; + + // Add an uninitialized message. + (*map_message.mutable_map_field())[0]; + EXPECT_FALSE(map_message.IsInitialized()); + + // Initialize uninitialized message + (*map_message.mutable_map_field())[0].set_a(0); + (*map_message.mutable_map_field())[0].set_b(0); + (*map_message.mutable_map_field())[0].set_c(0); + EXPECT_TRUE(map_message.IsInitialized()); +} + // Generated Message Reflection Test ================================ TEST(GeneratedMapFieldReflectionTest, SpaceUsed) { diff --git a/src/google/protobuf/map_unittest.proto b/src/google/protobuf/map_unittest.proto index 54bc4486..9232d58f 100644 --- a/src/google/protobuf/map_unittest.proto +++ b/src/google/protobuf/map_unittest.proto @@ -75,3 +75,8 @@ enum MapEnum { MAP_ENUM_BAR = 1; MAP_ENUM_BAZ = 2; } + +// Test embeded message with required fields +message TestRequiredMessageMap { + map<int32, TestRequired> map_field = 1; +} diff --git a/src/google/protobuf/no_field_presence_test.cc b/src/google/protobuf/no_field_presence_test.cc index f248327c..4b7b31d9 100644 --- a/src/google/protobuf/no_field_presence_test.cc +++ b/src/google/protobuf/no_field_presence_test.cc @@ -269,6 +269,10 @@ TEST(NoFieldPresenceTest, MessageFieldPresenceTest) { EXPECT_EQ(true, message.has_optional_lazy_message()); message.clear_optional_lazy_message(); EXPECT_EQ(false, message.has_optional_lazy_message()); + + // Test field presence of a message field on the default instance. + EXPECT_EQ(false, proto2_nofieldpresence_unittest::TestAllTypes:: + default_instance().has_optional_nested_message()); } TEST(NoFieldPresenceTest, ReflectionHasFieldTest) { @@ -287,6 +291,13 @@ TEST(NoFieldPresenceTest, ReflectionHasFieldTest) { EXPECT_EQ(false, r->HasField(message, field)); } + // Test field presence of a message field on the default instance. + const google::protobuf::FieldDescriptor* msg_field = + desc->FindFieldByName("optional_nested_message"); + EXPECT_EQ(false, r->HasField( + proto2_nofieldpresence_unittest::TestAllTypes:: + default_instance(), msg_field)); + // Fill all fields, expect everything to report true (check oneofs below). FillValues(&message); for (int i = 0; i < desc->field_count(); i++) { diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h index 6f7a9fdb..e8c0a13c 100644 --- a/src/google/protobuf/unknown_field_set.h +++ b/src/google/protobuf/unknown_field_set.h @@ -224,13 +224,16 @@ class LIBPROTOBUF_EXPORT UnknownField { uint32 number_; uint32 type_; + + union LengthDelimited { + string* string_value_; + }; + union { uint64 varint_; uint32 fixed32_; uint64 fixed64_; - mutable union { - string* string_value_; - } length_delimited_; + mutable union LengthDelimited length_delimited_; UnknownFieldSet* group_; }; }; diff --git a/src/google/protobuf/wire_format_lite.cc b/src/google/protobuf/wire_format_lite.cc index 0c784e66..50616551 100644 --- a/src/google/protobuf/wire_format_lite.cc +++ b/src/google/protobuf/wire_format_lite.cc @@ -57,10 +57,14 @@ const int WireFormatLite::kMessageSetMessageTag; // IBM xlC requires prefixing constants with WireFormatLite:: const int WireFormatLite::kMessageSetItemTagsSize = - io::CodedOutputStream::StaticVarintSize32<WireFormatLite::kMessageSetItemStartTag>::value + - io::CodedOutputStream::StaticVarintSize32<WireFormatLite::kMessageSetItemEndTag>::value + - io::CodedOutputStream::StaticVarintSize32<WireFormatLite::kMessageSetTypeIdTag>::value + - io::CodedOutputStream::StaticVarintSize32<WireFormatLite::kMessageSetMessageTag>::value; + io::CodedOutputStream::StaticVarintSize32< + WireFormatLite::kMessageSetItemStartTag>::value + + io::CodedOutputStream::StaticVarintSize32< + WireFormatLite::kMessageSetItemEndTag>::value + + io::CodedOutputStream::StaticVarintSize32< + WireFormatLite::kMessageSetTypeIdTag>::value + + io::CodedOutputStream::StaticVarintSize32< + WireFormatLite::kMessageSetMessageTag>::value; const WireFormatLite::CppType WireFormatLite::kFieldTypeToCppTypeMap[MAX_FIELD_TYPE + 1] = { |