-
-
Notifications
You must be signed in to change notification settings - Fork 6.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Extending support to full uint64_t/int64_t range - issue #178 (Integer conversion to unsigned) #183
Conversation
Hi @twelsby, thanks for your work! I'll have a look at the diff. In the meantime, could you check why the unit tests fail on Travis? |
} | ||
|
||
/*! | ||
@brief return whether value is a floating-point number | ||
|
||
This function returns true iff the JSON value is a floating-point number. | ||
This excludes integer values. | ||
This function returns true if the JSON value is a floating-point number. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, I used "iff" as (common?) abbreviation for "if and only iff" here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry I didn't know that one and thought it was a typo.
I looked at the diffs and adde some comments. Wow - I am impressed how much effort you put to extend all the unit tests! |
Awesome amount of changes. A little addition: you should set errno = 0 before calling strto functions.
I assume it does not change errno on success. |
Good pickup @Furcube I completely forgot about that. I'll fix it. |
result.m_value.number_integer = std::strtoll This will be very bad if NumberIntegerType is not a int64_t, but int32_t for example |
@Furcube, another good point. I think the best way would be to store it in a temporary |
The latest commit has the following changes:
|
Latest build adds a fix for #171 by adding two extra template overloads for operator[] for T* arguments. Seems to work well with no apparent side effects. |
#pragma GCC diagnostic push | ||
#pragma GCC diagnostic ignored "-Wfloat-equal" | ||
#endif | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this part with the #ifdef
s and #pragma
s is really ugly... I am not 100% convinced yet to have something like this in the library...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is necessary to suppress floating point warnings under gcc/clang. The only real alternatives are to:
- Accept the warnings - they are only warnings after all (ugly though)
- Change the build settings in the makefile so that -Wfloat-equal is omitted at the command line - this works for us but if the user decides to compile with the warning, and doesn't understand floating point, then they may come to the conclusion that this is a bug in our code
- Add the #pragma without the conditional block - this creates its own warning about unknown #pragma under VS2015
- Reinstate approx()
- Come up with some other means of avoiding the warning if such a thing exists
I will revert this for now and add it to its own pull request as it is really a separate issue.
@nlohmann, can you please close this pull request. I accidentally created it from my master which is causing all sorts of problems as I would like to point master elsewhere but can't while this is open. I will create another pull request with just the changes relevant to this subject and add a reference to this one. Unfortunately github does not allow changing the pull request source branch (although its an open feature request). |
Closed as requested by @twelsby. |
This pull request is to address issues raised in issue #178 related to the use of
uint64_t
andint64_t
types and the inaccuracies involved in parsing, or creating objects with the full range of these values. Specifically it addresses the following problems:uint64_t
value greater than (263) -1 will cause it to be represented as an incorrect negative value internally, and subsequently serialized as the negative value.double
initially and then converted to integers if possible, so parsing a number greater than (253) - 1 or less than -(253) + 1 will result in loss of precision. While this behavior is actually endorsed by RFC7159, due to the common use ofuint64_t
/int64_t
types in modern software it would be preferable if the full range could be supported with full precision.The pull request contains extensive changes to the code base however the majority of these are merely to introduce a new type,
number_unsigned_t
, which is required to support the upper range ofuint64_t
/int64_t
values. The flow on effect of this is the addition of companion constructors, operators and miscellaneous code that is required to implement the new type. There are also very substantial changes to the unit testing (now just shy of 8000 assertions), again to accommodate the new type. This new code is in the same form as that for the existing types so there will be no surprises. A small number of additional unit tests check the performance of the parsing against the full range of theuint64_t
/int64_t
types.The most controversial change is the change to the number parsing function
get_number()
. This now attempts to parse the number both as an integer usingstd::strloull()
/std::strtoll()
and also usingstd::strtold()
and then stores using the best representation. This method was presented in the discussion for issue #178.This method is far from ideal however the most likely alternatives seem to be either writing some custom (non-standard library based) number parsing function, or attempting to scan ahead in the string before parsing, or modifying the lexer to make the determination, or just accepting the reduced range. Neither of these alternatives seems ideal.