Add default NaN/Inf to C#, Java, Python (#5107)

* Add default NaN/Inf to C#, Java, Python

* Python NaN/Inf test added

* Remove MSVC2010/13 dependent code
This commit is contained in:
Vladimir Glavnyy
2019-01-15 00:23:42 +07:00
committed by Wouter van Oortmerssen
parent 46208b1e91
commit 4fa4d36706
14 changed files with 443 additions and 112 deletions

View 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)

View 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

View 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();

View 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