Add default NaN/Inf to C#, Java, Python (#5107)
authorVladimir Glavnyy <31897320+vglavnyy@users.noreply.github.com>
Mon, 14 Jan 2019 17:23:42 +0000 (00:23 +0700)
committerWouter van Oortmerssen <aardappel@gmail.com>
Mon, 14 Jan 2019 17:23:42 +0000 (09:23 -0800)
* Add default NaN/Inf to C#, Java, Python

* Python NaN/Inf test added

* Remove MSVC2010/13 dependent code

14 files changed:
include/flatbuffers/code_generators.h
src/code_generators.cpp
src/idl_gen_cpp.cpp
src/idl_gen_general.cpp
src/idl_gen_python.cpp
tests/JavaTest.java
tests/MyGame/MonsterExtra.cs [new file with mode: 0644]
tests/MyGame/MonsterExtra.java [new file with mode: 0644]
tests/MyGame/MonsterExtra.py [new file with mode: 0644]
tests/generate_code.bat
tests/generate_code.sh
tests/monster_extra.fbs
tests/monster_extra_generated.h
tests/py_test.py

index 8077d30..df09ca0 100644 (file)
@@ -136,27 +136,68 @@ class FloatConstantGenerator {
   std::string GenFloatConstant(const FieldDef &field) const;
 
  private:
+  virtual std::string Value(double v, const std::string &src) const = 0;
   virtual std::string Inf(double v) const = 0;
   virtual std::string NaN(double v) const = 0;
-  virtual std::string Value(double v, const std::string &src) const {
-    (void)v;
-    return src;
-  }
 
-  virtual std::string Inf(float v) const {
-    return this->Inf(static_cast<double>(v));
-  }
-  virtual std::string NaN(float v) const {
-    return this->NaN(static_cast<double>(v));
-  }
-  virtual std::string Value(float v, const std::string &src) const {
-    return this->Value(static_cast<double>(v), src);
-  }
+  virtual std::string Value(float v, const std::string &src) const = 0;
+  virtual std::string Inf(float v) const = 0;
+  virtual std::string NaN(float v) const = 0;
 
   template<typename T>
   std::string GenFloatConstantImpl(const FieldDef &field) const;
 };
 
+class SimpleFloatConstantGenerator : public FloatConstantGenerator {
+ public:
+  SimpleFloatConstantGenerator(const char *nan_number,
+                               const char *pos_inf_number,
+                               const char *neg_inf_number);
+
+ private:
+  std::string Value(double v,
+                    const std::string &src) const FLATBUFFERS_OVERRIDE;
+  std::string Inf(double v) const FLATBUFFERS_OVERRIDE;
+  std::string NaN(double v) const FLATBUFFERS_OVERRIDE;
+
+  std::string Value(float v, const std::string &src) const FLATBUFFERS_OVERRIDE;
+  std::string Inf(float v) const FLATBUFFERS_OVERRIDE;
+  std::string NaN(float v) const FLATBUFFERS_OVERRIDE;
+
+  const std::string nan_number_;
+  const std::string pos_inf_number_;
+  const std::string neg_inf_number_;
+};
+
+// C++, C#, Java like generator.
+class TypedFloatConstantGenerator : public FloatConstantGenerator {
+ public:
+  TypedFloatConstantGenerator(const char *double_prefix,
+                              const char *single_prefix, const char *nan_number,
+                              const char *pos_inf_number,
+                              const char *neg_inf_number = "");
+
+ private:
+  std::string Value(double v,
+                    const std::string &src) const FLATBUFFERS_OVERRIDE;
+  std::string Inf(double v) const FLATBUFFERS_OVERRIDE;
+
+  std::string NaN(double v) const FLATBUFFERS_OVERRIDE;
+
+  std::string Value(float v, const std::string &src) const FLATBUFFERS_OVERRIDE;
+  std::string Inf(float v) const FLATBUFFERS_OVERRIDE;
+  std::string NaN(float v) const FLATBUFFERS_OVERRIDE;
+
+  std::string MakeNaN(const std::string &prefix) const;
+  std::string MakeInf(bool neg, const std::string &prefix) const;
+
+  const std::string double_prefix_;
+  const std::string single_prefix_;
+  const std::string nan_number_;
+  const std::string pos_inf_number_;
+  const std::string neg_inf_number_;
+};
+
 }  // namespace flatbuffers
 
 #endif  // FLATBUFFERS_CODE_GENERATORS_H_
index b78b5ca..3b10db7 100644 (file)
@@ -188,6 +188,94 @@ std::string FloatConstantGenerator::GenFloatConstant(
   };
 }
 
+TypedFloatConstantGenerator::TypedFloatConstantGenerator(
+    const char *double_prefix, const char *single_prefix,
+    const char *nan_number, const char *pos_inf_number,
+    const char *neg_inf_number)
+    : double_prefix_(double_prefix),
+      single_prefix_(single_prefix),
+      nan_number_(nan_number),
+      pos_inf_number_(pos_inf_number),
+      neg_inf_number_(neg_inf_number) {}
+
+std::string TypedFloatConstantGenerator::MakeNaN(
+    const std::string &prefix) const {
+  return prefix + nan_number_;
+}
+std::string TypedFloatConstantGenerator::MakeInf(
+    bool neg, const std::string &prefix) const {
+  if (neg)
+    return !neg_inf_number_.empty() ? (prefix + neg_inf_number_)
+                                    : ("-" + prefix + pos_inf_number_);
+  else
+    return prefix + pos_inf_number_;
+}
+
+std::string TypedFloatConstantGenerator::Value(double v,
+                                               const std::string &src) const {
+  (void)v;
+  return src;
+}
+
+std::string TypedFloatConstantGenerator::Inf(double v) const {
+  return MakeInf(v < 0, double_prefix_);
+}
+
+std::string TypedFloatConstantGenerator::NaN(double v) const {
+  (void)v;
+  return MakeNaN(double_prefix_);
+}
+
+std::string TypedFloatConstantGenerator::Value(float v,
+                                               const std::string &src) const {
+  (void)v;
+  return src + "f";
+}
+
+std::string TypedFloatConstantGenerator::Inf(float v) const {
+  return MakeInf(v < 0, single_prefix_);
+}
+
+std::string TypedFloatConstantGenerator::NaN(float v) const {
+  (void)v;
+  return MakeNaN(single_prefix_);
+}
+
+SimpleFloatConstantGenerator::SimpleFloatConstantGenerator(
+    const char *nan_number, const char *pos_inf_number,
+    const char *neg_inf_number)
+    : nan_number_(nan_number),
+      pos_inf_number_(pos_inf_number),
+      neg_inf_number_(neg_inf_number) {}
+
+std::string SimpleFloatConstantGenerator::Value(double v,
+                                                const std::string &src) const {
+  (void)v;
+  return src;
+}
+
+std::string SimpleFloatConstantGenerator::Inf(double v) const {
+  return (v < 0) ? neg_inf_number_ : pos_inf_number_;
+}
+
+std::string SimpleFloatConstantGenerator::NaN(double v) const {
+  (void)v;
+  return nan_number_;
+}
+
+std::string SimpleFloatConstantGenerator::Value(float v,
+                                                const std::string &src) const {
+  return this->Value(static_cast<double>(v), src);
+}
+
+std::string SimpleFloatConstantGenerator::Inf(float v) const {
+  return this->Inf(static_cast<double>(v));
+}
+
+std::string SimpleFloatConstantGenerator::NaN(float v) const {
+  return this->NaN(static_cast<double>(v));
+}
+
 }  // namespace flatbuffers
 
 #if defined(_MSC_VER)
index 06896d9..9884081 100644 (file)
@@ -34,50 +34,15 @@ static std::string GeneratedFileName(const std::string &path,
 }
 
 namespace cpp {
-class CppFloatConstantGenerator : public FloatConstantGenerator {
- protected:
-  std::string Value(double v,
-                    const std::string &src) const FLATBUFFERS_OVERRIDE {
-    (void)v;
-    return src;
-  };
-
-  std::string Value(float v,
-                    const std::string &src) const FLATBUFFERS_OVERRIDE {
-    (void)v;
-    return src + "f";
-  }
-
-  std::string NaN(double v) const FLATBUFFERS_OVERRIDE {
-    (void)v;
-    return "std::numeric_limits<double>::quiet_NaN()";
-  }
-  std::string NaN(float v) const FLATBUFFERS_OVERRIDE {
-    (void)v;
-    return "std::numeric_limits<float>::quiet_NaN()";
-  }
-
-  std::string Inf(double v) const FLATBUFFERS_OVERRIDE {
-    if(v < 0)
-      return "-std::numeric_limits<double>::infinity()";
-    else
-      return "std::numeric_limits<double>::infinity()";
-  }
-
-  std::string Inf(float v) const FLATBUFFERS_OVERRIDE {
-    if (v < 0)
-      return "-std::numeric_limits<float>::infinity()";
-    else
-      return "std::numeric_limits<float>::infinity()";
-  }
-};
-
 class CppGenerator : public BaseGenerator {
  public:
   CppGenerator(const Parser &parser, const std::string &path,
                const std::string &file_name)
       : BaseGenerator(parser, path, file_name, "", "::"),
-        cur_name_space_(nullptr) {
+        cur_name_space_(nullptr),
+        float_const_gen_("std::numeric_limits<double>::",
+                         "std::numeric_limits<float>::", "quiet_NaN()",
+                         "infinity()") {
     static const char * const keywords[] = {
                                "alignas",
                                "alignof",
@@ -2785,7 +2750,7 @@ class CppGenerator : public BaseGenerator {
     cur_name_space_ = ns;
   }
 
-  const CppFloatConstantGenerator float_const_gen_;
+  const TypedFloatConstantGenerator float_const_gen_;
 };
 
 }  // namespace cpp
index 66984da..7c34ee2 100644 (file)
@@ -58,9 +58,16 @@ struct LanguageParameters {
   std::string class_annotation;
   std::string generated_type_annotation;
   CommentConfig comment_config;
+  const FloatConstantGenerator *float_gen;
 };
 
 const LanguageParameters &GetLangParams(IDLOptions::Language lang) {
+  static TypedFloatConstantGenerator CSharpFloatGen(
+      "Double.", "Single.", "NaN", "PositiveInfinity", "NegativeInfinity");
+
+  static TypedFloatConstantGenerator JavaFloatGen(
+      "Double.", "Float.", "NaN", "POSITIVE_INFINITY", "NEGATIVE_INFINITY");
+
   static const LanguageParameters language_parameters[] = {
     {
         IDLOptions::kJava,
@@ -95,6 +102,7 @@ const LanguageParameters &GetLangParams(IDLOptions::Language lang) {
             " *",
             " */",
         },
+        &JavaFloatGen
     },
     {
         IDLOptions::kCSharp,
@@ -128,6 +136,7 @@ const LanguageParameters &GetLangParams(IDLOptions::Language lang) {
             "///",
             nullptr,
         },
+        &CSharpFloatGen
     },
   };
 
@@ -429,7 +438,8 @@ class GeneralGenerator : public BaseGenerator {
     return SourceCastBasic(type, true);
   }
 
-  std::string GenEnumDefaultValue(const Value &value) const {
+  std::string GenEnumDefaultValue(const FieldDef &field) const {
+    auto& value = field.value;
     auto enum_def = value.type.enum_def;
     auto vec = enum_def->vals.vec;
     auto default_value = StringToInt(value.constant.c_str());
@@ -446,19 +456,19 @@ class GeneralGenerator : public BaseGenerator {
     return result;
   }
 
-  std::string GenDefaultValue(const Value &value, bool enableLangOverrides) const {
+  std::string GenDefaultValue(const FieldDef &field, bool enableLangOverrides) const {
+    auto& value = field.value;
     if (enableLangOverrides) {
       // handles both enum case and vector of enum case
       if (lang_.language == IDLOptions::kCSharp &&
           value.type.enum_def != nullptr &&
           value.type.base_type != BASE_TYPE_UNION) {
-        return GenEnumDefaultValue(value);
+        return GenEnumDefaultValue(field);
       }
     }
 
     auto longSuffix = lang_.language == IDLOptions::kJava ? "L" : "";
     switch (value.type.base_type) {
-      case BASE_TYPE_FLOAT: return value.constant + "f";
       case BASE_TYPE_BOOL: return value.constant == "0" ? "false" : "true";
       case BASE_TYPE_ULONG: {
         if (lang_.language != IDLOptions::kJava) return value.constant;
@@ -468,16 +478,21 @@ class GeneralGenerator : public BaseGenerator {
       }
       case BASE_TYPE_UINT:
       case BASE_TYPE_LONG: return value.constant + longSuffix;
-      default: return value.constant;
+      default:
+        if(IsFloat(value.type.base_type))
+          return lang_.float_gen->GenFloatConstant(field);
+        else
+          return value.constant;
     }
   }
 
-  std::string GenDefaultValue(const Value &value) const {
-    return GenDefaultValue(value, true);
+  std::string GenDefaultValue(const FieldDef &field) const {
+    return GenDefaultValue(field, true);
   }
 
-  std::string GenDefaultValueBasic(const Value &value,
+  std::string GenDefaultValueBasic(const FieldDef &field,
                                    bool enableLangOverrides) const {
+    auto& value = field.value;
     if (!IsScalar(value.type.base_type)) {
       if (enableLangOverrides) {
         if (lang_.language == IDLOptions::kCSharp) {
@@ -493,11 +508,11 @@ class GeneralGenerator : public BaseGenerator {
       }
       return "0";
     }
-    return GenDefaultValue(value, enableLangOverrides);
+    return GenDefaultValue(field, enableLangOverrides);
   }
 
-  std::string GenDefaultValueBasic(const Value &value) const {
-    return GenDefaultValueBasic(value, true);
+  std::string GenDefaultValueBasic(const FieldDef &field) const {
+    return GenDefaultValueBasic(field, true);
   }
 
   void GenEnum(EnumDef &enum_def, std::string *code_ptr) const {
@@ -956,7 +971,7 @@ class GeneralGenerator : public BaseGenerator {
           code += offset_prefix + getter;
           code += "(o + " + lang_.accessor_prefix + "bb_pos)" + dest_mask;
           code += " : " + default_cast;
-          code += GenDefaultValue(field.value);
+          code += GenDefaultValue(field);
         }
       } else {
         switch (field.value.type.base_type) {
@@ -1278,7 +1293,7 @@ class GeneralGenerator : public BaseGenerator {
           // supply all arguments, and thus won't compile when fields are added.
           if (lang_.language != IDLOptions::kJava) {
             code += " = ";
-            code += GenDefaultValueBasic(field.value);
+            code += GenDefaultValueBasic(field);
           }
         }
         code += ") {\n    builder.";
@@ -1338,7 +1353,7 @@ class GeneralGenerator : public BaseGenerator {
         code += ", ";
         if (lang_.language == IDLOptions::kJava)
           code += SourceCastBasic(field.value.type);
-        code += GenDefaultValue(field.value, false);
+        code += GenDefaultValue(field, false);
         code += "); }\n";
         if (field.value.type.base_type == BASE_TYPE_VECTOR) {
           auto vector_type = field.value.type.VectorType();
index 11491c0..fbb0805 100644 (file)
@@ -36,7 +36,8 @@ class PythonGenerator : public BaseGenerator {
   PythonGenerator(const Parser &parser, const std::string &path,
                   const std::string &file_name)
       : BaseGenerator(parser, path, file_name, "" /* not used */,
-                      "" /* not used */){
+                      "" /* not used */),
+        float_const_gen_("float('nan')", "float('inf')", "float('-inf')") {
     static const char * const keywords[] = {
       "False",
       "None",
@@ -191,7 +192,7 @@ class PythonGenerator : public BaseGenerator {
     code += "(self):";
     code += OffsetPrefix(field);
     getter += "o + self._tab.Pos)";
-    auto is_bool = field.value.type.base_type == BASE_TYPE_BOOL;
+    auto is_bool = IsBool(field.value.type.base_type);
     if (is_bool) {
       getter = "bool(" + getter + ")";
     }
@@ -200,7 +201,9 @@ class PythonGenerator : public BaseGenerator {
     if (is_bool) {
       default_value = field.value.constant == "0" ? "False" : "True";
     } else {
-      default_value = field.value.constant;
+      default_value = IsFloat(field.value.type.base_type)
+                          ? float_const_gen_.GenFloatConstant(field)
+                          : field.value.constant;
     }
     code += Indent + Indent + "return " + default_value + "\n\n";
   }
@@ -452,7 +455,10 @@ class PythonGenerator : public BaseGenerator {
     } else {
       code += MakeCamel(NormalizedName(field), false);
     }
-    code += ", " + field.value.constant;
+    code += ", ";
+    code += IsFloat(field.value.type.base_type)
+                ? float_const_gen_.GenFloatConstant(field)
+                : field.value.constant;
     code += ")\n";
   }
 
@@ -715,6 +721,7 @@ class PythonGenerator : public BaseGenerator {
   }
  private:
   std::unordered_set<std::string> keywords_;
+  const SimpleFloatConstantGenerator float_const_gen_;
 };
 
 }  // namespace python
index 3aead29..7d96f06 100644 (file)
@@ -24,6 +24,7 @@ import NamespaceA.NamespaceB.*;
 import com.google.flatbuffers.ByteBufferUtil;
 import static com.google.flatbuffers.Constants.*;
 import com.google.flatbuffers.FlatBufferBuilder;
+import MyGame.MonsterExtra;
 
 class JavaTest {
     public static void main(String[] args) {
diff --git a/tests/MyGame/MonsterExtra.cs b/tests/MyGame/MonsterExtra.cs
new file mode 100644 (file)
index 0000000..fc9a323
--- /dev/null
@@ -0,0 +1,64 @@
+// <auto-generated>
+//  automatically generated by the FlatBuffers compiler, do not modify
+// </auto-generated>
+
+namespace MyGame
+{
+
+using global::System;
+using global::FlatBuffers;
+
+public struct MonsterExtra : IFlatbufferObject
+{
+  private Table __p;
+  public ByteBuffer ByteBuffer { get { return __p.bb; } }
+  public static MonsterExtra GetRootAsMonsterExtra(ByteBuffer _bb) { return GetRootAsMonsterExtra(_bb, new MonsterExtra()); }
+  public static MonsterExtra GetRootAsMonsterExtra(ByteBuffer _bb, MonsterExtra obj) { return (obj.__assign(_bb.GetInt(_bb.Position) + _bb.Position, _bb)); }
+  public void __init(int _i, ByteBuffer _bb) { __p.bb_pos = _i; __p.bb = _bb; }
+  public MonsterExtra __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+  public float TestfNan { get { int o = __p.__offset(4); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)Single.NaN; } }
+  public bool MutateTestfNan(float testf_nan) { int o = __p.__offset(4); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, testf_nan); return true; } else { return false; } }
+  public float TestfPinf { get { int o = __p.__offset(6); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)Single.PositiveInfinity; } }
+  public bool MutateTestfPinf(float testf_pinf) { int o = __p.__offset(6); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, testf_pinf); return true; } else { return false; } }
+  public float TestfNinf { get { int o = __p.__offset(8); return o != 0 ? __p.bb.GetFloat(o + __p.bb_pos) : (float)Single.NegativeInfinity; } }
+  public bool MutateTestfNinf(float testf_ninf) { int o = __p.__offset(8); if (o != 0) { __p.bb.PutFloat(o + __p.bb_pos, testf_ninf); return true; } else { return false; } }
+  public double TestdNan { get { int o = __p.__offset(10); return o != 0 ? __p.bb.GetDouble(o + __p.bb_pos) : (double)Double.NaN; } }
+  public bool MutateTestdNan(double testd_nan) { int o = __p.__offset(10); if (o != 0) { __p.bb.PutDouble(o + __p.bb_pos, testd_nan); return true; } else { return false; } }
+  public double TestdPinf { get { int o = __p.__offset(12); return o != 0 ? __p.bb.GetDouble(o + __p.bb_pos) : (double)Double.PositiveInfinity; } }
+  public bool MutateTestdPinf(double testd_pinf) { int o = __p.__offset(12); if (o != 0) { __p.bb.PutDouble(o + __p.bb_pos, testd_pinf); return true; } else { return false; } }
+  public double TestdNinf { get { int o = __p.__offset(14); return o != 0 ? __p.bb.GetDouble(o + __p.bb_pos) : (double)Double.NegativeInfinity; } }
+  public bool MutateTestdNinf(double testd_ninf) { int o = __p.__offset(14); if (o != 0) { __p.bb.PutDouble(o + __p.bb_pos, testd_ninf); return true; } else { return false; } }
+
+  public static Offset<MonsterExtra> CreateMonsterExtra(FlatBufferBuilder builder,
+      float testf_nan = Single.NaN,
+      float testf_pinf = Single.PositiveInfinity,
+      float testf_ninf = Single.NegativeInfinity,
+      double testd_nan = Double.NaN,
+      double testd_pinf = Double.PositiveInfinity,
+      double testd_ninf = Double.NegativeInfinity) {
+    builder.StartObject(6);
+    MonsterExtra.AddTestdNinf(builder, testd_ninf);
+    MonsterExtra.AddTestdPinf(builder, testd_pinf);
+    MonsterExtra.AddTestdNan(builder, testd_nan);
+    MonsterExtra.AddTestfNinf(builder, testf_ninf);
+    MonsterExtra.AddTestfPinf(builder, testf_pinf);
+    MonsterExtra.AddTestfNan(builder, testf_nan);
+    return MonsterExtra.EndMonsterExtra(builder);
+  }
+
+  public static void StartMonsterExtra(FlatBufferBuilder builder) { builder.StartObject(6); }
+  public static void AddTestfNan(FlatBufferBuilder builder, float testfNan) { builder.AddFloat(0, testfNan, Single.NaN); }
+  public static void AddTestfPinf(FlatBufferBuilder builder, float testfPinf) { builder.AddFloat(1, testfPinf, Single.PositiveInfinity); }
+  public static void AddTestfNinf(FlatBufferBuilder builder, float testfNinf) { builder.AddFloat(2, testfNinf, Single.NegativeInfinity); }
+  public static void AddTestdNan(FlatBufferBuilder builder, double testdNan) { builder.AddDouble(3, testdNan, Double.NaN); }
+  public static void AddTestdPinf(FlatBufferBuilder builder, double testdPinf) { builder.AddDouble(4, testdPinf, Double.PositiveInfinity); }
+  public static void AddTestdNinf(FlatBufferBuilder builder, double testdNinf) { builder.AddDouble(5, testdNinf, Double.NegativeInfinity); }
+  public static Offset<MonsterExtra> EndMonsterExtra(FlatBufferBuilder builder) {
+    int o = builder.EndObject();
+    return new Offset<MonsterExtra>(o);
+  }
+};
+
+
+}
diff --git a/tests/MyGame/MonsterExtra.java b/tests/MyGame/MonsterExtra.java
new file mode 100644 (file)
index 0000000..6070efd
--- /dev/null
@@ -0,0 +1,58 @@
+// automatically generated by the FlatBuffers compiler, do not modify
+
+package MyGame;
+
+import java.nio.*;
+import java.lang.*;
+import java.util.*;
+import com.google.flatbuffers.*;
+
+@SuppressWarnings("unused")public final class MonsterExtra extends Table {
+  public static MonsterExtra getRootAsMonsterExtra(ByteBuffer _bb) { return getRootAsMonsterExtra(_bb, new MonsterExtra()); }
+  public static MonsterExtra getRootAsMonsterExtra(ByteBuffer _bb, MonsterExtra obj) { _bb.order(ByteOrder.LITTLE_ENDIAN); return (obj.__assign(_bb.getInt(_bb.position()) + _bb.position(), _bb)); }
+  public void __init(int _i, ByteBuffer _bb) { bb_pos = _i; bb = _bb; }
+  public MonsterExtra __assign(int _i, ByteBuffer _bb) { __init(_i, _bb); return this; }
+
+  public float testfNan() { int o = __offset(4); return o != 0 ? bb.getFloat(o + bb_pos) : Float.NaN; }
+  public boolean mutateTestfNan(float testf_nan) { int o = __offset(4); if (o != 0) { bb.putFloat(o + bb_pos, testf_nan); return true; } else { return false; } }
+  public float testfPinf() { int o = __offset(6); return o != 0 ? bb.getFloat(o + bb_pos) : Float.POSITIVE_INFINITY; }
+  public boolean mutateTestfPinf(float testf_pinf) { int o = __offset(6); if (o != 0) { bb.putFloat(o + bb_pos, testf_pinf); return true; } else { return false; } }
+  public float testfNinf() { int o = __offset(8); return o != 0 ? bb.getFloat(o + bb_pos) : Float.NEGATIVE_INFINITY; }
+  public boolean mutateTestfNinf(float testf_ninf) { int o = __offset(8); if (o != 0) { bb.putFloat(o + bb_pos, testf_ninf); return true; } else { return false; } }
+  public double testdNan() { int o = __offset(10); return o != 0 ? bb.getDouble(o + bb_pos) : Double.NaN; }
+  public boolean mutateTestdNan(double testd_nan) { int o = __offset(10); if (o != 0) { bb.putDouble(o + bb_pos, testd_nan); return true; } else { return false; } }
+  public double testdPinf() { int o = __offset(12); return o != 0 ? bb.getDouble(o + bb_pos) : Double.POSITIVE_INFINITY; }
+  public boolean mutateTestdPinf(double testd_pinf) { int o = __offset(12); if (o != 0) { bb.putDouble(o + bb_pos, testd_pinf); return true; } else { return false; } }
+  public double testdNinf() { int o = __offset(14); return o != 0 ? bb.getDouble(o + bb_pos) : Double.NEGATIVE_INFINITY; }
+  public boolean mutateTestdNinf(double testd_ninf) { int o = __offset(14); if (o != 0) { bb.putDouble(o + bb_pos, testd_ninf); return true; } else { return false; } }
+
+  public static int createMonsterExtra(FlatBufferBuilder builder,
+      float testf_nan,
+      float testf_pinf,
+      float testf_ninf,
+      double testd_nan,
+      double testd_pinf,
+      double testd_ninf) {
+    builder.startObject(6);
+    MonsterExtra.addTestdNinf(builder, testd_ninf);
+    MonsterExtra.addTestdPinf(builder, testd_pinf);
+    MonsterExtra.addTestdNan(builder, testd_nan);
+    MonsterExtra.addTestfNinf(builder, testf_ninf);
+    MonsterExtra.addTestfPinf(builder, testf_pinf);
+    MonsterExtra.addTestfNan(builder, testf_nan);
+    return MonsterExtra.endMonsterExtra(builder);
+  }
+
+  public static void startMonsterExtra(FlatBufferBuilder builder) { builder.startObject(6); }
+  public static void addTestfNan(FlatBufferBuilder builder, float testfNan) { builder.addFloat(0, testfNan, Float.NaN); }
+  public static void addTestfPinf(FlatBufferBuilder builder, float testfPinf) { builder.addFloat(1, testfPinf, Float.POSITIVE_INFINITY); }
+  public static void addTestfNinf(FlatBufferBuilder builder, float testfNinf) { builder.addFloat(2, testfNinf, Float.NEGATIVE_INFINITY); }
+  public static void addTestdNan(FlatBufferBuilder builder, double testdNan) { builder.addDouble(3, testdNan, Double.NaN); }
+  public static void addTestdPinf(FlatBufferBuilder builder, double testdPinf) { builder.addDouble(4, testdPinf, Double.POSITIVE_INFINITY); }
+  public static void addTestdNinf(FlatBufferBuilder builder, double testdNinf) { builder.addDouble(5, testdNinf, Double.NEGATIVE_INFINITY); }
+  public static int endMonsterExtra(FlatBufferBuilder builder) {
+    int o = builder.endObject();
+    return o;
+  }
+}
+
diff --git a/tests/MyGame/MonsterExtra.py b/tests/MyGame/MonsterExtra.py
new file mode 100644 (file)
index 0000000..3e8b26d
--- /dev/null
@@ -0,0 +1,70 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: MyGame
+
+import flatbuffers
+
+class MonsterExtra(object):
+    __slots__ = ['_tab']
+
+    @classmethod
+    def GetRootAsMonsterExtra(cls, buf, offset):
+        n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, offset)
+        x = MonsterExtra()
+        x.Init(buf, n + offset)
+        return x
+
+    # MonsterExtra
+    def Init(self, buf, pos):
+        self._tab = flatbuffers.table.Table(buf, pos)
+
+    # MonsterExtra
+    def TestfNan(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(4))
+        if o != 0:
+            return self._tab.Get(flatbuffers.number_types.Float32Flags, o + self._tab.Pos)
+        return float('nan')
+
+    # MonsterExtra
+    def TestfPinf(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(6))
+        if o != 0:
+            return self._tab.Get(flatbuffers.number_types.Float32Flags, o + self._tab.Pos)
+        return float('inf')
+
+    # MonsterExtra
+    def TestfNinf(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(8))
+        if o != 0:
+            return self._tab.Get(flatbuffers.number_types.Float32Flags, o + self._tab.Pos)
+        return float('-inf')
+
+    # MonsterExtra
+    def TestdNan(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(10))
+        if o != 0:
+            return self._tab.Get(flatbuffers.number_types.Float64Flags, o + self._tab.Pos)
+        return float('nan')
+
+    # MonsterExtra
+    def TestdPinf(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(12))
+        if o != 0:
+            return self._tab.Get(flatbuffers.number_types.Float64Flags, o + self._tab.Pos)
+        return float('inf')
+
+    # MonsterExtra
+    def TestdNinf(self):
+        o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(14))
+        if o != 0:
+            return self._tab.Get(flatbuffers.number_types.Float64Flags, o + self._tab.Pos)
+        return float('-inf')
+
+def MonsterExtraStart(builder): builder.StartObject(6)
+def MonsterExtraAddTestfNan(builder, testfNan): builder.PrependFloat32Slot(0, testfNan, float('nan'))
+def MonsterExtraAddTestfPinf(builder, testfPinf): builder.PrependFloat32Slot(1, testfPinf, float('inf'))
+def MonsterExtraAddTestfNinf(builder, testfNinf): builder.PrependFloat32Slot(2, testfNinf, float('-inf'))
+def MonsterExtraAddTestdNan(builder, testdNan): builder.PrependFloat64Slot(3, testdNan, float('nan'))
+def MonsterExtraAddTestdPinf(builder, testdPinf): builder.PrependFloat64Slot(4, testdPinf, float('inf'))
+def MonsterExtraAddTestdNinf(builder, testdNinf): builder.PrependFloat64Slot(5, testdNinf, float('-inf'))
+def MonsterExtraEnd(builder): return builder.EndObject()
index d2e8364..fed9c76 100644 (file)
@@ -23,7 +23,7 @@ if "%1"=="-b" set buildtype=%2
 
 IF NOT "%MONSTER_EXTRA%"=="skip" (
   @echo Generate MosterExtra
-  ..\%buildtype%\flatc.exe --cpp --gen-mutable --reflect-names --gen-object-api --gen-compare --no-includes monster_extra.fbs || goto FAIL
+  ..\%buildtype%\flatc.exe --cpp --java --csharp --python --gen-mutable --reflect-names --gen-object-api --gen-compare --no-includes monster_extra.fbs || goto FAIL
 ) else (
   @echo monster_extra.fbs skipped (the strtod function from MSVC2013 or older doesn't support NaN/Inf arguments)
 )
index 6a3a8f8..499e31a 100755 (executable)
@@ -20,7 +20,7 @@ set -e
 ../flatc --cpp --js --ts --php --gen-mutable --reflect-names --gen-object-api --gen-compare --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs
 ../flatc -b --schema --bfbs-comments --bfbs-builtins -I include_test monster_test.fbs
 ../flatc --jsonschema --schema -I include_test monster_test.fbs
-../flatc --cpp --gen-mutable --reflect-names --gen-object-api --gen-compare --no-includes monster_extra.fbs || goto FAIL
+../flatc --cpp --java --csharp --python --gen-mutable --reflect-names --gen-object-api --gen-compare --no-includes monster_extra.fbs || goto FAIL
 cd ../samples
 ../flatc --cpp --lobster --gen-mutable --reflect-names --gen-object-api --gen-compare --cpp-ptr-type flatbuffers::unique_ptr monster.fbs
 ../flatc -b --schema --bfbs-comments --bfbs-builtins monster.fbs
index 2518f5b..89f1cc8 100644 (file)
@@ -1,7 +1,7 @@
 namespace MyGame;
 
 // Not all programmining languages support this extra table.
-table MonsterExra {
+table MonsterExtra {
   // Float-point values with NaN and Inf defaults.
   testf_nan:float = nan;
   testf_pinf:float = +inf;
index 0dad3b0..ac316d6 100644 (file)
@@ -8,22 +8,22 @@
 
 namespace MyGame {
 
-struct MonsterExra;
-struct MonsterExraT;
+struct MonsterExtra;
+struct MonsterExtraT;
 
-bool operator==(const MonsterExraT &lhs, const MonsterExraT &rhs);
+bool operator==(const MonsterExtraT &lhs, const MonsterExtraT &rhs);
 
-inline const flatbuffers::TypeTable *MonsterExraTypeTable();
+inline const flatbuffers::TypeTable *MonsterExtraTypeTable();
 
-struct MonsterExraT : public flatbuffers::NativeTable {
-  typedef MonsterExra TableType;
+struct MonsterExtraT : public flatbuffers::NativeTable {
+  typedef MonsterExtra TableType;
   float testf_nan;
   float testf_pinf;
   float testf_ninf;
   double testd_nan;
   double testd_pinf;
   double testd_ninf;
-  MonsterExraT()
+  MonsterExtraT()
       : testf_nan(std::numeric_limits<float>::quiet_NaN()),
         testf_pinf(std::numeric_limits<float>::infinity()),
         testf_ninf(-std::numeric_limits<float>::infinity()),
@@ -33,7 +33,7 @@ struct MonsterExraT : public flatbuffers::NativeTable {
   }
 };
 
-inline bool operator==(const MonsterExraT &lhs, const MonsterExraT &rhs) {
+inline bool operator==(const MonsterExtraT &lhs, const MonsterExtraT &rhs) {
   return
       (lhs.testf_nan == rhs.testf_nan) &&
       (lhs.testf_pinf == rhs.testf_pinf) &&
@@ -43,10 +43,10 @@ inline bool operator==(const MonsterExraT &lhs, const MonsterExraT &rhs) {
       (lhs.testd_ninf == rhs.testd_ninf);
 }
 
-struct MonsterExra FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
-  typedef MonsterExraT NativeTableType;
+struct MonsterExtra FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+  typedef MonsterExtraT NativeTableType;
   static const flatbuffers::TypeTable *MiniReflectTypeTable() {
-    return MonsterExraTypeTable();
+    return MonsterExtraTypeTable();
   }
   enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
     VT_TESTF_NAN = 4,
@@ -102,45 +102,45 @@ struct MonsterExra FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
            VerifyField<double>(verifier, VT_TESTD_NINF) &&
            verifier.EndTable();
   }
-  MonsterExraT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
-  void UnPackTo(MonsterExraT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
-  static flatbuffers::Offset<MonsterExra> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterExraT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+  MonsterExtraT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+  void UnPackTo(MonsterExtraT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+  static flatbuffers::Offset<MonsterExtra> Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterExtraT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
 };
 
-struct MonsterExraBuilder {
+struct MonsterExtraBuilder {
   flatbuffers::FlatBufferBuilder &fbb_;
   flatbuffers::uoffset_t start_;
   void add_testf_nan(float testf_nan) {
-    fbb_.AddElement<float>(MonsterExra::VT_TESTF_NAN, testf_nan, std::numeric_limits<float>::quiet_NaN());
+    fbb_.AddElement<float>(MonsterExtra::VT_TESTF_NAN, testf_nan, std::numeric_limits<float>::quiet_NaN());
   }
   void add_testf_pinf(float testf_pinf) {
-    fbb_.AddElement<float>(MonsterExra::VT_TESTF_PINF, testf_pinf, std::numeric_limits<float>::infinity());
+    fbb_.AddElement<float>(MonsterExtra::VT_TESTF_PINF, testf_pinf, std::numeric_limits<float>::infinity());
   }
   void add_testf_ninf(float testf_ninf) {
-    fbb_.AddElement<float>(MonsterExra::VT_TESTF_NINF, testf_ninf, -std::numeric_limits<float>::infinity());
+    fbb_.AddElement<float>(MonsterExtra::VT_TESTF_NINF, testf_ninf, -std::numeric_limits<float>::infinity());
   }
   void add_testd_nan(double testd_nan) {
-    fbb_.AddElement<double>(MonsterExra::VT_TESTD_NAN, testd_nan, std::numeric_limits<double>::quiet_NaN());
+    fbb_.AddElement<double>(MonsterExtra::VT_TESTD_NAN, testd_nan, std::numeric_limits<double>::quiet_NaN());
   }
   void add_testd_pinf(double testd_pinf) {
-    fbb_.AddElement<double>(MonsterExra::VT_TESTD_PINF, testd_pinf, std::numeric_limits<double>::infinity());
+    fbb_.AddElement<double>(MonsterExtra::VT_TESTD_PINF, testd_pinf, std::numeric_limits<double>::infinity());
   }
   void add_testd_ninf(double testd_ninf) {
-    fbb_.AddElement<double>(MonsterExra::VT_TESTD_NINF, testd_ninf, -std::numeric_limits<double>::infinity());
+    fbb_.AddElement<double>(MonsterExtra::VT_TESTD_NINF, testd_ninf, -std::numeric_limits<double>::infinity());
   }
-  explicit MonsterExraBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+  explicit MonsterExtraBuilder(flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
   }
-  MonsterExraBuilder &operator=(const MonsterExraBuilder &);
-  flatbuffers::Offset<MonsterExra> Finish() {
+  MonsterExtraBuilder &operator=(const MonsterExtraBuilder &);
+  flatbuffers::Offset<MonsterExtra> Finish() {
     const auto end = fbb_.EndTable(start_);
-    auto o = flatbuffers::Offset<MonsterExra>(end);
+    auto o = flatbuffers::Offset<MonsterExtra>(end);
     return o;
   }
 };
 
-inline flatbuffers::Offset<MonsterExra> CreateMonsterExra(
+inline flatbuffers::Offset<MonsterExtra> CreateMonsterExtra(
     flatbuffers::FlatBufferBuilder &_fbb,
     float testf_nan = std::numeric_limits<float>::quiet_NaN(),
     float testf_pinf = std::numeric_limits<float>::infinity(),
@@ -148,7 +148,7 @@ inline flatbuffers::Offset<MonsterExra> CreateMonsterExra(
     double testd_nan = std::numeric_limits<double>::quiet_NaN(),
     double testd_pinf = std::numeric_limits<double>::infinity(),
     double testd_ninf = -std::numeric_limits<double>::infinity()) {
-  MonsterExraBuilder builder_(_fbb);
+  MonsterExtraBuilder builder_(_fbb);
   builder_.add_testd_ninf(testd_ninf);
   builder_.add_testd_pinf(testd_pinf);
   builder_.add_testd_nan(testd_nan);
@@ -158,15 +158,15 @@ inline flatbuffers::Offset<MonsterExra> CreateMonsterExra(
   return builder_.Finish();
 }
 
-flatbuffers::Offset<MonsterExra> CreateMonsterExra(flatbuffers::FlatBufferBuilder &_fbb, const MonsterExraT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+flatbuffers::Offset<MonsterExtra> CreateMonsterExtra(flatbuffers::FlatBufferBuilder &_fbb, const MonsterExtraT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
 
-inline MonsterExraT *MonsterExra::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
-  auto _o = new MonsterExraT();
+inline MonsterExtraT *MonsterExtra::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+  auto _o = new MonsterExtraT();
   UnPackTo(_o, _resolver);
   return _o;
 }
 
-inline void MonsterExra::UnPackTo(MonsterExraT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+inline void MonsterExtra::UnPackTo(MonsterExtraT *_o, const flatbuffers::resolver_function_t *_resolver) const {
   (void)_o;
   (void)_resolver;
   { auto _e = testf_nan(); _o->testf_nan = _e; };
@@ -177,21 +177,21 @@ inline void MonsterExra::UnPackTo(MonsterExraT *_o, const flatbuffers::resolver_
   { auto _e = testd_ninf(); _o->testd_ninf = _e; };
 }
 
-inline flatbuffers::Offset<MonsterExra> MonsterExra::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterExraT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
-  return CreateMonsterExra(_fbb, _o, _rehasher);
+inline flatbuffers::Offset<MonsterExtra> MonsterExtra::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MonsterExtraT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+  return CreateMonsterExtra(_fbb, _o, _rehasher);
 }
 
-inline flatbuffers::Offset<MonsterExra> CreateMonsterExra(flatbuffers::FlatBufferBuilder &_fbb, const MonsterExraT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+inline flatbuffers::Offset<MonsterExtra> CreateMonsterExtra(flatbuffers::FlatBufferBuilder &_fbb, const MonsterExtraT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
   (void)_rehasher;
   (void)_o;
-  struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MonsterExraT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
+  struct _VectorArgs { flatbuffers::FlatBufferBuilder *__fbb; const MonsterExtraT* __o; const flatbuffers::rehasher_function_t *__rehasher; } _va = { &_fbb, _o, _rehasher}; (void)_va;
   auto _testf_nan = _o->testf_nan;
   auto _testf_pinf = _o->testf_pinf;
   auto _testf_ninf = _o->testf_ninf;
   auto _testd_nan = _o->testd_nan;
   auto _testd_pinf = _o->testd_pinf;
   auto _testd_ninf = _o->testd_ninf;
-  return MyGame::CreateMonsterExra(
+  return MyGame::CreateMonsterExtra(
       _fbb,
       _testf_nan,
       _testf_pinf,
@@ -201,7 +201,7 @@ inline flatbuffers::Offset<MonsterExra> CreateMonsterExra(flatbuffers::FlatBuffe
       _testd_ninf);
 }
 
-inline const flatbuffers::TypeTable *MonsterExraTypeTable() {
+inline const flatbuffers::TypeTable *MonsterExtraTypeTable() {
   static const flatbuffers::TypeCode type_codes[] = {
     { flatbuffers::ET_FLOAT, 0, -1 },
     { flatbuffers::ET_FLOAT, 0, -1 },
index 268efbe..54f0446 100644 (file)
@@ -20,10 +20,10 @@ PY_VERSION = sys.version_info[:2]
 
 import ctypes
 from collections import defaultdict
+import math
 import timeit
 import unittest
 
-
 from flatbuffers import compat
 from flatbuffers import util
 from flatbuffers.compat import range_func as compat_range
@@ -40,6 +40,7 @@ import MyGame.Example.Monster  # refers to generated code
 import MyGame.Example.Test  # refers to generated code
 import MyGame.Example.Stat  # refers to generated code
 import MyGame.Example.Vec3  # refers to generated code
+import MyGame.MonsterExtra  # refers to generated code
 
 
 def assertRaises(test_case, fn, exception_class):
@@ -1395,6 +1396,27 @@ class TestAllCodePathsOfExampleSchema(unittest.TestCase):
         self.assertEqual(12345, stat2.Count())
 
 
+class TestAllCodePathsOfMonsterExtraSchema(unittest.TestCase):
+    def setUp(self, *args, **kwargs):
+        super(TestAllCodePathsOfMonsterExtraSchema, self).setUp(*args, **kwargs)
+
+        b = flatbuffers.Builder(0)
+        MyGame.MonsterExtra.MonsterExtraStart(b)
+        gen_mon = MyGame.MonsterExtra.MonsterExtraEnd(b)
+        b.Finish(gen_mon)
+
+        self.mon = MyGame.MonsterExtra.MonsterExtra.GetRootAsMonsterExtra(b.Bytes, b.Head())
+
+    def test_default_nan_inf(self):
+        self.assertTrue(math.isnan(self.mon.TestfNan()))
+        self.assertEqual(self.mon.TestfPinf(), float("inf"))
+        self.assertEqual(self.mon.TestfNinf(), float("-inf"))
+
+        self.assertTrue(math.isnan(self.mon.TestdNan()))
+        self.assertEqual(self.mon.TestdPinf(), float("inf"))
+        self.assertEqual(self.mon.TestdNinf(), float("-inf"))
+
+
 class TestVtableDeduplication(unittest.TestCase):
     ''' TestVtableDeduplication verifies that vtables are deduplicated. '''