mirror of
https://github.com/nlohmann/json.git
synced 2026-07-09 12:05:10 +00:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8861d3ec5a | |||
| d8b274e7c2 | |||
| fe0299545a | |||
| 366f3d26e5 | |||
| 7c9208bfb3 |
@@ -82,7 +82,13 @@ basic_json(basic_json&& other) noexcept;
|
|||||||
4. This is a constructor for existing `basic_json` types. It does not hijack copy/move constructors, since the parameter
|
4. This is a constructor for existing `basic_json` types. It does not hijack copy/move constructors, since the parameter
|
||||||
has different template arguments than the current ones.
|
has different template arguments than the current ones.
|
||||||
|
|
||||||
The constructor tries to convert the internal `m_value` of the parameter.
|
The constructor tries to convert the internal `m_value` of the parameter. Each member value (object, array, string,
|
||||||
|
etc.) is serialized via the corresponding `to_json()` overload. For objects and strings, the conversion requires
|
||||||
|
that the *target* `basic_json` type's `object_t::key_type` (or `string_t`) be directly constructible from the
|
||||||
|
*source* type's corresponding member type via `is_constructible`. If this requirement is not met, the conversion
|
||||||
|
does not fail to compile; instead, it silently falls back to the array-conversion path, which represents objects
|
||||||
|
as arrays of `[key, value]` pairs and strings as arrays of character codes. This is a known limitation tracked in
|
||||||
|
[issue #3425](https://github.com/nlohmann/json/issues/3425).
|
||||||
|
|
||||||
5. Creates a JSON value of type array or object from the passed initializer list `init`. In case `type_deduction` is
|
5. Creates a JSON value of type array or object from the passed initializer list `init`. In case `type_deduction` is
|
||||||
`#!cpp true` (default), the type of the JSON value to be created is deducted from the initializer list `init`
|
`#!cpp true` (default), the type of the JSON value to be created is deducted from the initializer list `init`
|
||||||
@@ -146,6 +152,11 @@ basic_json(basic_json&& other) noexcept;
|
|||||||
|
|
||||||
- `BasicJsonType` is a `basic_json` type.
|
- `BasicJsonType` is a `basic_json` type.
|
||||||
- `BasicJsonType` has different template arguments than `basic_json_t`.
|
- `BasicJsonType` has different template arguments than `basic_json_t`.
|
||||||
|
|
||||||
|
**Note:** For cross-`basic_json` conversions to produce correct results, the target `basic_json`'s
|
||||||
|
`object_t::key_type` and `string_t` must be directly constructible from the source `basic_json`'s
|
||||||
|
corresponding types. See the description of overload (4) above for details on what happens when
|
||||||
|
this requirement is not met.
|
||||||
|
|
||||||
`U`:
|
`U`:
|
||||||
: `uncvref_t<CompatibleType>`
|
: `uncvref_t<CompatibleType>`
|
||||||
|
|||||||
@@ -93,6 +93,15 @@ alphabetical order as `std::map` with `std::less` is used by default. Please not
|
|||||||
[RFC 8259](https://tools.ietf.org/html/rfc8259), because any order implements the specified "unordered" nature of JSON
|
[RFC 8259](https://tools.ietf.org/html/rfc8259), because any order implements the specified "unordered" nature of JSON
|
||||||
objects.
|
objects.
|
||||||
|
|
||||||
|
#### Cross-`basic_json` conversion requirements
|
||||||
|
|
||||||
|
When converting an object from one `basic_json` specialization to another via the
|
||||||
|
[converting constructor](basic_json.md#overload-4), the target `object_t`'s `key_type` must be
|
||||||
|
directly constructible from the source `basic_json`'s `string_t` type (or more generally, from the
|
||||||
|
source object's key type). If this requirement is not met, the conversion does not fail; instead,
|
||||||
|
the object is silently converted as an array of key-value pairs, which is incorrect. See
|
||||||
|
[issue #3425](https://github.com/nlohmann/json/issues/3425) for details and an example.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
??? example
|
??? example
|
||||||
|
|||||||
@@ -19,10 +19,8 @@ class basic_json {
|
|||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
1. Compares two JSON values for inequality according to the following rules:
|
1. Compares two JSON values for inequality. Returns `#!cpp !(lhs == rhs)` (until C++20) or `#!cpp !(*this == rhs)` (since C++20).
|
||||||
- The comparison always yields `#!cpp false` if (1) either operand is discarded, or (2) either operand is `NaN` and
|
- This means the comparison is simply the logical negation of `operator==`, including for special values like `NaN` and `discarded`.
|
||||||
the other operand is either `NaN` or any other number.
|
|
||||||
- Otherwise, returns the result of `#!cpp !(lhs == rhs)` (until C++20) or `#!cpp !(*this == rhs)` (since C++20).
|
|
||||||
|
|
||||||
2. Compares a JSON value and a scalar or a scalar and a JSON value for inequality by converting the scalar to a JSON
|
2. Compares a JSON value and a scalar or a scalar and a JSON value for inequality by converting the scalar to a JSON
|
||||||
value and comparing both JSON values according to 1.
|
value and comparing both JSON values according to 1.
|
||||||
@@ -54,13 +52,12 @@ Linear.
|
|||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
!!! note "Comparing `NaN`"
|
!!! note "Comparing `NaN` and `discarded`"
|
||||||
|
|
||||||
`NaN` values are unordered within the domain of numbers.
|
Since `operator!=` is defined as `!(a == b)`, the behavior for special values follows that of `operator==`:
|
||||||
The following comparisons all yield `#!cpp false`:
|
|
||||||
1. Comparing a `NaN` with itself.
|
- For `NaN` values: `NaN == NaN` yields `#!cpp false`, so `NaN != NaN` yields `#!cpp true`.
|
||||||
2. Comparing a `NaN` with another `NaN`.
|
- For `discarded` values: `discarded == x` yields `#!cpp false` for any `x`, so `discarded != x` yields `#!cpp true`.
|
||||||
3. Comparing a `NaN` and any other number.
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
@@ -94,5 +91,7 @@ Linear.
|
|||||||
|
|
||||||
## Version history
|
## Version history
|
||||||
|
|
||||||
1. Added in version 1.0.0. Added C++20 member functions in version 3.11.0.
|
1. Added in version 1.0.0. Added C++20 member functions in version 3.11.0. Changed in version 3.12.x to remove
|
||||||
2. Added in version 1.0.0. Added C++20 member functions in version 3.11.0.
|
special-casing for `NaN` and `discarded` values; `operator!=` now consistently means `!(a == b)`.
|
||||||
|
2. Added in version 1.0.0. Added C++20 member functions in version 3.11.0. Changed in version 3.12.x to remove
|
||||||
|
special-casing for `NaN` and `discarded` values; `operator!=` now consistently means `!(a == b)`.
|
||||||
|
|||||||
@@ -45,6 +45,15 @@ This implementation is interoperable as it does compare strings code unit by cod
|
|||||||
String values are stored as pointers in a `basic_json` type. That is, for any access to string values, a pointer of type
|
String values are stored as pointers in a `basic_json` type. That is, for any access to string values, a pointer of type
|
||||||
`string_t*` must be dereferenced.
|
`string_t*` must be dereferenced.
|
||||||
|
|
||||||
|
#### Cross-`basic_json` conversion requirements
|
||||||
|
|
||||||
|
When converting a string value from one `basic_json` specialization to another via the
|
||||||
|
[converting constructor](basic_json.md#overload-4), the target `string_t` must be directly
|
||||||
|
constructible from the source `basic_json`'s `string_t` type. If this requirement is not met, the
|
||||||
|
conversion does not fail; instead, the string is silently converted as an array of character codes,
|
||||||
|
which is incorrect. See [issue #3425](https://github.com/nlohmann/json/issues/3425) for details
|
||||||
|
and an example.
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
??? example
|
??? example
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
User-agent: *
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
Sitemap: https://json.nlohmann.me/sitemap.xml
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
"""Copy each documentation page's Markdown source into the built site."""
|
||||||
|
|
||||||
|
# Creates a `<path>.md` sibling of each HTML output (for example,
|
||||||
|
# `features/comments/` becomes `features/comments.md`) so agents and tools can
|
||||||
|
# fetch the raw Markdown directly instead of parsing rendered HTML.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
_pages = []
|
||||||
|
|
||||||
|
|
||||||
|
def on_files(files, config):
|
||||||
|
global _pages
|
||||||
|
_pages = [f for f in files if f.is_documentation_page()]
|
||||||
|
return files
|
||||||
|
|
||||||
|
|
||||||
|
def on_post_build(config):
|
||||||
|
site_dir = config["site_dir"]
|
||||||
|
for file in _pages:
|
||||||
|
url = file.url.rstrip("/")
|
||||||
|
target = os.path.join(site_dir, (url or "index") + ".md")
|
||||||
|
os.makedirs(os.path.dirname(target), exist_ok=True)
|
||||||
|
shutil.copyfile(file.abs_src_path, target)
|
||||||
@@ -367,6 +367,9 @@ markdown_extensions:
|
|||||||
auto_append:
|
auto_append:
|
||||||
- ../includes/glossary.md
|
- ../includes/glossary.md
|
||||||
|
|
||||||
|
hooks:
|
||||||
|
- hooks/copy_markdown_source.py
|
||||||
|
|
||||||
plugins:
|
plugins:
|
||||||
- search:
|
- search:
|
||||||
separator: '[\s\-\.]'
|
separator: '[\s\-\.]'
|
||||||
@@ -389,6 +392,33 @@ plugins:
|
|||||||
- https://nlohmann.github.io/json/*
|
- https://nlohmann.github.io/json/*
|
||||||
- mailto:*
|
- mailto:*
|
||||||
- privacy
|
- privacy
|
||||||
|
- llmstxt:
|
||||||
|
markdown_description: >
|
||||||
|
JSON for Modern C++ is a C++11 header-only library implementing a JSON
|
||||||
|
value type with an STL-like API, JSON Pointer/Patch, CBOR/MessagePack/
|
||||||
|
BSON/UBJSON/BJData binary format support, and a SAX-style parser interface.
|
||||||
|
sections:
|
||||||
|
Home:
|
||||||
|
- index.md
|
||||||
|
- home/*.md
|
||||||
|
Features:
|
||||||
|
- features/*.md
|
||||||
|
- features/binary_formats/*.md
|
||||||
|
- features/element_access/*.md
|
||||||
|
- features/parsing/*.md
|
||||||
|
- features/types/*.md
|
||||||
|
Integration:
|
||||||
|
- integration/*.md
|
||||||
|
API Documentation:
|
||||||
|
- api/*.md
|
||||||
|
- api/basic_json/*.md
|
||||||
|
- api/adl_serializer/*.md
|
||||||
|
- api/byte_container_with_subtype/*.md
|
||||||
|
- api/json_pointer/*.md
|
||||||
|
- api/json_sax/*.md
|
||||||
|
- api/macros/*.md
|
||||||
|
Community:
|
||||||
|
- community/*.md
|
||||||
|
|
||||||
extra_css:
|
extra_css:
|
||||||
- css/custom.css
|
- css/custom.css
|
||||||
|
|||||||
@@ -7,5 +7,6 @@ mkdocs-material-extensions==1.3.1 # extensions
|
|||||||
mkdocs-minify-plugin==0.8.0 # plugin "minify"
|
mkdocs-minify-plugin==0.8.0 # plugin "minify"
|
||||||
mkdocs-redirects==1.2.3 # plugin "redirects"
|
mkdocs-redirects==1.2.3 # plugin "redirects"
|
||||||
mkdocs-htmlproofer-plugin==1.5.0 # plugin "htmlproofer"
|
mkdocs-htmlproofer-plugin==1.5.0 # plugin "htmlproofer"
|
||||||
|
mkdocs-llmstxt==0.5.0 # plugin "llmstxt"
|
||||||
|
|
||||||
PyYAML==6.0.3 # linter
|
PyYAML==6.0.3 # linter
|
||||||
|
|||||||
@@ -465,18 +465,12 @@ class serializer
|
|||||||
{
|
{
|
||||||
if (codepoint <= 0xFFFF)
|
if (codepoint <= 0xFFFF)
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
write_u_escape(bytes, static_cast<std::uint16_t>(codepoint));
|
||||||
static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x",
|
|
||||||
static_cast<std::uint16_t>(codepoint)));
|
|
||||||
bytes += 6;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
write_u_escape(bytes, static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)));
|
||||||
static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
|
write_u_escape(bytes, static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu)));
|
||||||
static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),
|
|
||||||
static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu))));
|
|
||||||
bytes += 12;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -683,6 +677,32 @@ class serializer
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief write a lowercase "\uXXXX" escape sequence into @a string_buffer
|
||||||
|
*
|
||||||
|
* Branch-free replacement for `snprintf(buf, 7, "\\u%04x", codeunit)` in the
|
||||||
|
* string escaping hot path. It writes exactly six characters ('\\', 'u' and
|
||||||
|
* four hex digits) at position @a pos of @a string_buffer via a nibble
|
||||||
|
* lookup table, avoiding the format-string parsing and locale machinery of
|
||||||
|
* `snprintf`. Advances @a pos by the number of bytes written (6).
|
||||||
|
*
|
||||||
|
* @param[in] pos position in @a string_buffer to write at; there must
|
||||||
|
* be at least 6 bytes of headroom
|
||||||
|
* @param[in] codeunit 16-bit value to encode
|
||||||
|
*/
|
||||||
|
void write_u_escape(std::size_t& pos, std::uint16_t codeunit) noexcept
|
||||||
|
{
|
||||||
|
JSON_ASSERT(string_buffer.size() - pos >= 6);
|
||||||
|
constexpr const char* nibble_to_hex = "0123456789abcdef";
|
||||||
|
string_buffer[pos + 0] = '\\';
|
||||||
|
string_buffer[pos + 1] = 'u';
|
||||||
|
string_buffer[pos + 2] = nibble_to_hex[(codeunit >> 12u) & 0x0Fu];
|
||||||
|
string_buffer[pos + 3] = nibble_to_hex[(codeunit >> 8u) & 0x0Fu];
|
||||||
|
string_buffer[pos + 4] = nibble_to_hex[(codeunit >> 4u) & 0x0Fu];
|
||||||
|
string_buffer[pos + 5] = nibble_to_hex[codeunit & 0x0Fu];
|
||||||
|
pos += 6;
|
||||||
|
}
|
||||||
|
|
||||||
// templates to avoid warnings about useless casts
|
// templates to avoid warnings about useless casts
|
||||||
template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
|
template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
|
||||||
bool is_negative_number(NumberType x)
|
bool is_negative_number(NumberType x)
|
||||||
|
|||||||
@@ -3776,17 +3776,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return *this == basic_json(rhs);
|
return *this == basic_json(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief comparison: not equal
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
|
|
||||||
bool operator!=(const_reference rhs) const noexcept
|
|
||||||
{
|
|
||||||
if (compares_unordered(rhs, true))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return !operator==(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief comparison: 3-way
|
/// @brief comparison: 3-way
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
|
/// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
|
||||||
std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD*
|
std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD*
|
||||||
@@ -3892,10 +3881,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
|
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
|
||||||
friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
|
friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
|
||||||
{
|
{
|
||||||
if (compares_unordered(lhs, rhs, true))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return !(lhs == rhs);
|
return !(lhs == rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19962,18 +19962,12 @@ class serializer
|
|||||||
{
|
{
|
||||||
if (codepoint <= 0xFFFF)
|
if (codepoint <= 0xFFFF)
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
write_u_escape(bytes, static_cast<std::uint16_t>(codepoint));
|
||||||
static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x",
|
|
||||||
static_cast<std::uint16_t>(codepoint)));
|
|
||||||
bytes += 6;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
write_u_escape(bytes, static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)));
|
||||||
static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
|
write_u_escape(bytes, static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu)));
|
||||||
static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),
|
|
||||||
static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu))));
|
|
||||||
bytes += 12;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -20180,6 +20174,32 @@ class serializer
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* @brief write a lowercase "\uXXXX" escape sequence into @a string_buffer
|
||||||
|
*
|
||||||
|
* Branch-free replacement for `snprintf(buf, 7, "\\u%04x", codeunit)` in the
|
||||||
|
* string escaping hot path. It writes exactly six characters ('\\', 'u' and
|
||||||
|
* four hex digits) at position @a pos of @a string_buffer via a nibble
|
||||||
|
* lookup table, avoiding the format-string parsing and locale machinery of
|
||||||
|
* `snprintf`. Advances @a pos by the number of bytes written (6).
|
||||||
|
*
|
||||||
|
* @param[in] pos position in @a string_buffer to write at; there must
|
||||||
|
* be at least 6 bytes of headroom
|
||||||
|
* @param[in] codeunit 16-bit value to encode
|
||||||
|
*/
|
||||||
|
void write_u_escape(std::size_t& pos, std::uint16_t codeunit) noexcept
|
||||||
|
{
|
||||||
|
JSON_ASSERT(string_buffer.size() - pos >= 6);
|
||||||
|
constexpr const char* nibble_to_hex = "0123456789abcdef";
|
||||||
|
string_buffer[pos + 0] = '\\';
|
||||||
|
string_buffer[pos + 1] = 'u';
|
||||||
|
string_buffer[pos + 2] = nibble_to_hex[(codeunit >> 12u) & 0x0Fu];
|
||||||
|
string_buffer[pos + 3] = nibble_to_hex[(codeunit >> 8u) & 0x0Fu];
|
||||||
|
string_buffer[pos + 4] = nibble_to_hex[(codeunit >> 4u) & 0x0Fu];
|
||||||
|
string_buffer[pos + 5] = nibble_to_hex[codeunit & 0x0Fu];
|
||||||
|
pos += 6;
|
||||||
|
}
|
||||||
|
|
||||||
// templates to avoid warnings about useless casts
|
// templates to avoid warnings about useless casts
|
||||||
template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
|
template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
|
||||||
bool is_negative_number(NumberType x)
|
bool is_negative_number(NumberType x)
|
||||||
@@ -24602,17 +24622,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
return *this == basic_json(rhs);
|
return *this == basic_json(rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief comparison: not equal
|
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
|
|
||||||
bool operator!=(const_reference rhs) const noexcept
|
|
||||||
{
|
|
||||||
if (compares_unordered(rhs, true))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return !operator==(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief comparison: 3-way
|
/// @brief comparison: 3-way
|
||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
|
/// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
|
||||||
std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD*
|
std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD*
|
||||||
@@ -24718,10 +24727,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
|||||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
|
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
|
||||||
friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
|
friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
|
||||||
{
|
{
|
||||||
if (compares_unordered(lhs, rhs, true))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return !(lhs == rhs);
|
return !(lhs == rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -322,14 +322,12 @@ TEST_CASE("alternative string type")
|
|||||||
|
|
||||||
SECTION("JSON pointer")
|
SECTION("JSON pointer")
|
||||||
{
|
{
|
||||||
// conversion from json to alt_json fails to compile (see #3425);
|
// Direct conversion from a json literal to alt_json is not supported due to issue #3425:
|
||||||
// attempted fix(*) produces: [[['b','a','r'],['b','a','z']]] (with each char being an integer)
|
// alt_json's string_t (alt_string) is not directly constructible from std::string, so the
|
||||||
// (*) disable implicit conversion for json_refs of any basic_json type
|
// cross-basic_json conversion falls back to the array-conversion path, incorrectly representing
|
||||||
// alt_json j = R"(
|
// objects as arrays of [key, value] pairs and strings as arrays of character codes.
|
||||||
// {
|
// See https://github.com/nlohmann/json/issues/3425 for details.
|
||||||
// "foo": ["bar", "baz"]
|
// Workaround: use alt_json::parse() instead of implicit conversion.
|
||||||
// }
|
|
||||||
// )"_json;
|
|
||||||
auto j = alt_json::parse(R"({"foo": ["bar", "baz"]})");
|
auto j = alt_json::parse(R"({"foo": ["bar", "baz"]})");
|
||||||
|
|
||||||
CHECK(j.at(alt_json::json_pointer("/foo/0")) == j["foo"][0]);
|
CHECK(j.at(alt_json::json_pointer("/foo/0")) == j["foo"][0]);
|
||||||
|
|||||||
@@ -369,6 +369,7 @@ TEST_CASE("lexicographical comparison operators")
|
|||||||
SECTION("comparison: not equal")
|
SECTION("comparison: not equal")
|
||||||
{
|
{
|
||||||
// check that two values compare unequal as expected
|
// check that two values compare unequal as expected
|
||||||
|
// operator!= now means exactly !(a==b) without special cases for NaN/discarded
|
||||||
for (size_t i = 0; i < j_values.size(); ++i)
|
for (size_t i = 0; i < j_values.size(); ++i)
|
||||||
{
|
{
|
||||||
for (size_t j = 0; j < j_values.size(); ++j)
|
for (size_t j = 0; j < j_values.size(); ++j)
|
||||||
@@ -376,25 +377,12 @@ TEST_CASE("lexicographical comparison operators")
|
|||||||
CAPTURE(i)
|
CAPTURE(i)
|
||||||
CAPTURE(j)
|
CAPTURE(j)
|
||||||
|
|
||||||
if (json::compares_unordered(j_values[i], j_values[j], true))
|
CHECK((j_values[i] != j_values[j]) == !(j_values[i] == j_values[j]));
|
||||||
{
|
|
||||||
// if two values compare unordered,
|
|
||||||
// check that the boolean comparison result is always false
|
|
||||||
CHECK_FALSE(j_values[i] != j_values[j]);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// otherwise, check that they compare according to their definition
|
|
||||||
// as the inverse of equal
|
|
||||||
CHECK((j_values[i] != j_values[j]) == !(j_values[i] == j_values[j]));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// compare with null pointer
|
// compare with null pointer
|
||||||
const json j_null;
|
const json j_null;
|
||||||
CHECK((j_null != nullptr) == false);
|
|
||||||
CHECK((nullptr != j_null) == false);
|
|
||||||
CHECK((j_null != nullptr) == !(j_null == nullptr));
|
CHECK((j_null != nullptr) == !(j_null == nullptr));
|
||||||
CHECK((nullptr != j_null) == !(nullptr == j_null));
|
CHECK((nullptr != j_null) == !(nullptr == j_null));
|
||||||
}
|
}
|
||||||
@@ -594,3 +582,34 @@ TEST_CASE("lexicographical comparison operators")
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||||
|
// JSON_HAS_CPP_20 (do not remove; see note at top of file)
|
||||||
|
|
||||||
|
TEST_CASE("regression #3868 - heterogeneous comparisons compile under C++20 (P2468R2)")
|
||||||
|
{
|
||||||
|
// Issue #3868: operator!= was preventing compiler from synthesizing reversed
|
||||||
|
// operator== candidates under C++20's P2468R2 rewritten candidate rules.
|
||||||
|
// Verify that heterogeneous comparisons now work.
|
||||||
|
|
||||||
|
SECTION("string vs json")
|
||||||
|
{
|
||||||
|
std::string s = "string";
|
||||||
|
json j = "string";
|
||||||
|
CHECK(s == j);
|
||||||
|
CHECK(j == s);
|
||||||
|
CHECK_FALSE(s != j);
|
||||||
|
CHECK_FALSE(j != s);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("other heterogeneous types")
|
||||||
|
{
|
||||||
|
int i = 42;
|
||||||
|
json j = 42;
|
||||||
|
CHECK(i == j);
|
||||||
|
CHECK(j == i);
|
||||||
|
CHECK_FALSE(i != j);
|
||||||
|
CHECK_FALSE(j != i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|||||||
@@ -278,7 +278,7 @@ TEST_CASE("constructors")
|
|||||||
const auto t = j.get<std::tuple<int, float, std::string>>();
|
const auto t = j.get<std::tuple<int, float, std::string>>();
|
||||||
CHECK(std::get<0>(t) == j[0]);
|
CHECK(std::get<0>(t) == j[0]);
|
||||||
CHECK(std::get<1>(t) == j[1]);
|
CHECK(std::get<1>(t) == j[1]);
|
||||||
// CHECK(std::get<2>(t) == j[2]); // commented out due to CI issue, see https://github.com/nlohmann/json/pull/3985 and https://github.com/nlohmann/json/issues/4025
|
CHECK(std::get<2>(t) == j[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("std::tuple tie")
|
SECTION("std::tuple tie")
|
||||||
|
|||||||
@@ -168,6 +168,32 @@ TEST_CASE("convenience functions")
|
|||||||
CHECK_THROWS_WITH_AS(check_escaped("\xC2"), "[json.exception.type_error.316] incomplete UTF-8 string; last byte: 0xC2", json::type_error&);
|
CHECK_THROWS_WITH_AS(check_escaped("\xC2"), "[json.exception.type_error.316] incomplete UTF-8 string; last byte: 0xC2", json::type_error&);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SECTION("string escape with ensure_ascii")
|
||||||
|
{
|
||||||
|
// control characters are escaped regardless of ensure_ascii
|
||||||
|
check_escaped("\x01", "\\u0001", true);
|
||||||
|
check_escaped("\x1f", "\\u001f", true);
|
||||||
|
|
||||||
|
// non-ASCII code points in the Basic Multilingual Plane are emitted as
|
||||||
|
// a single lowercase \uXXXX escape (exercises every nibble position)
|
||||||
|
check_escaped("\xC2\x80", "\\u0080", true); // U+0080
|
||||||
|
check_escaped("\xC3\xBF", "\\u00ff", true); // U+00FF (ÿ)
|
||||||
|
check_escaped("\xDF\xBF", "\\u07ff", true); // U+07FF
|
||||||
|
check_escaped("\xE4\xBD\xA0", "\\u4f60", true); // U+4F60 (你)
|
||||||
|
check_escaped("\xEA\xAF\x8D", "\\uabcd", true); // U+ABCD
|
||||||
|
check_escaped("\xEF\xBF\xBD", "\\ufffd", true); // U+FFFD (replacement char, all-f nibbles)
|
||||||
|
|
||||||
|
// code points outside the BMP are emitted as a UTF-16 surrogate pair
|
||||||
|
// of two lowercase \uXXXX escapes
|
||||||
|
check_escaped("\xF0\x90\x80\x80", "\\ud800\\udc00", true); // U+10000 (lowest astral)
|
||||||
|
check_escaped("\xF0\x9F\x98\x80", "\\ud83d\\ude00", true); // U+1F600 (😀)
|
||||||
|
check_escaped("\xF4\x8F\xBF\xBF", "\\udbff\\udfff", true); // U+10FFFF (highest code point)
|
||||||
|
|
||||||
|
// with ensure_ascii disabled, non-ASCII input is passed through verbatim
|
||||||
|
check_escaped("\xE4\xBD\xA0", "\xE4\xBD\xA0", false);
|
||||||
|
check_escaped("\xF0\x9F\x98\x80", "\xF0\x9F\x98\x80", false);
|
||||||
|
}
|
||||||
|
|
||||||
SECTION("string concat")
|
SECTION("string concat")
|
||||||
{
|
{
|
||||||
using nlohmann::detail::concat;
|
using nlohmann::detail::concat;
|
||||||
|
|||||||
@@ -942,7 +942,7 @@ TEST_CASE("iterators 2")
|
|||||||
json j_expected{5, 4, 3, 2, 1};
|
json j_expected{5, 4, 3, 2, 1};
|
||||||
|
|
||||||
auto reversed = j | std::views::reverse;
|
auto reversed = j | std::views::reverse;
|
||||||
CHECK(std::ranges::equal(reversed, j_expected));
|
CHECK(reversed == j_expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("transform")
|
SECTION("transform")
|
||||||
|
|||||||
Reference in New Issue
Block a user