summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBrian Duff <bduff@google.com>2013-10-15 18:35:44 -0700
committerMax Cai <maxtroy@google.com>2013-10-25 16:06:21 +0100
commitccc48faf20dbf3b3cddcffe78d198876d543529b (patch)
tree82a2f42e9d464661152539821093b14fbc068189 /src
parent42be1e79ccd670be36220222936aa7cacc6856f6 (diff)
downloadexternal_protobuf-ccc48faf20dbf3b3cddcffe78d198876d543529b.zip
external_protobuf-ccc48faf20dbf3b3cddcffe78d198876d543529b.tar.gz
external_protobuf-ccc48faf20dbf3b3cddcffe78d198876d543529b.tar.bz2
Implement hashCode() and equals() behind a generator option.
The option is only called 'generate_equals' because: - equals() is the main thing; hashCode() is there only to complement equals(); - it's shorter; - toString() should not be included in this option because it's more for debugging and it's more likely to stop ProGuard from working well. Also shortened the "has bit" expression; was ((bitField & mask) == mask), now ((bitField & mask) != 0). Both the Java code and the bytecode are slightly shorter. Change-Id: Ic309a08a60883bf454eb6612679aa99611620e76
Diffstat (limited to 'src')
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_enum_field.cc73
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_enum_field.h12
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_field.h4
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_generator.cc2
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_helpers.cc13
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_helpers.h31
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message.cc84
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message.h7
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message_field.cc55
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_message_field.h12
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_params.h11
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_primitive_field.cc197
-rw-r--r--src/google/protobuf/compiler/javanano/javanano_primitive_field.h12
13 files changed, 456 insertions, 57 deletions
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.cc b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
index 3c4b978..b9f4fd0 100644
--- a/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.cc
@@ -159,8 +159,46 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
}
}
-string EnumFieldGenerator::GetBoxedType() const {
- return ClassName(params_, descriptor_->enum_type());
+void EnumFieldGenerator::GenerateEqualsCode(io::Printer* printer) const {
+ if (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$)) {\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()) {
+ printer->Print(variables_,
+ "(this.$name$ == null ? 0 : this.$name$)");
+ } else {
+ printer->Print(variables_,
+ "this.$name$");
+ }
+ printer->Print(";\n");
}
// ===================================================================
@@ -227,8 +265,19 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
"}\n");
}
-string AccessorEnumFieldGenerator::GetBoxedType() const {
- return ClassName(params_, descriptor_->enum_type());
+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");
}
// ===================================================================
@@ -366,8 +415,20 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
}
}
-string RepeatedEnumFieldGenerator::GetBoxedType() const {
- return ClassName(params_, descriptor_->enum_type());
+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
diff --git a/src/google/protobuf/compiler/javanano/javanano_enum_field.h b/src/google/protobuf/compiler/javanano/javanano_enum_field.h
index 934aaaa..af317d8 100644
--- a/src/google/protobuf/compiler/javanano/javanano_enum_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_enum_field.h
@@ -55,8 +55,8 @@ class EnumFieldGenerator : public FieldGenerator {
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSerializationCode(io::Printer* printer) const;
void GenerateSerializedSizeCode(io::Printer* printer) const;
-
- string GetBoxedType() const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
private:
const FieldDescriptor* descriptor_;
@@ -77,8 +77,8 @@ class AccessorEnumFieldGenerator : public FieldGenerator {
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSerializationCode(io::Printer* printer) const;
void GenerateSerializedSizeCode(io::Printer* printer) const;
-
- string GetBoxedType() const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
private:
const FieldDescriptor* descriptor_;
@@ -98,8 +98,8 @@ class RepeatedEnumFieldGenerator : public FieldGenerator {
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSerializationCode(io::Printer* printer) const;
void GenerateSerializedSizeCode(io::Printer* printer) const;
-
- string GetBoxedType() const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
private:
const FieldDescriptor* descriptor_;
diff --git a/src/google/protobuf/compiler/javanano/javanano_field.h b/src/google/protobuf/compiler/javanano/javanano_field.h
index dad2e7a..150ec19 100644
--- a/src/google/protobuf/compiler/javanano/javanano_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_field.h
@@ -62,8 +62,8 @@ class FieldGenerator {
virtual void GenerateMergingCode(io::Printer* printer) const = 0;
virtual void GenerateSerializationCode(io::Printer* printer) const = 0;
virtual void GenerateSerializedSizeCode(io::Printer* printer) const = 0;
-
- virtual string GetBoxedType() const = 0;
+ virtual void GenerateEqualsCode(io::Printer* printer) const = 0;
+ virtual void GenerateHashCodeCode(io::Printer* printer) const = 0;
protected:
const Params& params_;
diff --git a/src/google/protobuf/compiler/javanano/javanano_generator.cc b/src/google/protobuf/compiler/javanano/javanano_generator.cc
index 48c3a21..5c8bcb6 100644
--- a/src/google/protobuf/compiler/javanano/javanano_generator.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_generator.cc
@@ -125,6 +125,8 @@ bool JavaNanoGenerator::Generate(const FileDescriptor* file,
} else if (options[i].first == "optional_field_style") {
params.set_optional_field_accessors(options[i].second == "accessors");
params.set_use_reference_types_for_primitives(options[i].second == "reftypes");
+ } else if (options[i].first == "generate_equals") {
+ params.set_generate_equals(options[i].second == "true");
} else {
*error = "Ignore unknown javanano generator option: " + options[i].first;
}
diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.cc b/src/google/protobuf/compiler/javanano/javanano_helpers.cc
index ed6dbd7..95ee670 100644
--- a/src/google/protobuf/compiler/javanano/javanano_helpers.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_helpers.cc
@@ -482,7 +482,7 @@ string GenerateGetBit(int bit_index) {
int bit_in_var_index = bit_index % 32;
string mask = kBitMasks[bit_in_var_index];
- string result = "((" + var_name + " & " + mask + ") == " + mask + ")";
+ string result = "((" + var_name + " & " + mask + ") != 0)";
return result;
}
@@ -504,11 +504,22 @@ string GenerateClearBit(int bit_index) {
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
diff --git a/src/google/protobuf/compiler/javanano/javanano_helpers.h b/src/google/protobuf/compiler/javanano/javanano_helpers.h
index cddc077..753a4bd 100644
--- a/src/google/protobuf/compiler/javanano/javanano_helpers.h
+++ b/src/google/protobuf/compiler/javanano/javanano_helpers.h
@@ -141,30 +141,37 @@ string DefaultValue(const Params& params, const FieldDescriptor* field);
// Methods for shared bitfields.
-// Gets the name of the shared bitfield for the given index.
+// 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 the boolean value
-// of the bit of the shared bitfields for the given bit index.
-// Example: "((bitField1_ & 0x04) == 0x04)"
+// 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 of the shared
-// bitfields for the given bit index.
-// Example: "bitField1_ = (bitField1_ | 0x04)"
+// 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 of the shared
-// bitfields for the given bit index.
-// Example: "bitField1_ = (bitField1_ & ~0x04)"
+// 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);
-// Sets the 'get_*', 'set_*' and 'clear_*' variables, where * is the given bit
-// field name, to the appropriate Java expressions for the given 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);
diff --git a/src/google/protobuf/compiler/javanano/javanano_message.cc b/src/google/protobuf/compiler/javanano/javanano_message.cc
index c55ca55..63f8955 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_message.cc
@@ -198,6 +198,11 @@ void MessageGenerator::Generate(io::Printer* printer) {
GenerateClear(printer);
+ if (params_.generate_equals()) {
+ GenerateEquals(printer);
+ GenerateHashCode(printer);
+ }
+
// If we have an extension range, generate accessors for extensions.
if (params_.store_unknown_fields()
&& descriptor_->extension_range_count() > 0) {
@@ -326,11 +331,11 @@ void MessageGenerator::GenerateMergeFromMethods(io::Printer* printer) {
if (params_.store_unknown_fields()) {
printer->Print(
"if (unknownFieldData == null) {\n"
- " unknownFieldData = \n"
+ " unknownFieldData =\n"
" new java.util.ArrayList<com.google.protobuf.nano.UnknownFieldData>();\n"
"}\n"
- "if (!com.google.protobuf.nano.WireFormatNano.storeUnknownField(unknownFieldData, \n"
- " input, tag)) {\n"
+ "if (!com.google.protobuf.nano.WireFormatNano.storeUnknownField(\n"
+ " unknownFieldData, input, tag)) {\n"
" return this;\n"
"}\n");
} else {
@@ -427,6 +432,79 @@ void MessageGenerator::GenerateClear(io::Printer* printer) {
"}\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(
+ "if (unknownFieldData == null || unknownFieldData.isEmpty()) {\n"
+ " return other.unknownFieldData == null || other.unknownFieldData.isEmpty();"
+ "} else {\n"
+ " return unknownFieldData.equals(other.unknownFieldData);\n"
+ "}\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");
+ 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 + (unknownFieldData == null || unknownFieldData.isEmpty()\n"
+ " ? 0 : unknownFieldData.hashCode());\n");
+ }
+
+ printer->Print("return result;\n");
+
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
// ===================================================================
} // namespace javanano
diff --git a/src/google/protobuf/compiler/javanano/javanano_message.h b/src/google/protobuf/compiler/javanano/javanano_message.h
index d59ec9f..f87f84f 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message.h
+++ b/src/google/protobuf/compiler/javanano/javanano_message.h
@@ -36,9 +36,10 @@
#define GOOGLE_PROTOBUF_COMPILER_JAVA_MESSAGE_H__
#include <string>
-#include <google/protobuf/stubs/common.h>
-#include <google/protobuf/compiler/javanano/javanano_params.h>
+#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 {
@@ -76,6 +77,8 @@ class MessageGenerator {
const FieldDescriptor* field);
void GenerateClear(io::Printer* printer);
+ void GenerateEquals(io::Printer* printer);
+ void GenerateHashCode(io::Printer* printer);
const Params& params_;
const Descriptor* descriptor_;
diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.cc b/src/google/protobuf/compiler/javanano/javanano_message_field.cc
index 02253f9..9f8298c 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_message_field.cc
@@ -126,8 +126,25 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
"}\n");
}
-string MessageFieldGenerator::GetBoxedType() const {
- return ClassName(params_, descriptor_->message_type());
+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");
}
// ===================================================================
@@ -203,8 +220,22 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
"}\n");
}
-string AccessorMessageFieldGenerator::GetBoxedType() const {
- return ClassName(params_, descriptor_->message_type());
+void AccessorMessageFieldGenerator::
+GenerateEqualsCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "if ($name$_ == null) {\n"
+ " if (other.$name$_ != null) {\n"
+ " return false;\n"
+ " }\n"
+ "} else if (!$name$_.equals(other.$name$_)) {\n"
+ " return false;\n"
+ "}\n");
+}
+
+void AccessorMessageFieldGenerator::
+GenerateHashCodeCode(io::Printer* printer) const {
+ printer->Print(variables_,
+ "result = 31 * result + ($name$_ == null ? 0 : $name$_.hashCode());\n");
}
// ===================================================================
@@ -291,8 +322,20 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
"}\n");
}
-string RepeatedMessageFieldGenerator::GetBoxedType() const {
- return ClassName(params_, descriptor_->message_type());
+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
diff --git a/src/google/protobuf/compiler/javanano/javanano_message_field.h b/src/google/protobuf/compiler/javanano/javanano_message_field.h
index 9807513..b724351 100644
--- a/src/google/protobuf/compiler/javanano/javanano_message_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_message_field.h
@@ -55,8 +55,8 @@ class MessageFieldGenerator : public FieldGenerator {
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSerializationCode(io::Printer* printer) const;
void GenerateSerializedSizeCode(io::Printer* printer) const;
-
- string GetBoxedType() const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
private:
const FieldDescriptor* descriptor_;
@@ -77,8 +77,8 @@ class AccessorMessageFieldGenerator : public FieldGenerator {
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSerializationCode(io::Printer* printer) const;
void GenerateSerializedSizeCode(io::Printer* printer) const;
-
- string GetBoxedType() const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
private:
const FieldDescriptor* descriptor_;
@@ -99,8 +99,8 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSerializationCode(io::Printer* printer) const;
void GenerateSerializedSizeCode(io::Printer* printer) const;
-
- string GetBoxedType() const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
private:
const FieldDescriptor* descriptor_;
diff --git a/src/google/protobuf/compiler/javanano/javanano_params.h b/src/google/protobuf/compiler/javanano/javanano_params.h
index 6e5379c..24aece3 100644
--- a/src/google/protobuf/compiler/javanano/javanano_params.h
+++ b/src/google/protobuf/compiler/javanano/javanano_params.h
@@ -61,6 +61,7 @@ class Params {
bool java_enum_style_;
bool optional_field_accessors_;
bool use_reference_types_for_primitives_;
+ bool generate_equals_;
public:
Params(const string & base_name) :
@@ -71,7 +72,8 @@ class Params {
generate_has_(false),
java_enum_style_(false),
optional_field_accessors_(false),
- use_reference_types_for_primitives_(false) {
+ use_reference_types_for_primitives_(false),
+ generate_equals_(false) {
}
const string& base_name() const {
@@ -186,6 +188,13 @@ class Params {
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_;
+ }
};
} // namespace javanano
diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
index 0f7512a..cc5fd45 100644
--- a/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
+++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
@@ -404,8 +404,102 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
}
}
-string PrimitiveFieldGenerator::GetBoxedType() const {
- return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+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 {
+ 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;
+ }
+ }
}
// ===================================================================
@@ -483,8 +577,87 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
"}\n");
}
-string AccessorPrimitiveFieldGenerator::GetBoxedType() const {
- return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+void AccessorPrimitiveFieldGenerator::
+GenerateEqualsCode(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:
+ case JAVATYPE_LONG:
+ case JAVATYPE_FLOAT:
+ case JAVATYPE_DOUBLE:
+ 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;
+ }
}
// ===================================================================
@@ -629,8 +802,20 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
"}\n");
}
-string RepeatedPrimitiveFieldGenerator::GetBoxedType() const {
- return BoxedPrimitiveTypeName(GetJavaType(descriptor_));
+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
diff --git a/src/google/protobuf/compiler/javanano/javanano_primitive_field.h b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
index b42e2f3..2d2b268 100644
--- a/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
+++ b/src/google/protobuf/compiler/javanano/javanano_primitive_field.h
@@ -55,8 +55,8 @@ class PrimitiveFieldGenerator : public FieldGenerator {
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSerializationCode(io::Printer* printer) const;
void GenerateSerializedSizeCode(io::Printer* printer) const;
-
- string GetBoxedType() const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
private:
void GenerateSerializationConditional(io::Printer* printer) const;
@@ -79,8 +79,8 @@ class AccessorPrimitiveFieldGenerator : public FieldGenerator {
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSerializationCode(io::Printer* printer) const;
void GenerateSerializedSizeCode(io::Printer* printer) const;
-
- string GetBoxedType() const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
private:
const FieldDescriptor* descriptor_;
@@ -100,8 +100,8 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
void GenerateMergingCode(io::Printer* printer) const;
void GenerateSerializationCode(io::Printer* printer) const;
void GenerateSerializedSizeCode(io::Printer* printer) const;
-
- string GetBoxedType() const;
+ void GenerateEqualsCode(io::Printer* printer) const;
+ void GenerateHashCodeCode(io::Printer* printer) const;
private:
void GenerateRepeatedDataSizeCode(io::Printer* printer) const;