Compare commits

...
Author SHA1 Message Date
Niels Lohmann 908038c027 Look up the key only once in the callback parser's key()
Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-15 08:16:23 +02:00
Niels Lohmann 4e294f4b18 Clarify that double is only the default floating-point type in the docs (#5830)
Follow-up to review comments on #5825: number_float_t uses double
precision only by default, and the stated limits apply to double.
Also say "default type for X_t" instead of "default value for X_t".

Signed-off-by: Niels Lohmann <mail@nlohmann.me>
2026-10-14 18:28:49 +02:00
10 changed files with 30 additions and 23 deletions

No files matched your search

+1 -1
View File
@@ -27,7 +27,7 @@ To store objects in C++, a type is defined by the template parameters explained
### Default type ### Default type
With the default values for `ArrayType` (`std::vector`) and `AllocatorType` (`std::allocator`), the default value for With the default values for `ArrayType` (`std::vector`) and `AllocatorType` (`std::allocator`), the default type for
`array_t` is: `array_t` is:
```cpp ```cpp
+1 -1
View File
@@ -23,7 +23,7 @@ To store boolean values in C++, a type is defined by the template parameter `Bo
### Default type ### Default type
With the default values for `BooleanType` (`#!cpp bool`), the default value for `boolean_t` is `#!cpp bool`. With the default values for `BooleanType` (`#!cpp bool`), the default type for `boolean_t` is `#!cpp bool`.
### Storage ### Storage
@@ -35,7 +35,7 @@ type to use.
### Default type ### Default type
With the default values for `NumberFloatType` (`double`), the default value for `number_float_t` is `#!cpp double`. With the default values for `NumberFloatType` (`double`), the default type for `number_float_t` is `#!cpp double`.
### Default behavior ### Default behavior
@@ -52,8 +52,9 @@ With the default values for `NumberFloatType` (`double`), the default value for
> interoperability can be achieved by implementations that expect no more precision or range than these provide, in the > interoperability can be achieved by implementations that expect no more precision or range than these provide, in the
> sense that implementations will approximate JSON numbers within the expected precision. > sense that implementations will approximate JSON numbers within the expected precision.
This implementation does exactly follow this approach, as it uses double precision floating-point numbers. Note that This implementation does exactly follow this approach, as it uses double precision floating-point numbers by default.
numbers smaller than `-1.79769313486232e+308` or greater than `1.79769313486232e+308` are rejected during parsing with Note that with the default `double`, numbers smaller than `-1.79769313486232e+308` or greater than
`1.79769313486232e+308` are rejected during parsing with
[`out_of_range.406`](../../home/exceptions.md#jsonexceptionout_of_range406). Non-finite values (NaN and infinity) can [`out_of_range.406`](../../home/exceptions.md#jsonexceptionout_of_range406). Non-finite values (NaN and infinity) can
only be stored by assigning them directly and are serialized to `null`. only be stored by assigning them directly and are serialized to `null`.
@@ -31,7 +31,7 @@ to use.
### Default type ### Default type
With the default values for `NumberIntegerType` (`std::int64_t`), the default value for `number_integer_t` is With the default values for `NumberIntegerType` (`std::int64_t`), the default type for `number_integer_t` is
`#!cpp std::int64_t`. `#!cpp std::int64_t`.
### Default behavior ### Default behavior
@@ -32,7 +32,7 @@ the type to use.
### Default type ### Default type
With the default values for `NumberUnsignedType` (`std::uint64_t`), the default value for `number_unsigned_t` is With the default values for `NumberUnsignedType` (`std::uint64_t`), the default type for `number_unsigned_t` is
`#!cpp std::uint64_t`. `#!cpp std::uint64_t`.
### Default behavior ### Default behavior
+1 -1
View File
@@ -36,7 +36,7 @@ To store objects in C++, a type is defined by the template parameters described
### Default type ### Default type
With the default values for `ObjectType` (`std::map`), `StringType` (`std::string`), and `AllocatorType` With the default values for `ObjectType` (`std::map`), `StringType` (`std::string`), and `AllocatorType`
(`std::allocator`), the default value for `object_t` is: (`std::allocator`), the default type for `object_t` is:
```cpp ```cpp
// until C++14 // until C++14
+1 -1
View File
@@ -32,7 +32,7 @@ JSON class into byte-sized characters during deserialization.
### Default type ### Default type
With the default values for `StringType` (`std::string`), the default value for `string_t` is `#!cpp std::string`. With the default values for `StringType` (`std::string`), the default type for `string_t` is `#!cpp std::string`.
### Encoding ### Encoding
+8 -8
View File
@@ -120,7 +120,7 @@ requirements are collected in [Template Parameter Requirements](template_paramet
### Default type ### Default type
With the default values for *ObjectType* (`std::map`), *StringType* (`std::string`), and *AllocatorType* (`std::allocator`), the default value for `object_t` is: With the default values for *ObjectType* (`std::map`), *StringType* (`std::string`), and *AllocatorType* (`std::allocator`), the default type for `object_t` is:
```cpp ```cpp
std::map< std::map<
@@ -177,7 +177,7 @@ json j = m;
### Default type ### Default type
With the default values for *ArrayType* (`std::vector`) and *AllocatorType* (`std::allocator`), the default value for `array_t` is: With the default values for *ArrayType* (`std::vector`) and *AllocatorType* (`std::allocator`), the default type for `array_t` is:
```cpp ```cpp
std::vector< std::vector<
@@ -209,7 +209,7 @@ Unicode values are split by the JSON class into byte-sized characters during des
### Default type ### Default type
With the default values for *StringType* (`std::string`), the default value for `string_t` is `#!cpp std::string`. With the default values for *StringType* (`std::string`), the default type for `string_t` is `#!cpp std::string`.
### Encoding ### Encoding
@@ -234,7 +234,7 @@ String values are stored as pointers in a `basic_json` type. That is, for any ac
### Default type ### Default type
With the default values for *BooleanType* (`#!cpp bool`), the default value for `boolean_t` is `#!cpp bool`. With the default values for *BooleanType* (`#!cpp bool`), the default type for `boolean_t` is `#!cpp bool`.
### Storage ### Storage
@@ -252,9 +252,9 @@ This description includes both integer and floating-point numbers. However, C++
### Default types ### Default types
With the default values for *NumberIntegerType* (`std::int64_t`), the default value for `number_integer_t` is `std::int64_t`. With the default values for *NumberIntegerType* (`std::int64_t`), the default type for `number_integer_t` is `std::int64_t`.
With the default values for *NumberUnsignedType* (`std::uint64_t`), the default value for `number_unsigned_t` is `std::uint64_t`. With the default values for *NumberUnsignedType* (`std::uint64_t`), the default type for `number_unsigned_t` is `std::uint64_t`.
With the default values for *NumberFloatType* (`#!cpp double`), the default value for `number_float_t` is `#!cpp double`. With the default values for *NumberFloatType* (`#!cpp double`), the default type for `number_float_t` is `#!cpp double`.
### Default behavior ### Default behavior
@@ -281,7 +281,7 @@ As this range is a subrange of the exactly supported range [`INT64_MIN`, `INT64_
> This specification allows implementations to set limits on the range and precision of numbers accepted. Since software that implements IEEE 754-2008 binary64 (double precision) numbers is generally available and widely used, good interoperability can be achieved by implementations that expect no more precision or range than these provide, in the sense that implementations will approximate JSON numbers within the expected precision. > This specification allows implementations to set limits on the range and precision of numbers accepted. Since software that implements IEEE 754-2008 binary64 (double precision) numbers is generally available and widely used, good interoperability can be achieved by implementations that expect no more precision or range than these provide, in the sense that implementations will approximate JSON numbers within the expected precision.
This implementation does exactly follow this approach, as it uses double precision floating-point numbers. Note that numbers smaller than `#!c -1.79769313486232e+308` or greater than `#!c 1.79769313486232e+308` are rejected during parsing with [`out_of_range.406`](../../home/exceptions.md#jsonexceptionout_of_range406). Non-finite values (NaN and infinity) can only be stored by assigning them directly and are serialized to `#!json null`. This implementation does exactly follow this approach, as it uses double precision floating-point numbers by default (see *NumberFloatType* above). Note that with the default `#!cpp double`, numbers smaller than `#!c -1.79769313486232e+308` or greater than `#!c 1.79769313486232e+308` are rejected during parsing with [`out_of_range.406`](../../home/exceptions.md#jsonexceptionout_of_range406). Non-finite values (NaN and infinity) can only be stored by assigning them directly and are serialized to `#!json null`.
### Storage ### Storage
+6 -3
View File
@@ -674,16 +674,19 @@ class json_sax_dom_callback_parser
if (keep && ref_stack.back()) if (keep && ref_stack.back())
{ {
auto& obj = *ref_stack.back()->m_data.m_value.object; auto& obj = *ref_stack.back()->m_data.m_value.object;
const auto it = obj.find(val); // a single lookup: insert the placeholder, or find the existing member
if (it != obj.end()) const auto inserted = obj.emplace(val, discarded);
const auto it = inserted.first;
if (!inserted.second)
{ {
// this is a duplicate key (legal in JSON); remember its // this is a duplicate key (legal in JSON); remember its
// current value so it can be restored later if the new // current value so it can be restored later if the new
// value is rejected by the callback, instead of being // value is rejected by the callback, instead of being
// erased together with the discarded placeholder // erased together with the discarded placeholder
duplicate_key_stash.emplace_back(&(it->second), it->second); duplicate_key_stash.emplace_back(&(it->second), it->second);
it->second = discarded;
} }
object_element = &(obj[val] = discarded); object_element = &(it->second);
} }
return true; return true;
+6 -3
View File
@@ -13850,16 +13850,19 @@ class json_sax_dom_callback_parser
if (keep && ref_stack.back()) if (keep && ref_stack.back())
{ {
auto& obj = *ref_stack.back()->m_data.m_value.object; auto& obj = *ref_stack.back()->m_data.m_value.object;
const auto it = obj.find(val); // a single lookup: insert the placeholder, or find the existing member
if (it != obj.end()) const auto inserted = obj.emplace(val, discarded);
const auto it = inserted.first;
if (!inserted.second)
{ {
// this is a duplicate key (legal in JSON); remember its // this is a duplicate key (legal in JSON); remember its
// current value so it can be restored later if the new // current value so it can be restored later if the new
// value is rejected by the callback, instead of being // value is rejected by the callback, instead of being
// erased together with the discarded placeholder // erased together with the discarded placeholder
duplicate_key_stash.emplace_back(&(it->second), it->second); duplicate_key_stash.emplace_back(&(it->second), it->second);
it->second = discarded;
} }
object_element = &(obj[val] = discarded); object_element = &(it->second);
} }
return true; return true;