Allow NaN/+inf/-inf defaults in micro/nano.

Adds support for default values of NaN, infinity and negative
infinity for floats and doubles in both the nano and micro
java compiler.

Change-Id: Ibc43e5ebb073e51d9a8181f3aa23b72e10015dca
pull/91/head
Chris Smith 12 years ago
parent c01060c8ca
commit d98e9c4d0e
  1. 26
      java/src/test/java/com/google/protobuf/NanoTest.java
  2. 29
      src/google/protobuf/compiler/javanano/javanano_helpers.cc
  3. 39
      src/google/protobuf/compiler/javanano/javanano_primitive_field.cc
  4. 7
      src/google/protobuf/unittest_nano.proto

@ -2062,6 +2062,12 @@ public class NanoTest extends TestCase {
assertEquals(TestAllTypesNano.BAR, msg.defaultNestedEnum);
assertEquals(NanoOuterClass.FOREIGN_NANO_BAR, msg.defaultForeignEnum);
assertEquals(UnittestImportNano.IMPORT_NANO_BAR, msg.defaultImportEnum);
assertEquals(Float.POSITIVE_INFINITY, msg.defaultFloatInf);
assertEquals(Float.NEGATIVE_INFINITY, msg.defaultFloatNegInf);
assertEquals(Float.NaN, msg.defaultFloatNan);
assertEquals(Double.POSITIVE_INFINITY, msg.defaultDoubleInf);
assertEquals(Double.NEGATIVE_INFINITY, msg.defaultDoubleNegInf);
assertEquals(Double.NaN, msg.defaultDoubleNan);
// Default values are not output, except for required fields.
byte [] result = MessageNano.toByteArray(msg);
@ -2073,6 +2079,26 @@ public class NanoTest extends TestCase {
}
}
/**
* Tests that fields with a default value of NaN are not serialized when
* set to NaN. This is a special case as NaN != NaN, so normal equality
* checks don't work.
*/
public void testNanoNotANumberDefaults() throws Exception {
TestAllTypesNano msg = new TestAllTypesNano();
msg.defaultDoubleNan = 0;
msg.defaultFloatNan = 0;
byte[] result = MessageNano.toByteArray(msg);
int msgSerializedSize = msg.getSerializedSize();
assertTrue(msgSerializedSize > 3);
msg.defaultDoubleNan = Double.NaN;
msg.defaultFloatNan = Float.NaN;
result = MessageNano.toByteArray(msg);
msgSerializedSize = msg.getSerializedSize();
assertEquals(3, msgSerializedSize);
}
/**
* Test that a bug in skipRawBytes() has been fixed: if the skip skips
* exactly up to a limit, this should not break things.

@ -32,6 +32,7 @@
// 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>
@ -422,10 +423,30 @@ string DefaultValue(const Params& params, const FieldDescriptor* field) {
case FieldDescriptor::CPPTYPE_UINT64:
return SimpleItoa(static_cast<int64>(field->default_value_uint64())) +
"L";
case FieldDescriptor::CPPTYPE_DOUBLE:
return SimpleDtoa(field->default_value_double()) + "D";
case FieldDescriptor::CPPTYPE_FLOAT:
return SimpleFtoa(field->default_value_float()) + "F";
case FieldDescriptor::CPPTYPE_DOUBLE: {
double value = field->default_value_double();
if (value == numeric_limits<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:

@ -33,6 +33,7 @@
// Sanjay Ghemawat, Jeff Dean, and others.
#include <map>
#include <math.h>
#include <string>
#include <google/protobuf/compiler/javanano/javanano_primitive_field.h>
@ -174,6 +175,38 @@ int FixedSize(FieldDescriptor::Type type) {
return -1;
}
// Returns true if the field has a default value equal to NaN.
bool IsDefaultNaN(const FieldDescriptor* field) {
switch (field->type()) {
case FieldDescriptor::TYPE_INT32 : return false;
case FieldDescriptor::TYPE_UINT32 : return false;
case FieldDescriptor::TYPE_SINT32 : return false;
case FieldDescriptor::TYPE_FIXED32 : return false;
case FieldDescriptor::TYPE_SFIXED32: return false;
case FieldDescriptor::TYPE_INT64 : return false;
case FieldDescriptor::TYPE_UINT64 : return false;
case FieldDescriptor::TYPE_SINT64 : return false;
case FieldDescriptor::TYPE_FIXED64 : return false;
case FieldDescriptor::TYPE_SFIXED64: return false;
case FieldDescriptor::TYPE_FLOAT :
return isnan(field->default_value_float());
case FieldDescriptor::TYPE_DOUBLE :
return isnan(field->default_value_double());
case FieldDescriptor::TYPE_BOOL : return false;
case FieldDescriptor::TYPE_STRING : return false;
case FieldDescriptor::TYPE_BYTES : return false;
case FieldDescriptor::TYPE_ENUM : return false;
case FieldDescriptor::TYPE_GROUP : return false;
case FieldDescriptor::TYPE_MESSAGE : return false;
// No default because we want the compiler to complain if any new
// types are added.
}
GOOGLE_LOG(FATAL) << "Can't get here.";
return false;
}
// Return true if the type is a that has variable length
// for instance String's.
bool IsVariableLenType(JavaType type) {
@ -308,6 +341,9 @@ GenerateSerializationCode(io::Printer* printer) const {
} else if (IsReferenceType(GetJavaType(descriptor_))) {
printer->Print(variables_,
"if (!this.$name$.equals($default$)) {\n");
} else if (IsDefaultNaN(descriptor_)) {
printer->Print(variables_,
"if (!$capitalized_type$.isNaN(this.$name$)) {\n");
} else {
printer->Print(variables_,
"if (this.$name$ != $default$) {\n");
@ -332,6 +368,9 @@ GenerateSerializedSizeCode(io::Printer* printer) const {
} else if (IsReferenceType(GetJavaType(descriptor_))) {
printer->Print(variables_,
"if (!this.$name$.equals($default$)) {\n");
} else if (IsDefaultNaN(descriptor_)) {
printer->Print(variables_,
"if (!$capitalized_type$.isNaN(this.$name$)) {\n");
} else {
printer->Print(variables_,
"if (this.$name$ != $default$) {\n");

@ -142,6 +142,13 @@ message TestAllTypesNano {
optional string default_string_nonascii = 76 [default = "dünya"];
optional bytes default_bytes_nonascii = 77 [default = "dünyab"];
optional float default_float_inf = 97 [default = inf];
optional float default_float_neg_inf = 98 [default = -inf];
optional float default_float_nan = 99 [default = nan];
optional double default_double_inf = 100 [default = inf];
optional double default_double_neg_inf = 101 [default = -inf];
optional double default_double_nan = 102 [default = nan];
optional NestedEnum default_nested_enum = 81 [default = BAR];
optional ForeignEnumNano default_foreign_enum = 82
[default = FOREIGN_NANO_BAR];

Loading…
Cancel
Save