Bläddra i källkod

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

Ulas Kirazci 12 år sedan
förälder
incheckning
49e4bdc1eb

+ 26 - 0
java/src/test/java/com/google/protobuf/NanoTest.java

@@ -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.

+ 25 - 4
src/google/protobuf/compiler/javanano/javanano_helpers.cc

@@ -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:

+ 39 - 0
src/google/protobuf/compiler/javanano/javanano_primitive_field.cc

@@ -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");

+ 7 - 0
src/google/protobuf/unittest_nano.proto

@@ -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];