* Make the value lifecycle inline-friendly
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Compare standard containers without a thread-local depth count
operator== on objects and arrays recursed through the containers' own
operator== and counted the depth in a thread-local variable. Where reading a
thread-local costs a call (macOS), that added about 10% to comparing documents
with many small containers. For the standard containers, walk objects and
arrays directly, compare scalars and strings inline, and pass the depth as an
argument, falling back to compare_iteratively beyond the depth limit. Other
container types keep the previous path.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
* Address review: owns_memory() helper, leaf compare naming, astyle
- Add detail::owns_memory(value_t), a switch listing every enumerator so
-Wswitch-enum flags it when a type is added; destroy() and the copy
constructor use it instead of hand-written comparisons. Clang emits the
same bitmask test as before.
- Drop the parentheses around the scalar operands in
JSON_IMPLEMENT_SCALAR_CASES; they are only needed for the container
operands (#1530), which the comment now says.
- Build equal_bounded_containers from detail::conjunction so astyle no
longer pads the template brackets.
- Rename equal_scalar() to equal_leaf() and document why it also compares
strings, unlike JSON_IMPLEMENT_SCALAR_FAST.
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
---------
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
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