Skip to content

Commit 3fb2e38

Browse files
committed
parser: Add zero_on_float_to_int logic and improve json parsing.
1 parent 31beb0f commit 3fb2e38

File tree

5 files changed

+41
-1
lines changed

5 files changed

+41
-1
lines changed

include/flatbuffers/idl.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,10 @@ struct IDLOptions {
787787
/******************************* Python gRPC ********************************/
788788
bool grpc_python_typed_handlers;
789789

790+
// If set, when a float value is received for an integer field, set the value
791+
// to 0 to avoid precision loss.
792+
bool zero_on_float_to_int;
793+
790794
IDLOptions()
791795
: gen_jvmstatic(false),
792796
use_flexbuffers(false),
@@ -861,7 +865,8 @@ struct IDLOptions {
861865
set_empty_vectors_to_null(true),
862866
grpc_filename_suffix(".fb"),
863867
grpc_use_system_headers(true),
864-
grpc_python_typed_handlers(false) {}
868+
grpc_python_typed_handlers(false),
869+
zero_on_float_to_int(false) {}
865870
};
866871

867872
// This encapsulates where the parser is in the current source file.

src/idl_parser.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2189,6 +2189,24 @@ CheckedError Parser::ParseSingleValue(const std::string *name, Value &e,
21892189
} else {
21902190
// Try a float number.
21912191
TRY_ECHECK(kTokenFloatConstant, IsFloat(in_type), BASE_TYPE_FLOAT);
2192+
2193+
// Special handling for integer types that might come as floats from JSON
2194+
// This happens when large integers are parsed as doubles by JSON parsers
2195+
// Set the value to 0 to avoid precision issues
2196+
if (!match && token_ == kTokenFloatConstant && IsInteger(in_type) &&
2197+
opts.zero_on_float_to_int) {
2198+
double float_val = std::stod(attribute_);
2199+
// For ulong fields that receive float values, set to 0
2200+
Warning("Float value " + std::to_string(float_val) + " received for <" +
2201+
std::string(TypeName(in_type)) +
2202+
"> field, setting to 0 to avoid precision loss " +
2203+
std::to_string(IsFloat(in_type)) + " " +
2204+
std::to_string(IsInteger(in_type)) + " " +
2205+
std::to_string(token_));
2206+
attribute_ = "0";
2207+
TRY_ECHECK(kTokenFloatConstant, IsInteger(in_type), BASE_TYPE_INT);
2208+
}
2209+
21922210
// Integer token can init any scalar (integer of float).
21932211
FORCE_ECHECK(kTokenIntegerConstant, IsScalar(in_type), BASE_TYPE_INT);
21942212
}

tests/parser_test.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -928,5 +928,20 @@ void FieldIdentifierTest() {
928928
#endif
929929
}
930930

931+
void ZeroOnFloatToIntTest() {
932+
flatbuffers::IDLOptions opts;
933+
{
934+
opts.zero_on_float_to_int = true;
935+
flatbuffers::Parser parser(opts);
936+
TEST_EQ(true, parser.Parse("table T{ i: int = 1.0; }"));
937+
}
938+
939+
{
940+
opts.zero_on_float_to_int = false;
941+
flatbuffers::Parser parser(opts);
942+
TEST_EQ(false, parser.Parse("table T{ i: int = 1.0; }"));
943+
}
944+
}
945+
931946
} // namespace tests
932947
} // namespace flatbuffers

tests/parser_test.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ void ValidSameNameDifferentNamespaceTest();
2626
void WarningsAsErrorsTest();
2727
void StringVectorDefaultsTest();
2828
void FieldIdentifierTest();
29+
void ZeroOnFloatToIntTest();
2930

3031
} // namespace tests
3132
} // namespace flatbuffers

tests/test.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1729,6 +1729,7 @@ int FlatBufferTests(const std::string &tests_data_path) {
17291729
EmbeddedSchemaAccess();
17301730
Offset64Tests();
17311731
UnionUnderlyingTypeTest();
1732+
ZeroOnFloatToIntTest();
17321733
return 0;
17331734
}
17341735
} // namespace

0 commit comments

Comments
 (0)