1
0
mirror of https://github.com/nlohmann/json.git synced 2026-07-26 05:33:04 +04:00
Files
json/docs/mkdocs/docs/api/basic_json/std_hash.md
T
Niels Lohmann 68c87ad9de Fix std::hash contract violation for numeric types
Fixes #5256: json(42) == json(42u) is true, but their hashes differed,
violating the std::hash contract. This also applied to float comparisons:
json(42) == json(42.0) is true, but they hashed differently.

Solution: Normalize numeric type hashing to ensure equal values hash equal.
- Signed/unsigned integers: normalize unsigned to signed via static_cast,
  matching the existing operator== behavior (lines 3711-3717 in json.hpp)
- Integer/float bridging: for values exactly representable as the float type,
  hash via the float form to collide correctly with float values
- All numeric types share a single type tag to ensure hash collision

The fix is rigorous for the reported issue (int/uint, any magnitude) with zero
gaps. For int/float comparisons, there's a documented edge case at extreme
magnitudes due to float precision limits, mirroring limitations already
present in operator==.

Changes:
- include/nlohmann/detail/hash.hpp: core fix with new
  is_exactly_representable_as_float helper
- tests/src/unit-hash.cpp: update expected hash counts (21 -> 19 distinct),
  add explicit std::hash contract verification
- docs/mkdocs/docs/api/basic_json/std_hash.md: update description
- docs/mkdocs/docs/examples/std_hash.cpp/.output: show the fix in action
- single_include/nlohmann/json.hpp: regenerated via amalgamate

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-07-09 21:12:31 +02:00

1.4 KiB

std::hashnlohmann::basic_json\

namespace std {
    struct hash<nlohmann::basic_json>;
}

Return a hash value for a JSON object. The hash function tries to rely on std::hash where possible. To satisfy the std::hash contract, numeric JSON values that compare equal must hash to the same value. This means:

  • json(42), json(42u), and json(42.0) all hash to the same value
  • json(0), json(0u), and json(0.0) all hash to the same value

Different types hash differently for non-numeric types (e.g., #!json null, #!cpp false, and strings all have distinct hashes).

Edge case: For very large integers outside the exact representable range of the floating-point type (beyond ~2^53 for typical double), the hash values for integer and floating-point values may differ, even if the floating-point value was obtained by casting the integer (due to precision loss). This is a documented limitation arising from how the comparison operator normalizes numeric types.

Examples

??? example

The example shows how to calculate hash values for different JSON values.
 
```cpp
--8<-- "examples/std_hash.cpp"
```

Output:

```json
--8<-- "examples/std_hash.output"
```

Note the output is platform-dependent.

Version history

  • Added in version 1.0.0.
  • Extended for arbitrary basic_json types in version 3.10.5.