Two bugs for custom number types that compile on develop (found while
analysing #3578):
- compare_integer_with_float() took the signedness of the integer type
from std::is_signed, which is false for class types such as
absl::int128 or boost::multiprecision::cpp_int. Any float below zero
then compared less than every integer, e.g. json(int128(-5)) <
json(-2.5) was false. The signedness now comes from
std::numeric_limits, like the digits used for the range bound.
- With number_integer_t/number_unsigned_t wider than 64 bits (e.g.
__int128), CBOR, MessagePack, and BSON silently truncated integers
beyond 64 bits (to_cbor of 2^100 read back as 0), BJData truncated
unsigned ones with the 'M' marker and could encode truncated ND-array
elements and dimensions, and BON8 did not compile (std::to_string is
ambiguous for __int128). The writers now throw out_of_range.407 when
an integer does not fit the format's range ([-2^64, 2^64-1] for CBOR,
[-2^63, 2^64-1] for MessagePack, int64/uint64 for BSON, int64 for
BON8); BJData writes such unsigned values as high-precision numbers,
as it already did for signed ones and UBJSON does for both, and falls
back to a plain object for the ND-array. The checks use
std::numeric_limits digits and compile away when the number types are
at most 64 bits wide, so the default types pay nothing (the CBOR,
MessagePack, and BSON writers compile to identical code).
The new unit-custom-number-types.cpp tests the comparison with a small
class-type integer and the writers with __int128 where the standard
library supports it as an integral type.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
The mixed number arms of JSON_IMPLEMENT_OPERATOR cast the integer to
number_float_t before comparing. Past the float's mantissa that cast is lossy:
2^63-2 and 2^63-1 both round to 2^63, so each compares equal to that float
while differing from each other. Equality is therefore intransitive and the
ordering is not a strict weak ordering, which makes std::sort over such values,
or using them as keys in std::set or std::map, undefined behavior.
Compare the two exactly instead. The integer's range is a power of two the
float represents exactly, so a float outside it is ordered by magnitude alone;
inside it, truncating the float is exact, and the integer parts and then any
fractional part decide. The helper hands back a pair whose comparison with the
original operator reproduces that ordering, which keeps every operator's return
type as it was, including partial_ordering for the spaceship.
A NaN operand is returned in both members, so NaN stays false for the
relational operators and unordered for <=>. Values a float represents exactly
still compare equal, so json(1) == json(1.0) is unchanged.
Signed-off-by: qatcod <79017227+qatcod@users.noreply.github.com>
* Add versioned inline namespace
Add a versioned inline namespace to prevent ABI issues when linking code
using multiple library versions.
* Add namespace macros
* Encode ABI information in inline namespace
Add _diag suffix to inline namespace if JSON_DIAGNOSTICS is enabled, and
_ldvcmp suffix if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON is enabled.
* Move ABI-affecting macros into abi_macros.hpp
* Move std_fs namespace definition into std_fs.hpp
* Remove std_fs namespace from unit test
* Format more files in tests directory
* Add unit tests
* Update documentation
* Fix GDB pretty printer
* fixup! Add namespace macros
* Derive ABI prefix from NLOHMANN_JSON_VERSION_*
* Add C++20 3-way comparison operator and fix broken comparisons
Fixes#3207.
Fixes#3409.
* Fix iterators to meet (more) std::ranges requirements
Fixes#3130.
Related discussion: #3408
* Add note about CMake standard version selection to unit tests
Document how CMake chooses which C++ standard version to use when
building tests.
* Update documentation
* CI: add legacy discarded value comparison
* Fix internal linkage errors when building a module
* Rename 'develop' folder to 'include/nlohmann'
* Rename 'src' folder to 'single_include/nlohmann'
* Use <nlohmann/*> headers in sources and tests
* Change amalgamate config file