mirror of
https://github.com/nlohmann/json.git
synced 2024-11-23 22:19:02 +08:00
Fix C++20/gcc-12 issues (Part 2) (#3446)
* 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
This commit is contained in:
parent
ede6667858
commit
6b97599a27
2
.github/workflows/ubuntu.yml
vendored
2
.github/workflows/ubuntu.yml
vendored
@ -48,7 +48,7 @@ jobs:
|
||||
container: ghcr.io/nlohmann/json-ci:v2.3.0
|
||||
strategy:
|
||||
matrix:
|
||||
target: [ci_test_diagnostics, ci_test_noexceptions, ci_test_noimplicitconversions]
|
||||
target: [ci_test_diagnostics, ci_test_noexceptions, ci_test_noimplicitconversions, ci_test_legacycomparison]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: cmake
|
||||
|
@ -37,13 +37,14 @@ if(${MAIN_PROJECT} AND (${CMAKE_VERSION} VERSION_EQUAL 3.13 OR ${CMAKE_VERSION}
|
||||
else()
|
||||
set(JSON_BuildTests_INIT OFF)
|
||||
endif()
|
||||
option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ${JSON_BuildTests_INIT})
|
||||
option(JSON_CI "Enable CI build targets." OFF)
|
||||
option(JSON_Diagnostics "Use extended diagnostic messages." OFF)
|
||||
option(JSON_ImplicitConversions "Enable implicit conversions." ON)
|
||||
option(JSON_Install "Install CMake targets during install step." ${MAIN_PROJECT})
|
||||
option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OFF)
|
||||
option(JSON_SystemInclude "Include as system headers (skip for clang-tidy)." OFF)
|
||||
option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ${JSON_BuildTests_INIT})
|
||||
option(JSON_CI "Enable CI build targets." OFF)
|
||||
option(JSON_Diagnostics "Use extended diagnostic messages." OFF)
|
||||
option(JSON_ImplicitConversions "Enable implicit conversions." ON)
|
||||
option(JSON_LegacyDiscardedValueComparison "Enable legacy discarded value comparison." OFF)
|
||||
option(JSON_Install "Install CMake targets during install step." ${MAIN_PROJECT})
|
||||
option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OFF)
|
||||
option(JSON_SystemInclude "Include as system headers (skip for clang-tidy)." OFF)
|
||||
|
||||
if (JSON_CI)
|
||||
include(ci)
|
||||
@ -77,6 +78,10 @@ if (NOT JSON_ImplicitConversions)
|
||||
message(STATUS "Implicit conversions are disabled")
|
||||
endif()
|
||||
|
||||
if (JSON_LegacyDiscardedValueComparison)
|
||||
message(STATUS "Legacy discarded value comparison enabled")
|
||||
endif()
|
||||
|
||||
if (JSON_Diagnostics)
|
||||
message(STATUS "Diagnostics enabled")
|
||||
endif()
|
||||
@ -100,8 +105,9 @@ endif()
|
||||
target_compile_definitions(
|
||||
${NLOHMANN_JSON_TARGET_NAME}
|
||||
INTERFACE
|
||||
JSON_USE_IMPLICIT_CONVERSIONS=$<BOOL:${JSON_ImplicitConversions}>
|
||||
JSON_DIAGNOSTICS=$<BOOL:${JSON_Diagnostics}>
|
||||
$<$<NOT:$<BOOL:${JSON_ImplicitConversions}>>:JSON_USE_IMPLICIT_CONVERSIONS=0>
|
||||
$<$<BOOL:${JSON_Diagnostics}>:JSON_DIAGNOSTICS=1>
|
||||
$<$<BOOL:${JSON_LegacyDiscardedValueComparison}>:JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1>
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
|
@ -498,6 +498,20 @@ add_custom_target(ci_test_diagnostics
|
||||
COMMENT "Compile and test with improved diagnostics enabled"
|
||||
)
|
||||
|
||||
###############################################################################
|
||||
# Enable legacy discarded value comparison.
|
||||
###############################################################################
|
||||
|
||||
add_custom_target(ci_test_legacycomparison
|
||||
COMMAND CXX=${CLANG_TOOL} ${CMAKE_COMMAND}
|
||||
-DCMAKE_BUILD_TYPE=Debug -GNinja
|
||||
-DJSON_BuildTests=ON -DJSON_MultipleHeaders=ON -DJSON_LegacyDiscardedValueComparison=ON
|
||||
-S${PROJECT_SOURCE_DIR} -B${PROJECT_BINARY_DIR}/build_legacycomparison
|
||||
COMMAND ${CMAKE_COMMAND} --build ${PROJECT_BINARY_DIR}/build_legacycomparison
|
||||
COMMAND cd ${PROJECT_BINARY_DIR}/build_legacycomparison && ${CMAKE_CTEST_COMMAND} --parallel ${N} --output-on-failure
|
||||
COMMENT "Compile and test with legacy discarded value comparison enabled"
|
||||
)
|
||||
|
||||
###############################################################################
|
||||
# Coverage.
|
||||
###############################################################################
|
||||
@ -797,8 +811,9 @@ endfunction()
|
||||
ci_get_cmake(3.1.0 CMAKE_3_1_0_BINARY)
|
||||
ci_get_cmake(3.13.0 CMAKE_3_13_0_BINARY)
|
||||
|
||||
set(JSON_CMAKE_FLAGS_3_1_0 "JSON_Install;JSON_MultipleHeaders;JSON_ImplicitConversions;JSON_Valgrind;JSON_Diagnostics;JSON_SystemInclude")
|
||||
set(JSON_CMAKE_FLAGS_3_13_0 "JSON_BuildTests")
|
||||
set(JSON_CMAKE_FLAGS_3_1_0 JSON_Diagnostics JSON_ImplicitConversions JSON_LegacyDiscardedValueComparison
|
||||
JSON_Install JSON_MultipleHeaders JSON_SystemInclude JSON_Valgrind)
|
||||
set(JSON_CMAKE_FLAGS_3_13_0 JSON_BuildTests)
|
||||
|
||||
function(ci_add_cmake_flags_targets flag min_version)
|
||||
string(TOLOWER "ci_cmake_flag_${flag}" flag_target)
|
||||
|
@ -156,6 +156,7 @@ endfunction()
|
||||
#############################################################################
|
||||
# json_test_add_test_for(
|
||||
# <file>
|
||||
# [NAME <name>]
|
||||
# MAIN <main>
|
||||
# [CXX_STANDARDS <version_number>...] [FORCE])
|
||||
#
|
||||
@ -165,6 +166,7 @@ endfunction()
|
||||
#
|
||||
# if C++ standard <version_number> is supported by the compiler and the
|
||||
# source file contains JSON_HAS_CPP_<version_number>.
|
||||
# Use NAME <name> to override the filename-derived test name.
|
||||
# Use FORCE to create the test regardless of the file containing
|
||||
# JSON_HAS_CPP_<version_number>.
|
||||
# Test targets are linked against <main>.
|
||||
@ -172,15 +174,22 @@ endfunction()
|
||||
#############################################################################
|
||||
|
||||
function(json_test_add_test_for file)
|
||||
cmake_parse_arguments(args "FORCE" "MAIN" "CXX_STANDARDS" ${ARGN})
|
||||
|
||||
get_filename_component(file_basename ${file} NAME_WE)
|
||||
string(REGEX REPLACE "unit-([^$]+)" "test-\\1" test_name ${file_basename})
|
||||
cmake_parse_arguments(args "FORCE" "MAIN;NAME" "CXX_STANDARDS" ${ARGN})
|
||||
|
||||
if("${args_MAIN}" STREQUAL "")
|
||||
message(FATAL_ERROR "Required argument MAIN <main> missing.")
|
||||
endif()
|
||||
|
||||
if("${args_NAME}" STREQUAL "")
|
||||
get_filename_component(file_basename ${file} NAME_WE)
|
||||
string(REGEX REPLACE "unit-([^$]+)" "test-\\1" test_name ${file_basename})
|
||||
else()
|
||||
set(test_name ${args_NAME})
|
||||
if(NOT test_name MATCHES "test-[^$]+")
|
||||
message(FATAL_ERROR "Test name must start with 'test-'.")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if("${args_CXX_STANDARDS}" STREQUAL "")
|
||||
set(args_CXX_STANDARDS 11)
|
||||
endif()
|
||||
|
@ -233,9 +233,10 @@ Access to the JSON value
|
||||
- [**operator==**](operator_eq.md) - comparison: equal
|
||||
- [**operator!=**](operator_ne.md) - comparison: not equal
|
||||
- [**operator<**](operator_lt.md) - comparison: less than
|
||||
- [**operator<=**](operator_le.md) - comparison: less than or equal
|
||||
- [**operator>**](operator_gt.md) - comparison: greater than
|
||||
- [**operator<=**](operator_le.md) - comparison: less than or equal
|
||||
- [**operator>=**](operator_ge.md) - comparison: greater than or equal
|
||||
- [**operator<=>**](operator_spaceship.md) - comparison: 3-way
|
||||
|
||||
### Serialization / Dumping
|
||||
|
||||
|
@ -1,21 +1,31 @@
|
||||
# <small>nlohmann::basic_json::</small>operator==
|
||||
|
||||
```cpp
|
||||
bool operator==(const_reference lhs, const_reference rhs) noexcept;
|
||||
// until C++20
|
||||
bool operator==(const_reference lhs, const_reference rhs) noexcept; // (1)
|
||||
|
||||
template<typename ScalarType>
|
||||
bool operator==(const_reference lhs, const ScalarType rhs) noexcept;
|
||||
bool operator==(const_reference lhs, const ScalarType rhs) noexcept; // (2)
|
||||
|
||||
template<typename ScalarType>
|
||||
bool operator==(ScalarType lhs, const const_reference rhs) noexcept;
|
||||
bool operator==(ScalarType lhs, const const_reference rhs) noexcept; // (2)
|
||||
|
||||
// since C++20
|
||||
class basic_json {
|
||||
bool operator==(const_reference rhs) const noexcept; // (1)
|
||||
|
||||
template<typename ScalarType>
|
||||
bool operator==(ScalarType rhs) const noexcept; // (2)
|
||||
};
|
||||
```
|
||||
|
||||
Compares two JSON values for equality according to the following rules:
|
||||
1. Compares two JSON values for equality according to the following rules:
|
||||
- Two JSON values are equal if (1) neither value is discarded, or (2) they are of the same
|
||||
type and their stored values are the same according to their respective `operator==`.
|
||||
- Integer and floating-point numbers are automatically converted before comparison.
|
||||
|
||||
- Two JSON values are equal if (1) they are not discarded, (2) they are from the same type, and (3) their stored values
|
||||
are the same according to their respective `operator==`.
|
||||
- Integer and floating-point numbers are automatically converted before comparison. Note that two NaN values are always
|
||||
treated as unequal.
|
||||
2. Compares a JSON value and a scalar or a scalar and a JSON value for equality by converting the
|
||||
scalar to a JSON value and comparing both JSON values according to 1.
|
||||
|
||||
## Template parameters
|
||||
|
||||
@ -32,7 +42,7 @@ Compares two JSON values for equality according to the following rules:
|
||||
|
||||
## Return value
|
||||
|
||||
whether the values `lhs` and `rhs` are equal
|
||||
whether the values `lhs`/`*this` and `rhs` are equal
|
||||
|
||||
## Exception safety
|
||||
|
||||
@ -46,7 +56,11 @@ Linear.
|
||||
|
||||
!!! note "Comparing special values"
|
||||
|
||||
- NaN values never compare equal to themselves or to other NaN values.
|
||||
- `NaN` values are unordered within the domain of numbers.
|
||||
The following comparisons all yield `#!cpp false`:
|
||||
1. Comparing a `NaN` with itself.
|
||||
2. Comparing a `NaN` with another `NaN`.
|
||||
3. Comparing a `NaN` and any other number.
|
||||
- JSON `#!cpp null` values are all equal.
|
||||
- Discarded values never compare equal to themselves.
|
||||
|
||||
@ -117,4 +131,5 @@ Linear.
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 1.0.0.
|
||||
1. Added in version 1.0.0. Added C++20 member functions in version 3.11.0.
|
||||
2. Added in version 1.0.0. Added C++20 member functions in version 3.11.0.
|
||||
|
@ -1,17 +1,25 @@
|
||||
# <small>nlohmann::basic_json::</small>operator>=
|
||||
|
||||
```cpp
|
||||
bool operator>=(const_reference lhs, const_reference rhs) noexcept,
|
||||
// until C++20
|
||||
bool operator>=(const_reference lhs, const_reference rhs) noexcept; // (1)
|
||||
|
||||
template<typename ScalarType>
|
||||
bool operator>=(const_reference lhs, const ScalarType rhs) noexcept;
|
||||
bool operator>=(const_reference lhs, const ScalarType rhs) noexcept; // (2)
|
||||
|
||||
template<typename ScalarType>
|
||||
bool operator>=(ScalarType lhs, const const_reference rhs) noexcept;
|
||||
bool operator>=(ScalarType lhs, const const_reference rhs) noexcept; // (2)
|
||||
```
|
||||
|
||||
Compares whether one JSON value `lhs` is greater than or equal to another JSON value `rhs` by calculating
|
||||
`#!cpp !(lhs < rhs)`.
|
||||
1. Compares whether one JSON value `lhs` is greater than or equal to another JSON value `rhs`
|
||||
according to the following rules:
|
||||
- The comparison always yields `#!cpp false` if (1) either operand is discarded, or (2) either
|
||||
operand is `NaN` and the other operand is either `NaN` or any other number.
|
||||
- Otherwise, returns the result of `#!cpp !(lhs < rhs)`.
|
||||
|
||||
2. Compares wether a JSON value is greater than or equal to a scalar or a scalar is greater than or
|
||||
equal to a JSON value by converting the scalar to a JSON value and comparing both JSON values
|
||||
according to 1.
|
||||
|
||||
## Template parameters
|
||||
|
||||
@ -38,6 +46,21 @@ No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
Linear.
|
||||
|
||||
## Notes
|
||||
|
||||
!!! note "Comparing `NaN`"
|
||||
|
||||
`NaN` values are unordered within the domain of numbers.
|
||||
The following comparisons all yield `#!cpp false`:
|
||||
1. Comparing a `NaN` with itself.
|
||||
2. Comparing a `NaN` with another `NaN`.
|
||||
3. Comparing a `NaN` and any other number.
|
||||
|
||||
!!! note "Operator overload resolution"
|
||||
|
||||
Since C++20 overload resolution will consider the _rewritten candidate_ generated from
|
||||
[`operator<=>`](operator_spaceship.md).
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
@ -54,6 +77,11 @@ Linear.
|
||||
--8<-- "examples/operator__greaterequal.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [**operator<=>**](operator_spaceship.md) comparison: 3-way
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 1.0.0.
|
||||
1. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0.
|
||||
2. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0.
|
||||
|
@ -1,16 +1,24 @@
|
||||
# <small>nlohmann::basic_json::</small>operator>
|
||||
|
||||
```cpp
|
||||
bool operator>(const_reference lhs, const_reference rhs) noexcept,
|
||||
// until C++20
|
||||
bool operator>(const_reference lhs, const_reference rhs) noexcept; // (1)
|
||||
|
||||
template<typename ScalarType>
|
||||
bool operator>(const_reference lhs, const ScalarType rhs) noexcept;
|
||||
bool operator>(const_reference lhs, const ScalarType rhs) noexcept; // (2)
|
||||
|
||||
template<typename ScalarType>
|
||||
bool operator>(ScalarType lhs, const const_reference rhs) noexcept;
|
||||
bool operator>(ScalarType lhs, const const_reference rhs) noexcept; // (2)
|
||||
```
|
||||
|
||||
Compares whether one JSON value `lhs` is greater than another JSON value `rhs` by calculating `#!cpp !(lhs <= rhs)`.
|
||||
1. Compares whether one JSON value `lhs` is greater than another JSON value `rhs` according to the
|
||||
following rules:
|
||||
- The comparison always yields `#!cpp false` if (1) either operand is discarded, or (2) either
|
||||
operand is `NaN` and the other operand is either `NaN` or any other number.
|
||||
- Otherwise, returns the result of `#!cpp !(lhs <= rhs)`.
|
||||
|
||||
2. Compares wether a JSON value is greater than a scalar or a scalar is greater than a JSON value by
|
||||
converting the scalar to a JSON value and comparing both JSON values according to 1.
|
||||
|
||||
## Template parameters
|
||||
|
||||
@ -37,6 +45,21 @@ No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
Linear.
|
||||
|
||||
## Notes
|
||||
|
||||
!!! note "Comparing `NaN`"
|
||||
|
||||
`NaN` values are unordered within the domain of numbers.
|
||||
The following comparisons all yield `#!cpp false`:
|
||||
1. Comparing a `NaN` with itself.
|
||||
2. Comparing a `NaN` with another `NaN`.
|
||||
3. Comparing a `NaN` and any other number.
|
||||
|
||||
!!! note "Operator overload resolution"
|
||||
|
||||
Since C++20 overload resolution will consider the _rewritten candidate_ generated from
|
||||
[`operator<=>`](operator_spaceship.md).
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
@ -53,6 +76,11 @@ Linear.
|
||||
--8<-- "examples/operator__greater.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [**operator<=>**](operator_spaceship.md) comparison: 3-way
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 1.0.0.
|
||||
1. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0.
|
||||
2. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0.
|
||||
|
@ -1,17 +1,25 @@
|
||||
# <small>nlohmann::basic_json::</small>operator<=
|
||||
|
||||
```cpp
|
||||
bool operator<=(const_reference lhs, const_reference rhs) noexcept,
|
||||
// until C++20
|
||||
bool operator<=(const_reference lhs, const_reference rhs) noexcept; // (1)
|
||||
|
||||
template<typename ScalarType>
|
||||
bool operator<=(const_reference lhs, const ScalarType rhs) noexcept;
|
||||
bool operator<=(const_reference lhs, const ScalarType rhs) noexcept; // (2)
|
||||
|
||||
template<typename ScalarType>
|
||||
bool operator<=(ScalarType lhs, const const_reference rhs) noexcept;
|
||||
bool operator<=(ScalarType lhs, const const_reference rhs) noexcept; // (2)
|
||||
```
|
||||
|
||||
Compares whether one JSON value `lhs` is less than or equal to another JSON value `rhs` by calculating
|
||||
`#cpp !(rhs < lhs)`.
|
||||
1. Compares whether one JSON value `lhs` is less than or equal to another JSON value `rhs`
|
||||
according to the following rules:
|
||||
- The comparison always yields `#!cpp false` if (1) either operand is discarded, or (2) either
|
||||
operand is `NaN` and the other operand is either `NaN` or any other number.
|
||||
- Otherwise, returns the result of `#!cpp !(rhs < lhs)`.
|
||||
|
||||
1. Compares wether a JSON value is less than or equal to a scalar or a scalar is less than or equal
|
||||
to a JSON value by converting the scalar to a JSON value and comparing both JSON values according
|
||||
to 1.
|
||||
|
||||
## Template parameters
|
||||
|
||||
@ -38,6 +46,21 @@ No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
Linear.
|
||||
|
||||
## Notes
|
||||
|
||||
!!! note "Comparing `NaN`"
|
||||
|
||||
`NaN` values are unordered within the domain of numbers.
|
||||
The following comparisons all yield `#!cpp false`:
|
||||
1. Comparing a `NaN` with itself.
|
||||
2. Comparing a `NaN` with another `NaN`.
|
||||
3. Comparing a `NaN` and any other number.
|
||||
|
||||
!!! note "Operator overload resolution"
|
||||
|
||||
Since C++20 overload resolution will consider the _rewritten candidate_ generated from
|
||||
[`operator<=>`](operator_spaceship.md).
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
@ -54,6 +77,11 @@ Linear.
|
||||
--8<-- "examples/operator__lessequal.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [**operator<=>**](operator_spaceship.md) comparison: 3-way
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 1.0.0.
|
||||
1. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0.
|
||||
2. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0.
|
||||
|
@ -1,31 +1,34 @@
|
||||
# <small>nlohmann::basic_json::</small>operator<
|
||||
|
||||
```cpp
|
||||
bool operator<(const_reference lhs, const_reference rhs) noexcept;
|
||||
// until C++20
|
||||
bool operator<(const_reference lhs, const_reference rhs) noexcept; // (1)
|
||||
|
||||
template<typename ScalarType>
|
||||
bool operator<(const_reference lhs, const ScalarType rhs) noexcept;
|
||||
bool operator<(const_reference lhs, const ScalarType rhs) noexcept; // (2)
|
||||
|
||||
template<typename ScalarType>
|
||||
bool operator<(ScalarType lhs, const const_reference rhs) noexcept;
|
||||
bool operator<(ScalarType lhs, const const_reference rhs) noexcept; // (2)
|
||||
```
|
||||
|
||||
Compares whether one JSON value `lhs` is less than another JSON value `rhs` according to the following rules:
|
||||
1. Compares whether one JSON value `lhs` is less than another JSON value `rhs` according to the
|
||||
following rules:
|
||||
- If either operand is discarded, the comparison yields `#!cpp false`.
|
||||
- If both operands have the same type, the values are compared using their respective `operator<`.
|
||||
- Integer and floating-point numbers are automatically converted before comparison.
|
||||
- In case `lhs` and `rhs` have different types, the values are ignored and the order of the types
|
||||
is considered, which is:
|
||||
1. null
|
||||
2. boolean
|
||||
3. number (all types)
|
||||
4. object
|
||||
5. array
|
||||
6. string
|
||||
7. binary
|
||||
For instance, any boolean value is considered less than any string.
|
||||
|
||||
- If `lhs` and `rhs` have the same type, the values are compared using the default `<` operator.
|
||||
- Integer and floating-point numbers are automatically converted before comparison
|
||||
- Discarded values a
|
||||
- In case `lhs` and `rhs` have different types, the values are ignored and the order of the types is considered, which
|
||||
is:
|
||||
1. null
|
||||
2. boolean
|
||||
3. number (all types)
|
||||
4. object
|
||||
5. array
|
||||
6. string
|
||||
7. binary
|
||||
|
||||
For instance, any boolean value is considered less than any string.
|
||||
2. Compares wether a JSON value is less than a scalar or a scalar is less than a JSON value by converting
|
||||
the scalar to a JSON value and comparing both JSON values according to 1.
|
||||
|
||||
## Template parameters
|
||||
|
||||
@ -52,6 +55,21 @@ No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
Linear.
|
||||
|
||||
## Notes
|
||||
|
||||
!!! note "Comparing `NaN`"
|
||||
|
||||
`NaN` values are unordered within the domain of numbers.
|
||||
The following comparisons all yield `#!cpp false`:
|
||||
1. Comparing a `NaN` with itself.
|
||||
2. Comparing a `NaN` with another `NaN`.
|
||||
3. Comparing a `NaN` and any other number.
|
||||
|
||||
!!! note "Operator overload resolution"
|
||||
|
||||
Since C++20 overload resolution will consider the _rewritten candidate_ generated from
|
||||
[`operator<=>`](operator_spaceship.md).
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
@ -68,6 +86,11 @@ Linear.
|
||||
--8<-- "examples/operator__less.output"
|
||||
```
|
||||
|
||||
## See also
|
||||
|
||||
- [**operator<=>**](operator_spaceship.md) comparison: 3-way
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 1.0.0.
|
||||
1. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0.
|
||||
2. Added in version 1.0.0. Conditionally removed since C++20 in version 3.11.0.
|
||||
|
@ -1,16 +1,32 @@
|
||||
# <small>nlohmann::basic_json::</small>operator!=
|
||||
|
||||
```cpp
|
||||
bool operator!=(const_reference lhs, const_reference rhs) noexcept;
|
||||
// until C++20
|
||||
bool operator!=(const_reference lhs, const_reference rhs) noexcept; // (1)
|
||||
|
||||
template<typename ScalarType>
|
||||
bool operator!=(const_reference lhs, const ScalarType rhs) noexcept;
|
||||
bool operator!=(const_reference lhs, const ScalarType rhs) noexcept; // (2)
|
||||
|
||||
template<typename ScalarType>
|
||||
bool operator!=(ScalarType lhs, const const_reference rhs) noexcept;
|
||||
bool operator!=(ScalarType lhs, const const_reference rhs) noexcept; // (2)
|
||||
|
||||
// since C++20
|
||||
class basic_json {
|
||||
bool operator!=(const_reference rhs) const noexcept; // (1)
|
||||
|
||||
template<typename ScalarType>
|
||||
bool operator!=(ScalarType rhs) const noexcept; // (2)
|
||||
};
|
||||
```
|
||||
|
||||
Compares two JSON values for inequality by calculating `#!cpp !(lhs == rhs)`.
|
||||
1. Compares two JSON values for inequality according to the following rules:
|
||||
- The comparison always yields `#!cpp false` if (1) either operand is discarded, or (2) either
|
||||
operand is `NaN` and 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 value and comparing both JSON values according to 1.
|
||||
|
||||
## Template parameters
|
||||
|
||||
@ -27,7 +43,7 @@ Compares two JSON values for inequality by calculating `#!cpp !(lhs == rhs)`.
|
||||
|
||||
## Return value
|
||||
|
||||
whether the values `lhs` and `rhs` are not equal
|
||||
whether the values `lhs`/`*this` and `rhs` are not equal
|
||||
|
||||
## Exception safety
|
||||
|
||||
@ -37,6 +53,16 @@ No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
Linear.
|
||||
|
||||
## Notes
|
||||
|
||||
!!! note "Comparing `NaN`"
|
||||
|
||||
`NaN` values are unordered within the domain of numbers.
|
||||
The following comparisons all yield `#!cpp false`:
|
||||
1. Comparing a `NaN` with itself.
|
||||
2. Comparing a `NaN` with another `NaN`.
|
||||
3. Comparing a `NaN` and any other number.
|
||||
|
||||
## Examples
|
||||
|
||||
??? example
|
||||
@ -69,4 +95,5 @@ Linear.
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 1.0.0.
|
||||
1. Added in version 1.0.0. Added C++20 member functions in version 3.11.0.
|
||||
2. Added in version 1.0.0. Added C++20 member functions in version 3.11.0.
|
||||
|
70
docs/mkdocs/docs/api/basic_json/operator_spaceship.md
Normal file
70
docs/mkdocs/docs/api/basic_json/operator_spaceship.md
Normal file
@ -0,0 +1,70 @@
|
||||
# <small>nlohmann::basic_json::</small>operator<=>
|
||||
|
||||
```cpp
|
||||
// since C++20
|
||||
class basic_json {
|
||||
std::partial_ordering operator<=>(const_reference rhs) const noexcept; // (1)
|
||||
|
||||
template<typename ScalarType>
|
||||
std::partial_ordering operator<=>(const ScalarType rhs) const noexcept; // (2)
|
||||
};
|
||||
```
|
||||
|
||||
1. 3-way compares two JSON values producing a result of type `std::partial_ordering` according to the following rules:
|
||||
- Two JSON values compare with a result of `std::partial_ordering::unordered` if either value is discarded.
|
||||
- If both JSON values are of the same type, the result is produced by 3-way comparing their stored values using their
|
||||
respective `operator<=>`.
|
||||
- Integer and floating-point numbers are converted to their common type and then 3-way compared using their respective
|
||||
`operator<=>`.
|
||||
For instance, comparing an integer and a floating-point value will 3-way compare the first value convertered to
|
||||
floating-point with the second value.
|
||||
- Otherwise, yields a result by comparing the type (see [`value_t`](value_t.md)).
|
||||
|
||||
2. 3-way compares a JSON value and a scalar or a scalar and a JSON value by converting the scalar to a JSON value and 3-way
|
||||
comparing both JSON values (see 1).
|
||||
|
||||
## Template parameters
|
||||
|
||||
`ScalarType`
|
||||
: a scalar type according to `std::is_scalar<ScalarType>::value`
|
||||
|
||||
## Parameters
|
||||
|
||||
`rhs` (in)
|
||||
: second value to consider
|
||||
|
||||
## Return value
|
||||
|
||||
the `std::partial_ordering` of the 3-way comparison of `*this` and `rhs`
|
||||
|
||||
## Exception safety
|
||||
|
||||
No-throw guarantee: this function never throws exceptions.
|
||||
|
||||
## Complexity
|
||||
|
||||
Linear.
|
||||
|
||||
## Notes
|
||||
|
||||
!!! note "Comparing `NaN`"
|
||||
|
||||
- `NaN` values are unordered within the domain of numbers.
|
||||
The following comparisons all yield `std::partial_ordering::unordered`:
|
||||
1. Comparing a `NaN` with itself.
|
||||
2. Comparing a `NaN` with another `NaN`.
|
||||
3. Comparing a `NaN` and any other number.
|
||||
|
||||
## See also
|
||||
|
||||
- [**operator==**](operator_eq.md) - comparison: equal
|
||||
- [**operator!=**](operator_ne.md) - comparison: not equal
|
||||
- [**operator<**](operator_lt.md) - comparison: less than
|
||||
- [**operator<=**](operator_le.md) - comparison: less than or equal
|
||||
- [**operator>**](operator_gt.md) - comparison: greater than
|
||||
- [**operator>=**](operator_ge.md) - comparison: greater than or equal
|
||||
|
||||
## Version history
|
||||
|
||||
1. Added in version 3.11.0.
|
||||
2. Added in version 3.11.0.
|
@ -24,10 +24,41 @@ functions [`is_null`](is_null.md), [`is_object`](is_object.md), [`is_array`](is_
|
||||
|
||||
## Notes
|
||||
|
||||
There are three enumeration entries (number_integer, number_unsigned, and number_float), because the library
|
||||
distinguishes these three types for numbers: [`number_unsigned_t`](number_unsigned_t.md) is used for unsigned integers,
|
||||
[`number_integer_t`](number_integer_t.md) is used for signed integers, and [`number_float_t`](number_float_t.md) is used
|
||||
for floating-point numbers or to approximate integers which do not fit in the limits of their respective type.
|
||||
!!! note "Ordering"
|
||||
|
||||
The order of types is as follows:
|
||||
|
||||
1. `null`
|
||||
2. `boolean`
|
||||
3. `number_integer`, `number_unsigned`, `number_float`
|
||||
4. `object`
|
||||
5. `array`
|
||||
6. `string`
|
||||
7. `binary`
|
||||
|
||||
`discarded` is unordered.
|
||||
|
||||
!!! note "Types of numbers"
|
||||
|
||||
There are three enumerators for numbers (`number_integer`, `number_unsigned`, and `number_float`) to distinguish
|
||||
between different types of numbers:
|
||||
|
||||
- [`number_unsigned_t`](number_unsigned_t.md) for unsigned integers
|
||||
- [`number_integer_t`](number_integer_t.md) for signed integers
|
||||
- [`number_float_t`](number_float_t.md) for floating-point numbers or to approximate integers which do not fit
|
||||
into the limits of their respective type
|
||||
|
||||
!!! warning "Comparison operators"
|
||||
|
||||
`operator<` and `operator<=>` (since C++20) are overloaded and compare according to the ordering described above.
|
||||
Until C++20 all other relational and equality operators yield results according to the integer value of each
|
||||
enumerator.
|
||||
Since C++20 some compilers consider the _rewritten candidates_ generated from `operator<=>` during overload
|
||||
resolution, while others do not.
|
||||
For predictable and portable behavior use:
|
||||
|
||||
- `operator<` or `operator<=>` when wanting to compare according to the order described above
|
||||
- `operator==` or `operator!=` when wanting to compare according to each enumerators integer value
|
||||
|
||||
## Examples
|
||||
|
||||
|
@ -17,6 +17,8 @@ header. See also the [macro overview page](../../features/macros.md).
|
||||
|
||||
- [**JSON_HAS_CPP_11**<br>**JSON_HAS_CPP_14**<br>**JSON_HAS_CPP_17**<br>**JSON_HAS_CPP_20**](json_has_cpp_11.md) - set supported C++ standard
|
||||
- [**JSON_HAS_FILESYSTEM**<br>**JSON_HAS_EXPERIMENTAL_FILESYSTEM**](json_has_filesystem.md) - control `std::filesystem` support
|
||||
- [**JSON_HAS_RANGES**](json_has_ranges.md) - control `std::ranges` support
|
||||
- [**JSON_HAS_THREE_WAY_COMPARISON**](json_has_three_way_comparison.md) - control 3-way comparison support
|
||||
- [**JSON_NO_IO**](json_no_io.md) - switch off functions relying on certain C++ I/O headers
|
||||
- [**JSON_SKIP_UNSUPPORTED_COMPILER_CHECK**](json_skip_unsupported_compiler_check.md) - do not warn about unsupported compilers
|
||||
|
||||
@ -29,6 +31,12 @@ header. See also the [macro overview page](../../features/macros.md).
|
||||
|
||||
- [**JSON_USE_IMPLICIT_CONVERSIONS**](json_use_implicit_conversions.md) - control implicit conversions
|
||||
|
||||
<!-- comment-->
|
||||
## Comparison behavior
|
||||
|
||||
- [**JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON**](json_use_legacy_discarded_value_comparison.md) -
|
||||
control comparison of discarded values
|
||||
|
||||
## Serialization/deserialization macros
|
||||
|
||||
- [**NLOHMANN_DEFINE_TYPE_INTRUSIVE(type, member...)**<br>**NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(type, member...)**](nlohmann_define_type_intrusive.md) - serialization/deserialization of types _with_ access to private variables
|
||||
|
18
docs/mkdocs/docs/api/macros/json_has_ranges.md
Normal file
18
docs/mkdocs/docs/api/macros/json_has_ranges.md
Normal file
@ -0,0 +1,18 @@
|
||||
# JSON_HAS_RANGES
|
||||
|
||||
```cpp
|
||||
#define JSON_HAS_RANGES /* value */
|
||||
```
|
||||
|
||||
This macro indicates whether the standard library has any support for ranges. Implies support for concepts.
|
||||
Possible values are `1` when supported or `0` when unsupported.
|
||||
|
||||
## Default definition
|
||||
|
||||
The default value is detected based on the preprocessor macro `#!cpp __cpp_lib_ranges`.
|
||||
|
||||
When the macro is not defined, the library will define it to its default value.
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.11.0.
|
19
docs/mkdocs/docs/api/macros/json_has_three_way_comparison.md
Normal file
19
docs/mkdocs/docs/api/macros/json_has_three_way_comparison.md
Normal file
@ -0,0 +1,19 @@
|
||||
# JSON_HAS_THREE_WAY_COMPARISON
|
||||
|
||||
```cpp
|
||||
#define JSON_HAS_THREE_WAY_COMPARISON /* value */
|
||||
```
|
||||
|
||||
This macro indicates whether the compiler and standard library support 3-way comparison.
|
||||
Possible values are `1` when supported or `0` when unsupported.
|
||||
|
||||
## Default definition
|
||||
|
||||
The default value is detected based on the preprocessor macros `#!cpp __cpp_impl_three_way_comparison`
|
||||
and `#!cpp __cpp_lib_three_way_comparison`.
|
||||
|
||||
When the macro is not defined, the library will define it to its default value.
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.11.0.
|
@ -0,0 +1,61 @@
|
||||
# JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
|
||||
```cpp
|
||||
#define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON /* value */
|
||||
```
|
||||
|
||||
This macro enables the (incorrect) legacy comparison behavior of discarded JSON values.
|
||||
Possible values are `1` to enable or `0` to disable (default).
|
||||
|
||||
When enabled, comparisons involving at least one discarded JSON value yield results as follows:
|
||||
|
||||
| **Operator** | **Result** |
|
||||
|--------------|---------------|
|
||||
| `==` | `#!cpp false` |
|
||||
| `!=` | `#!cpp true` |
|
||||
| `<` | `#!cpp false` |
|
||||
| `<=` | `#!cpp true` |
|
||||
| `>=` | `#!cpp true` |
|
||||
| `>` | `#!cpp false` |
|
||||
|
||||
Otherwise, comparisons involving at least one discarded JSON value always yield `#!cpp false`.
|
||||
|
||||
## Default definition
|
||||
|
||||
The default value is `0`.
|
||||
|
||||
```cpp
|
||||
#define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
|
||||
```
|
||||
|
||||
When the macro is not defined, the library will define it to its default value.
|
||||
|
||||
## Notes
|
||||
|
||||
!!! warning "Inconsistent behavior in C++20 and beyond"
|
||||
|
||||
When targeting C++20 or above, enabling the legacy comparison behavior is _strongly_
|
||||
discouraged.
|
||||
|
||||
- The 3-way comparison operator (`<=>`) will always give the correct result
|
||||
(`#!cpp std::partial_ordering::unordered`) regardless of the value of
|
||||
`JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON`.
|
||||
- Overloads for the equality and relational operators emulate the legacy behavior.
|
||||
|
||||
Code outside your control may use either 3-way comparison or the equality and
|
||||
relational operators, resulting in inconsistent and unpredictable behavior.
|
||||
|
||||
See [`operator<=>`](../basic_json/operator_spaceship.md) for more information on 3-way
|
||||
comparison.
|
||||
|
||||
!!! warning "Deprecation"
|
||||
|
||||
The legacy comparison behavior is deprecated and may be removed in a future major
|
||||
version release.
|
||||
|
||||
New code should not depend on it and existing code should try to remove or rewrite
|
||||
expressions relying on it.
|
||||
|
||||
## Version history
|
||||
|
||||
- Added in version 3.11.0.
|
4
docs/mkdocs/docs/css/custom.css
Normal file
4
docs/mkdocs/docs/css/custom.css
Normal file
@ -0,0 +1,4 @@
|
||||
/* disable ligatures in code and preformatted blocks */
|
||||
code, pre {
|
||||
font-variant-ligatures: none;
|
||||
}
|
@ -154,15 +154,16 @@ nav:
|
||||
- 'operator value_t': api/basic_json/operator_value_t.md
|
||||
- 'operator[]': api/basic_json/operator[].md
|
||||
- 'operator=': api/basic_json/operator=.md
|
||||
- 'operator+=': api/basic_json/operator+=.md
|
||||
- 'operator==': api/basic_json/operator_eq.md
|
||||
- 'operator!=': api/basic_json/operator_ne.md
|
||||
- 'operator<': api/basic_json/operator_lt.md
|
||||
- 'operator<<': api/basic_json/operator_ltlt.md
|
||||
- 'operator<=': api/basic_json/operator_le.md
|
||||
- 'operator>': api/basic_json/operator_gt.md
|
||||
- 'operator>>': api/basic_json/operator_gtgt.md
|
||||
- 'operator<=': api/basic_json/operator_le.md
|
||||
- 'operator>=': api/basic_json/operator_ge.md
|
||||
- 'operator+=': api/basic_json/operator+=.md
|
||||
- 'operator<=>': api/basic_json/operator_spaceship.md
|
||||
- 'operator<<': api/basic_json/operator_ltlt.md
|
||||
- 'operator>>': api/basic_json/operator_gtgt.md
|
||||
- 'operator""_json': api/basic_json/operator_literal_json.md
|
||||
- 'operator""_json_pointer': api/basic_json/operator_literal_json_pointer.md
|
||||
- 'out_of_range': api/basic_json/out_of_range.md
|
||||
@ -246,6 +247,8 @@ nav:
|
||||
- 'JSON_HAS_CPP_20': api/macros/json_has_cpp_11.md
|
||||
- 'JSON_HAS_EXPERIMENTAL_FILESYSTEM': api/macros/json_has_filesystem.md
|
||||
- 'JSON_HAS_FILESYSTEM': api/macros/json_has_filesystem.md
|
||||
- 'JSON_HAS_RANGES': api/macros/json_has_ranges.md
|
||||
- 'JSON_HAS_THREE_WAY_COMPARISON': api/macros/json_has_three_way_comparison.md
|
||||
- 'JSON_NOEXCEPTION': api/macros/json_noexception.md
|
||||
- 'JSON_NO_IO': api/macros/json_no_io.md
|
||||
- 'JSON_SKIP_LIBRARY_VERSION_CHECK': api/macros/json_skip_library_version_check.md
|
||||
@ -253,6 +256,7 @@ nav:
|
||||
- 'JSON_THROW_USER': api/macros/json_throw_user.md
|
||||
- 'JSON_TRY_USER': api/macros/json_throw_user.md
|
||||
- 'JSON_USE_IMPLICIT_CONVERSIONS': api/macros/json_use_implicit_conversions.md
|
||||
- 'JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON': api/macros/json_use_legacy_discarded_value_comparison.md
|
||||
- 'NLOHMANN_DEFINE_TYPE_INTRUSIVE': api/macros/nlohmann_define_type_intrusive.md
|
||||
- 'NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT': api/macros/nlohmann_define_type_intrusive.md
|
||||
- 'NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE': api/macros/nlohmann_define_type_non_intrusive.md
|
||||
@ -319,5 +323,8 @@ plugins:
|
||||
minify_html: true
|
||||
- git-revision-date-localized
|
||||
|
||||
extra_css:
|
||||
- css/custom.css
|
||||
|
||||
extra_javascript:
|
||||
- https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-MML-AM_CHTML
|
||||
|
@ -39,7 +39,7 @@ namespace nlohmann
|
||||
namespace detail
|
||||
{
|
||||
template<typename BasicJsonType>
|
||||
void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
|
||||
inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_null()))
|
||||
{
|
||||
@ -86,7 +86,7 @@ void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_boolean()))
|
||||
{
|
||||
@ -96,7 +96,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::boolean_t& b)
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
||||
{
|
||||
@ -111,7 +111,7 @@ template <
|
||||
std::is_assignable<StringType&, const typename BasicJsonType::string_t>::value
|
||||
&& !std::is_same<typename BasicJsonType::string_t, StringType>::value
|
||||
&& !is_json_ref<StringType>::value, int > = 0 >
|
||||
void from_json(const BasicJsonType& j, StringType& s)
|
||||
inline void from_json(const BasicJsonType& j, StringType& s)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
||||
{
|
||||
@ -122,26 +122,26 @@ void from_json(const BasicJsonType& j, StringType& s)
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
|
||||
{
|
||||
get_arithmetic_value(j, val);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_unsigned_t& val)
|
||||
{
|
||||
get_arithmetic_value(j, val);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_integer_t& val)
|
||||
{
|
||||
get_arithmetic_value(j, val);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename EnumType,
|
||||
enable_if_t<std::is_enum<EnumType>::value, int> = 0>
|
||||
void from_json(const BasicJsonType& j, EnumType& e)
|
||||
inline void from_json(const BasicJsonType& j, EnumType& e)
|
||||
{
|
||||
typename std::underlying_type<EnumType>::type val;
|
||||
get_arithmetic_value(j, val);
|
||||
@ -151,7 +151,7 @@ void from_json(const BasicJsonType& j, EnumType& e)
|
||||
// forward_list doesn't have an insert method
|
||||
template<typename BasicJsonType, typename T, typename Allocator,
|
||||
enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
|
||||
void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
|
||||
inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||
{
|
||||
@ -168,7 +168,7 @@ void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
|
||||
// valarray doesn't have an insert method
|
||||
template<typename BasicJsonType, typename T,
|
||||
enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
|
||||
void from_json(const BasicJsonType& j, std::valarray<T>& l)
|
||||
inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||
{
|
||||
@ -193,7 +193,7 @@ auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
|
||||
inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType::array_t& arr, priority_tag<3> /*unused*/)
|
||||
{
|
||||
arr = *j.template get_ptr<const typename BasicJsonType::array_t*>();
|
||||
}
|
||||
@ -237,8 +237,8 @@ template<typename BasicJsonType, typename ConstructibleArrayType,
|
||||
enable_if_t<
|
||||
std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
|
||||
int> = 0>
|
||||
void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,
|
||||
priority_tag<0> /*unused*/)
|
||||
inline void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,
|
||||
priority_tag<0> /*unused*/)
|
||||
{
|
||||
using std::end;
|
||||
|
||||
@ -295,7 +295,7 @@ auto from_json(BasicJsonType&& j, identity_tag<std::array<T, N>> tag)
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin)
|
||||
inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_binary()))
|
||||
{
|
||||
@ -307,7 +307,7 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t& bin)
|
||||
|
||||
template<typename BasicJsonType, typename ConstructibleObjectType,
|
||||
enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
|
||||
void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||
inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
|
||||
{
|
||||
@ -339,7 +339,7 @@ template < typename BasicJsonType, typename ArithmeticType,
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&
|
||||
!std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
|
||||
int > = 0 >
|
||||
void from_json(const BasicJsonType& j, ArithmeticType& val)
|
||||
inline void from_json(const BasicJsonType& j, ArithmeticType& val)
|
||||
{
|
||||
switch (static_cast<value_t>(j))
|
||||
{
|
||||
@ -389,7 +389,7 @@ std::pair<A1, A2> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::pair
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename A1, typename A2>
|
||||
void from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priority_tag<1> /*unused*/)
|
||||
inline void from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priority_tag<1> /*unused*/)
|
||||
{
|
||||
p = from_json_tuple_impl(std::forward<BasicJsonType>(j), identity_tag<std::pair<A1, A2>> {}, priority_tag<0> {});
|
||||
}
|
||||
@ -401,7 +401,7 @@ std::tuple<Args...> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::tu
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename... Args>
|
||||
void from_json_tuple_impl(BasicJsonType&& j, std::tuple<Args...>& t, priority_tag<3> /*unused*/)
|
||||
inline void from_json_tuple_impl(BasicJsonType&& j, std::tuple<Args...>& t, priority_tag<3> /*unused*/)
|
||||
{
|
||||
t = from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {});
|
||||
}
|
||||
@ -421,7 +421,7 @@ auto from_json(BasicJsonType&& j, TupleRelated&& t)
|
||||
template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
|
||||
typename = enable_if_t < !std::is_constructible <
|
||||
typename BasicJsonType::string_t, Key >::value >>
|
||||
void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
|
||||
inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||
{
|
||||
@ -441,7 +441,7 @@ void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>&
|
||||
template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
|
||||
typename = enable_if_t < !std::is_constructible <
|
||||
typename BasicJsonType::string_t, Key >::value >>
|
||||
void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
|
||||
inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
|
||||
{
|
||||
@ -460,7 +460,7 @@ void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyE
|
||||
|
||||
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||
template<typename BasicJsonType>
|
||||
void from_json(const BasicJsonType& j, std_fs::path& p)
|
||||
inline void from_json(const BasicJsonType& j, std_fs::path& p)
|
||||
{
|
||||
if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
|
||||
{
|
||||
@ -482,11 +482,16 @@ struct from_json_fn
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
#ifndef JSON_HAS_CPP_17
|
||||
/// namespace to hold default `from_json` function
|
||||
/// to see why this is required:
|
||||
/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
|
||||
namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)
|
||||
{
|
||||
constexpr const auto& from_json = detail::static_const<detail::from_json_fn>::value; // NOLINT(misc-definitions-in-headers)
|
||||
#endif
|
||||
JSON_INLINE_VARIABLE constexpr const auto& from_json = // NOLINT(misc-definitions-in-headers)
|
||||
detail::static_const<detail::from_json_fn>::value;
|
||||
#ifndef JSON_HAS_CPP_17
|
||||
} // namespace
|
||||
#endif
|
||||
} // namespace nlohmann
|
||||
|
@ -267,55 +267,55 @@ struct external_constructor<value_t::object>
|
||||
|
||||
template<typename BasicJsonType, typename T,
|
||||
enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>
|
||||
void to_json(BasicJsonType& j, T b) noexcept
|
||||
inline void to_json(BasicJsonType& j, T b) noexcept
|
||||
{
|
||||
external_constructor<value_t::boolean>::construct(j, b);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleString,
|
||||
enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>
|
||||
void to_json(BasicJsonType& j, const CompatibleString& s)
|
||||
inline void to_json(BasicJsonType& j, const CompatibleString& s)
|
||||
{
|
||||
external_constructor<value_t::string>::construct(j, s);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)
|
||||
inline void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)
|
||||
{
|
||||
external_constructor<value_t::string>::construct(j, std::move(s));
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename FloatType,
|
||||
enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
|
||||
void to_json(BasicJsonType& j, FloatType val) noexcept
|
||||
inline void to_json(BasicJsonType& j, FloatType val) noexcept
|
||||
{
|
||||
external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleNumberUnsignedType,
|
||||
enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>
|
||||
void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept
|
||||
inline void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept
|
||||
{
|
||||
external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename CompatibleNumberIntegerType,
|
||||
enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>
|
||||
void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept
|
||||
inline void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept
|
||||
{
|
||||
external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename EnumType,
|
||||
enable_if_t<std::is_enum<EnumType>::value, int> = 0>
|
||||
void to_json(BasicJsonType& j, EnumType e) noexcept
|
||||
inline void to_json(BasicJsonType& j, EnumType e) noexcept
|
||||
{
|
||||
using underlying_type = typename std::underlying_type<EnumType>::type;
|
||||
external_constructor<value_t::number_integer>::construct(j, static_cast<underlying_type>(e));
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
void to_json(BasicJsonType& j, const std::vector<bool>& e)
|
||||
inline void to_json(BasicJsonType& j, const std::vector<bool>& e)
|
||||
{
|
||||
external_constructor<value_t::array>::construct(j, e);
|
||||
}
|
||||
@ -328,39 +328,39 @@ template < typename BasicJsonType, typename CompatibleArrayType,
|
||||
!std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
|
||||
!is_basic_json<CompatibleArrayType>::value,
|
||||
int > = 0 >
|
||||
void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
|
||||
inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
|
||||
{
|
||||
external_constructor<value_t::array>::construct(j, arr);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)
|
||||
inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin)
|
||||
{
|
||||
external_constructor<value_t::binary>::construct(j, bin);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename T,
|
||||
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
|
||||
void to_json(BasicJsonType& j, const std::valarray<T>& arr)
|
||||
inline void to_json(BasicJsonType& j, const std::valarray<T>& arr)
|
||||
{
|
||||
external_constructor<value_t::array>::construct(j, std::move(arr));
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
|
||||
inline void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
|
||||
{
|
||||
external_constructor<value_t::array>::construct(j, std::move(arr));
|
||||
}
|
||||
|
||||
template < typename BasicJsonType, typename CompatibleObjectType,
|
||||
enable_if_t < is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value&& !is_basic_json<CompatibleObjectType>::value, int > = 0 >
|
||||
void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
|
||||
inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
|
||||
{
|
||||
external_constructor<value_t::object>::construct(j, obj);
|
||||
}
|
||||
|
||||
template<typename BasicJsonType>
|
||||
void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
|
||||
inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
|
||||
{
|
||||
external_constructor<value_t::object>::construct(j, std::move(obj));
|
||||
}
|
||||
@ -370,13 +370,13 @@ template <
|
||||
enable_if_t < !std::is_constructible<typename BasicJsonType::string_t,
|
||||
const T(&)[N]>::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
int > = 0 >
|
||||
void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
inline void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
|
||||
{
|
||||
external_constructor<value_t::array>::construct(j, arr);
|
||||
}
|
||||
|
||||
template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible<BasicJsonType, T1>::value&& std::is_constructible<BasicJsonType, T2>::value, int > = 0 >
|
||||
void to_json(BasicJsonType& j, const std::pair<T1, T2>& p)
|
||||
inline void to_json(BasicJsonType& j, const std::pair<T1, T2>& p)
|
||||
{
|
||||
j = { p.first, p.second };
|
||||
}
|
||||
@ -384,26 +384,26 @@ void to_json(BasicJsonType& j, const std::pair<T1, T2>& p)
|
||||
// for https://github.com/nlohmann/json/pull/1134
|
||||
template<typename BasicJsonType, typename T,
|
||||
enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>
|
||||
void to_json(BasicJsonType& j, const T& b)
|
||||
inline void to_json(BasicJsonType& j, const T& b)
|
||||
{
|
||||
j = { {b.key(), b.value()} };
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
|
||||
void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)
|
||||
inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)
|
||||
{
|
||||
j = { std::get<Idx>(t)... };
|
||||
}
|
||||
|
||||
template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0>
|
||||
void to_json(BasicJsonType& j, const T& t)
|
||||
inline void to_json(BasicJsonType& j, const T& t)
|
||||
{
|
||||
to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {});
|
||||
}
|
||||
|
||||
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||
template<typename BasicJsonType>
|
||||
void to_json(BasicJsonType& j, const std_fs::path& p)
|
||||
inline void to_json(BasicJsonType& j, const std_fs::path& p)
|
||||
{
|
||||
j = p.string();
|
||||
}
|
||||
@ -420,11 +420,16 @@ struct to_json_fn
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
#ifndef JSON_HAS_CPP_17
|
||||
/// namespace to hold default `to_json` function
|
||||
/// to see why this is required:
|
||||
/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
|
||||
namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)
|
||||
{
|
||||
constexpr const auto& to_json = detail::static_const<detail::to_json_fn>::value; // NOLINT(misc-definitions-in-headers)
|
||||
#endif
|
||||
JSON_INLINE_VARIABLE constexpr const auto& to_json = // NOLINT(misc-definitions-in-headers)
|
||||
detail::static_const<detail::to_json_fn>::value;
|
||||
#ifndef JSON_HAS_CPP_17
|
||||
} // namespace
|
||||
#endif
|
||||
} // namespace nlohmann
|
||||
|
@ -51,9 +51,12 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
|
||||
// make sure BasicJsonType is basic_json or const basic_json
|
||||
static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,
|
||||
"iter_impl only accepts (const) basic_json");
|
||||
// superficial check for the LegacyBidirectionalIterator named requirement
|
||||
static_assert(std::is_base_of<std::bidirectional_iterator_tag, std::bidirectional_iterator_tag>::value
|
||||
&& std::is_base_of<std::bidirectional_iterator_tag, typename array_t::iterator::iterator_category>::value,
|
||||
"basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement.");
|
||||
|
||||
public:
|
||||
|
||||
/// The std::iterator class template (used as a base class to provide typedefs) is deprecated in C++17.
|
||||
/// The C++ Standard has never required user-defined iterators to derive from std::iterator.
|
||||
/// A user-defined iterator should provide publicly accessible typedefs named
|
||||
|
@ -6,6 +6,10 @@
|
||||
#include <tuple> // tuple_size, get, tuple_element
|
||||
#include <utility> // move
|
||||
|
||||
#if JSON_HAS_RANGES
|
||||
#include <ranges> // enable_borrowed_range
|
||||
#endif
|
||||
|
||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
|
||||
@ -25,14 +29,14 @@ template<typename IteratorType> class iteration_proxy_value
|
||||
public:
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = iteration_proxy_value;
|
||||
using pointer = value_type * ;
|
||||
using reference = value_type & ;
|
||||
using pointer = value_type *;
|
||||
using reference = value_type &;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type;
|
||||
|
||||
private:
|
||||
/// the iterator
|
||||
IteratorType anchor;
|
||||
IteratorType anchor{};
|
||||
/// an index for arrays (used to create key names)
|
||||
std::size_t array_index = 0;
|
||||
/// last stringified array index
|
||||
@ -40,15 +44,30 @@ template<typename IteratorType> class iteration_proxy_value
|
||||
/// a string representation of the array index
|
||||
mutable string_type array_index_str = "0";
|
||||
/// an empty string (to return a reference for primitive values)
|
||||
const string_type empty_str{};
|
||||
string_type empty_str{};
|
||||
|
||||
public:
|
||||
explicit iteration_proxy_value(IteratorType it) noexcept
|
||||
explicit iteration_proxy_value() = default;
|
||||
explicit iteration_proxy_value(IteratorType it, std::size_t array_index_ = 0)
|
||||
noexcept(std::is_nothrow_move_constructible<IteratorType>::value
|
||||
&& std::is_nothrow_default_constructible<string_type>::value)
|
||||
: anchor(std::move(it))
|
||||
, array_index(array_index_)
|
||||
{}
|
||||
|
||||
iteration_proxy_value(iteration_proxy_value const&) = default;
|
||||
iteration_proxy_value& operator=(iteration_proxy_value const&) = default;
|
||||
// older GCCs are a bit fussy and require explicit noexcept specifiers on defaulted functions
|
||||
iteration_proxy_value(iteration_proxy_value&&)
|
||||
noexcept(std::is_nothrow_move_constructible<IteratorType>::value
|
||||
&& std::is_nothrow_move_constructible<string_type>::value) = default;
|
||||
iteration_proxy_value& operator=(iteration_proxy_value&&)
|
||||
noexcept(std::is_nothrow_move_assignable<IteratorType>::value
|
||||
&& std::is_nothrow_move_assignable<string_type>::value) = default;
|
||||
~iteration_proxy_value() = default;
|
||||
|
||||
/// dereference operator (needed for range-based for)
|
||||
iteration_proxy_value& operator*()
|
||||
const iteration_proxy_value& operator*() const
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
@ -62,6 +81,14 @@ template<typename IteratorType> class iteration_proxy_value
|
||||
return *this;
|
||||
}
|
||||
|
||||
iteration_proxy_value operator++(int)& // NOLINT(cert-dcl21-cpp)
|
||||
{
|
||||
auto tmp = iteration_proxy_value(anchor, array_index);
|
||||
++anchor;
|
||||
++array_index;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/// equality operator (needed for InputIterator)
|
||||
bool operator==(const iteration_proxy_value& o) const
|
||||
{
|
||||
@ -122,25 +149,34 @@ template<typename IteratorType> class iteration_proxy
|
||||
{
|
||||
private:
|
||||
/// the container to iterate
|
||||
typename IteratorType::reference container;
|
||||
typename IteratorType::pointer container = nullptr;
|
||||
|
||||
public:
|
||||
explicit iteration_proxy() = default;
|
||||
|
||||
/// construct iteration proxy from a container
|
||||
explicit iteration_proxy(typename IteratorType::reference cont) noexcept
|
||||
: container(cont) {}
|
||||
: container(&cont) {}
|
||||
|
||||
iteration_proxy(iteration_proxy const&) = default;
|
||||
iteration_proxy& operator=(iteration_proxy const&) = default;
|
||||
iteration_proxy(iteration_proxy&&) noexcept = default;
|
||||
iteration_proxy& operator=(iteration_proxy&&) noexcept = default;
|
||||
~iteration_proxy() = default;
|
||||
|
||||
/// return iterator begin (needed for range-based for)
|
||||
iteration_proxy_value<IteratorType> begin() noexcept
|
||||
iteration_proxy_value<IteratorType> begin() const noexcept
|
||||
{
|
||||
return iteration_proxy_value<IteratorType>(container.begin());
|
||||
return iteration_proxy_value<IteratorType>(container->begin());
|
||||
}
|
||||
|
||||
/// return iterator end (needed for range-based for)
|
||||
iteration_proxy_value<IteratorType> end() noexcept
|
||||
iteration_proxy_value<IteratorType> end() const noexcept
|
||||
{
|
||||
return iteration_proxy_value<IteratorType>(container.end());
|
||||
return iteration_proxy_value<IteratorType>(container->end());
|
||||
}
|
||||
};
|
||||
|
||||
// Structured Bindings Support
|
||||
// For further reference see https://blog.tartanllama.xyz/structured-bindings/
|
||||
// And see https://github.com/nlohmann/json/pull/1391
|
||||
@ -187,3 +223,8 @@ class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
} // namespace std
|
||||
|
||||
#if JSON_HAS_RANGES
|
||||
template <typename IteratorType>
|
||||
inline constexpr bool ::std::ranges::enable_borrowed_range<::nlohmann::detail::iteration_proxy<IteratorType>> = true;
|
||||
#endif
|
||||
|
@ -37,6 +37,12 @@
|
||||
#define JSON_HAS_CPP_11
|
||||
#endif
|
||||
|
||||
#ifdef __has_include
|
||||
#if __has_include(<version>)
|
||||
#include <version>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(JSON_HAS_FILESYSTEM) && !defined(JSON_HAS_EXPERIMENTAL_FILESYSTEM)
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#if defined(__cpp_lib_filesystem)
|
||||
@ -98,14 +104,31 @@
|
||||
#endif
|
||||
|
||||
#ifndef JSON_HAS_THREE_WAY_COMPARISON
|
||||
#if defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L \
|
||||
&& defined(__cpp_impl_three_way_comparison)&& __cpp_impl_three_way_comparison >= 201907L
|
||||
#if defined(__cpp_impl_three_way_comparison) && __cpp_impl_three_way_comparison >= 201907L \
|
||||
&& defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L
|
||||
#define JSON_HAS_THREE_WAY_COMPARISON 1
|
||||
#else
|
||||
#define JSON_HAS_THREE_WAY_COMPARISON 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef JSON_HAS_RANGES
|
||||
// ranges header shipping in GCC 11.1.0 (released 2021-04-27) has syntax error
|
||||
#if defined(__GLIBCXX__) && __GLIBCXX__ == 20210427
|
||||
#define JSON_HAS_RANGES 0
|
||||
#elif defined(__cpp_lib_ranges)
|
||||
#define JSON_HAS_RANGES 1
|
||||
#else
|
||||
#define JSON_HAS_RANGES 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#define JSON_INLINE_VARIABLE inline
|
||||
#else
|
||||
#define JSON_INLINE_VARIABLE
|
||||
#endif
|
||||
|
||||
#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address)
|
||||
#define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]]
|
||||
#else
|
||||
@ -429,3 +452,7 @@
|
||||
#ifndef JSON_DIAGNOSTICS
|
||||
#define JSON_DIAGNOSTICS 0
|
||||
#endif
|
||||
|
||||
#ifndef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#define JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON 0
|
||||
#endif
|
||||
|
@ -14,6 +14,7 @@
|
||||
#undef NLOHMANN_BASIC_JSON_TPL
|
||||
#undef JSON_EXPLICIT
|
||||
#undef NLOHMANN_CAN_CALL_STD_FUNC_IMPL
|
||||
#undef JSON_INLINE_VARIABLE
|
||||
#undef JSON_NO_UNIQUE_ADDRESS
|
||||
|
||||
#ifndef JSON_TEST_KEEP_MACROS
|
||||
@ -26,6 +27,8 @@
|
||||
#undef JSON_HAS_FILESYSTEM
|
||||
#undef JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||
#undef JSON_HAS_THREE_WAY_COMPARISON
|
||||
#undef JSON_HAS_RANGES
|
||||
#undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
#endif
|
||||
|
||||
#include <nlohmann/thirdparty/hedley/hedley_undef.hpp>
|
||||
|
@ -5,6 +5,11 @@
|
||||
#include <cstdint> // uint8_t
|
||||
#include <string> // string
|
||||
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||
#include <compare> // partial_ordering
|
||||
#endif
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
@ -64,7 +69,11 @@ Returns an ordering that is similar to Python:
|
||||
|
||||
@since version 1.0.0
|
||||
*/
|
||||
inline bool operator<(const value_t lhs, const value_t rhs) noexcept
|
||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||
inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD*
|
||||
#else
|
||||
inline bool operator<(const value_t lhs, const value_t rhs) noexcept
|
||||
#endif
|
||||
{
|
||||
static constexpr std::array<std::uint8_t, 9> order = {{
|
||||
0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */,
|
||||
@ -75,7 +84,26 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept
|
||||
|
||||
const auto l_index = static_cast<std::size_t>(lhs);
|
||||
const auto r_index = static_cast<std::size_t>(rhs);
|
||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||
if (l_index < order.size() && r_index < order.size())
|
||||
{
|
||||
return order[l_index] <=> order[r_index]; // *NOPAD*
|
||||
}
|
||||
return std::partial_ordering::unordered;
|
||||
#else
|
||||
return l_index < order.size() && r_index < order.size() && order[l_index] < order[r_index];
|
||||
#endif
|
||||
}
|
||||
|
||||
// GCC selects the built-in operator< over an operator rewritten from
|
||||
// a user-defined spaceship operator
|
||||
// Clang, MSVC, and ICC select the rewritten candidate
|
||||
// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200)
|
||||
#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__)
|
||||
inline bool operator<(const value_t lhs, const value_t rhs) noexcept
|
||||
{
|
||||
return std::is_lt(lhs <=> rhs); // *NOPAD*
|
||||
}
|
||||
#endif
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
@ -1905,7 +1905,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
detail::negation<std::is_same<ValueType, typename string_t::value_type>>,
|
||||
detail::negation<detail::is_basic_json<ValueType>>,
|
||||
detail::negation<std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>>,
|
||||
|
||||
#if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) && _MSC_VER >= 1910 && _MSC_VER <= 1914))
|
||||
detail::negation<std::is_same<ValueType, std::string_view>>,
|
||||
#endif
|
||||
@ -3538,7 +3537,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @}
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////
|
||||
// lexicographical comparison operators //
|
||||
//////////////////////////////////////////
|
||||
@ -3546,6 +3544,212 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @name lexicographical comparison operators
|
||||
/// @{
|
||||
|
||||
// note parentheses around operands are necessary; see
|
||||
// https://github.com/nlohmann/json/issues/1530
|
||||
#define JSON_IMPLEMENT_OPERATOR(op, null_result, unordered_result, default_result) \
|
||||
const auto lhs_type = lhs.type(); \
|
||||
const auto rhs_type = rhs.type(); \
|
||||
\
|
||||
if (lhs_type == rhs_type) /* NOLINT(readability/braces) */ \
|
||||
{ \
|
||||
switch (lhs_type) \
|
||||
{ \
|
||||
case value_t::array: \
|
||||
return (*lhs.m_value.array) op (*rhs.m_value.array); \
|
||||
\
|
||||
case value_t::object: \
|
||||
return (*lhs.m_value.object) op (*rhs.m_value.object); \
|
||||
\
|
||||
case value_t::null: \
|
||||
return (null_result); \
|
||||
\
|
||||
case value_t::string: \
|
||||
return (*lhs.m_value.string) op (*rhs.m_value.string); \
|
||||
\
|
||||
case value_t::boolean: \
|
||||
return (lhs.m_value.boolean) op (rhs.m_value.boolean); \
|
||||
\
|
||||
case value_t::number_integer: \
|
||||
return (lhs.m_value.number_integer) op (rhs.m_value.number_integer); \
|
||||
\
|
||||
case value_t::number_unsigned: \
|
||||
return (lhs.m_value.number_unsigned) op (rhs.m_value.number_unsigned); \
|
||||
\
|
||||
case value_t::number_float: \
|
||||
return (lhs.m_value.number_float) op (rhs.m_value.number_float); \
|
||||
\
|
||||
case value_t::binary: \
|
||||
return (*lhs.m_value.binary) op (*rhs.m_value.binary); \
|
||||
\
|
||||
case value_t::discarded: \
|
||||
default: \
|
||||
return (unordered_result); \
|
||||
} \
|
||||
} \
|
||||
else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float) \
|
||||
{ \
|
||||
return static_cast<number_float_t>(lhs.m_value.number_integer) op rhs.m_value.number_float; \
|
||||
} \
|
||||
else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer) \
|
||||
{ \
|
||||
return lhs.m_value.number_float op static_cast<number_float_t>(rhs.m_value.number_integer); \
|
||||
} \
|
||||
else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float) \
|
||||
{ \
|
||||
return static_cast<number_float_t>(lhs.m_value.number_unsigned) op rhs.m_value.number_float; \
|
||||
} \
|
||||
else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned) \
|
||||
{ \
|
||||
return lhs.m_value.number_float op static_cast<number_float_t>(rhs.m_value.number_unsigned); \
|
||||
} \
|
||||
else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer) \
|
||||
{ \
|
||||
return static_cast<number_integer_t>(lhs.m_value.number_unsigned) op rhs.m_value.number_integer; \
|
||||
} \
|
||||
else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned) \
|
||||
{ \
|
||||
return lhs.m_value.number_integer op static_cast<number_integer_t>(rhs.m_value.number_unsigned); \
|
||||
} \
|
||||
else if(compares_unordered(lhs, rhs))\
|
||||
{\
|
||||
return (unordered_result);\
|
||||
}\
|
||||
\
|
||||
return (default_result);
|
||||
|
||||
JSON_PRIVATE_UNLESS_TESTED:
|
||||
// returns true if:
|
||||
// - any operand is NaN and the other operand is of number type
|
||||
// - any operand is discarded
|
||||
// in legacy mode, discarded values are considered ordered if
|
||||
// an operation is computed as an odd number of inverses of others
|
||||
static bool compares_unordered(const_reference lhs, const_reference rhs, bool inverse = false) noexcept
|
||||
{
|
||||
if ((lhs.is_number_float() && std::isnan(lhs.m_value.number_float) && rhs.is_number())
|
||||
|| (rhs.is_number_float() && std::isnan(rhs.m_value.number_float) && lhs.is_number()))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
return (lhs.is_discarded() || rhs.is_discarded()) && !inverse;
|
||||
#else
|
||||
static_cast<void>(inverse);
|
||||
return lhs.is_discarded() || rhs.is_discarded();
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
bool compares_unordered(const_reference rhs, bool inverse = false) const noexcept
|
||||
{
|
||||
return compares_unordered(*this, rhs, inverse);
|
||||
}
|
||||
|
||||
public:
|
||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||
/// @brief comparison: equal
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
|
||||
bool operator==(const_reference rhs) const noexcept
|
||||
{
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
const_reference lhs = *this;
|
||||
JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
}
|
||||
|
||||
/// @brief comparison: equal
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
|
||||
template<typename ScalarType>
|
||||
requires std::is_scalar_v<ScalarType>
|
||||
bool operator==(ScalarType rhs) const noexcept
|
||||
{
|
||||
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
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
|
||||
std::partial_ordering operator<=>(const_reference rhs) const noexcept // *NOPAD*
|
||||
{
|
||||
const_reference lhs = *this;
|
||||
// default_result is used if we cannot compare values. In that case,
|
||||
// we compare types.
|
||||
JSON_IMPLEMENT_OPERATOR(<=>, // *NOPAD*
|
||||
std::partial_ordering::equivalent,
|
||||
std::partial_ordering::unordered,
|
||||
lhs_type <=> rhs_type) // *NOPAD*
|
||||
}
|
||||
|
||||
/// @brief comparison: 3-way
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_spaceship/
|
||||
template<typename ScalarType>
|
||||
requires std::is_scalar_v<ScalarType>
|
||||
std::partial_ordering operator<=>(ScalarType rhs) const noexcept // *NOPAD*
|
||||
{
|
||||
return *this <=> basic_json(rhs); // *NOPAD*
|
||||
}
|
||||
|
||||
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
// all operators that are computed as an odd number of inverses of others
|
||||
// need to be overloaded to emulate the legacy comparison behavior
|
||||
|
||||
/// @brief comparison: less than or equal
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
|
||||
bool operator<=(const_reference rhs) const noexcept
|
||||
{
|
||||
if (compares_unordered(rhs, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return !(rhs < *this);
|
||||
}
|
||||
|
||||
/// @brief comparison: less than or equal
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/
|
||||
template<typename ScalarType>
|
||||
requires std::is_scalar_v<ScalarType>
|
||||
bool operator<=(ScalarType rhs) const noexcept
|
||||
{
|
||||
return *this <= basic_json(rhs);
|
||||
}
|
||||
|
||||
/// @brief comparison: greater than or equal
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
|
||||
JSON_HEDLEY_DEPRECATED_FOR(3.11.0, undef JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON)
|
||||
bool operator>=(const_reference rhs) const noexcept
|
||||
{
|
||||
if (compares_unordered(rhs, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return !(*this < rhs);
|
||||
}
|
||||
|
||||
/// @brief comparison: greater than or equal
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
|
||||
template<typename ScalarType>
|
||||
requires std::is_scalar_v<ScalarType>
|
||||
bool operator>=(ScalarType rhs) const noexcept
|
||||
{
|
||||
return *this >= basic_json(rhs);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
/// @brief comparison: equal
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_eq/
|
||||
friend bool operator==(const_reference lhs, const_reference rhs) noexcept
|
||||
@ -3554,71 +3758,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
||||
#endif
|
||||
const auto lhs_type = lhs.type();
|
||||
const auto rhs_type = rhs.type();
|
||||
|
||||
if (lhs_type == rhs_type)
|
||||
{
|
||||
switch (lhs_type)
|
||||
{
|
||||
case value_t::array:
|
||||
return *lhs.m_value.array == *rhs.m_value.array;
|
||||
|
||||
case value_t::object:
|
||||
return *lhs.m_value.object == *rhs.m_value.object;
|
||||
|
||||
case value_t::null:
|
||||
return true;
|
||||
|
||||
case value_t::string:
|
||||
return *lhs.m_value.string == *rhs.m_value.string;
|
||||
|
||||
case value_t::boolean:
|
||||
return lhs.m_value.boolean == rhs.m_value.boolean;
|
||||
|
||||
case value_t::number_integer:
|
||||
return lhs.m_value.number_integer == rhs.m_value.number_integer;
|
||||
|
||||
case value_t::number_unsigned:
|
||||
return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned;
|
||||
|
||||
case value_t::number_float:
|
||||
return lhs.m_value.number_float == rhs.m_value.number_float;
|
||||
|
||||
case value_t::binary:
|
||||
return *lhs.m_value.binary == *rhs.m_value.binary;
|
||||
|
||||
case value_t::discarded:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float)
|
||||
{
|
||||
return static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float;
|
||||
}
|
||||
else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer)
|
||||
{
|
||||
return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer);
|
||||
}
|
||||
else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float)
|
||||
{
|
||||
return static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float;
|
||||
}
|
||||
else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned)
|
||||
{
|
||||
return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned);
|
||||
}
|
||||
else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer)
|
||||
{
|
||||
return static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer;
|
||||
}
|
||||
else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned)
|
||||
{
|
||||
return lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned);
|
||||
}
|
||||
|
||||
return false;
|
||||
JSON_IMPLEMENT_OPERATOR( ==, true, false, false)
|
||||
#ifdef __GNUC__
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
@ -3646,6 +3786,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
|
||||
friend bool operator!=(const_reference lhs, const_reference rhs) noexcept
|
||||
{
|
||||
if (compares_unordered(lhs, rhs, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
@ -3671,76 +3815,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_lt/
|
||||
friend bool operator<(const_reference lhs, const_reference rhs) noexcept
|
||||
{
|
||||
const auto lhs_type = lhs.type();
|
||||
const auto rhs_type = rhs.type();
|
||||
|
||||
if (lhs_type == rhs_type)
|
||||
{
|
||||
switch (lhs_type)
|
||||
{
|
||||
case value_t::array:
|
||||
// note parentheses are necessary, see
|
||||
// https://github.com/nlohmann/json/issues/1530
|
||||
return (*lhs.m_value.array) < (*rhs.m_value.array);
|
||||
|
||||
case value_t::object:
|
||||
return (*lhs.m_value.object) < (*rhs.m_value.object);
|
||||
|
||||
case value_t::null:
|
||||
return false;
|
||||
|
||||
case value_t::string:
|
||||
return (*lhs.m_value.string) < (*rhs.m_value.string);
|
||||
|
||||
case value_t::boolean:
|
||||
return (lhs.m_value.boolean) < (rhs.m_value.boolean);
|
||||
|
||||
case value_t::number_integer:
|
||||
return (lhs.m_value.number_integer) < (rhs.m_value.number_integer);
|
||||
|
||||
case value_t::number_unsigned:
|
||||
return (lhs.m_value.number_unsigned) < (rhs.m_value.number_unsigned);
|
||||
|
||||
case value_t::number_float:
|
||||
return (lhs.m_value.number_float) < (rhs.m_value.number_float);
|
||||
|
||||
case value_t::binary:
|
||||
return (*lhs.m_value.binary) < (*rhs.m_value.binary);
|
||||
|
||||
case value_t::discarded:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_float)
|
||||
{
|
||||
return static_cast<number_float_t>(lhs.m_value.number_integer) < rhs.m_value.number_float;
|
||||
}
|
||||
else if (lhs_type == value_t::number_float && rhs_type == value_t::number_integer)
|
||||
{
|
||||
return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_integer);
|
||||
}
|
||||
else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_float)
|
||||
{
|
||||
return static_cast<number_float_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_float;
|
||||
}
|
||||
else if (lhs_type == value_t::number_float && rhs_type == value_t::number_unsigned)
|
||||
{
|
||||
return lhs.m_value.number_float < static_cast<number_float_t>(rhs.m_value.number_unsigned);
|
||||
}
|
||||
else if (lhs_type == value_t::number_integer && rhs_type == value_t::number_unsigned)
|
||||
{
|
||||
return lhs.m_value.number_integer < static_cast<number_integer_t>(rhs.m_value.number_unsigned);
|
||||
}
|
||||
else if (lhs_type == value_t::number_unsigned && rhs_type == value_t::number_integer)
|
||||
{
|
||||
return static_cast<number_integer_t>(lhs.m_value.number_unsigned) < rhs.m_value.number_integer;
|
||||
}
|
||||
|
||||
// We only reach this line if we cannot compare values. In that case,
|
||||
// default_result is used if we cannot compare values. In that case,
|
||||
// we compare types. Note we have to call the operator explicitly,
|
||||
// because MSVC has problems otherwise.
|
||||
return operator<(lhs_type, rhs_type);
|
||||
JSON_IMPLEMENT_OPERATOR( <, false, false, operator<(lhs_type, rhs_type))
|
||||
}
|
||||
|
||||
/// @brief comparison: less than
|
||||
@ -3765,6 +3843,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_le/
|
||||
friend bool operator<=(const_reference lhs, const_reference rhs) noexcept
|
||||
{
|
||||
if (compares_unordered(lhs, rhs, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return !(rhs < lhs);
|
||||
}
|
||||
|
||||
@ -3790,6 +3872,11 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_gt/
|
||||
friend bool operator>(const_reference lhs, const_reference rhs) noexcept
|
||||
{
|
||||
// double inverse
|
||||
if (compares_unordered(lhs, rhs))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return !(lhs <= rhs);
|
||||
}
|
||||
|
||||
@ -3815,6 +3902,10 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_ge/
|
||||
friend bool operator>=(const_reference lhs, const_reference rhs) noexcept
|
||||
{
|
||||
if (compares_unordered(lhs, rhs, true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return !(lhs < rhs);
|
||||
}
|
||||
|
||||
@ -3835,6 +3926,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return basic_json(lhs) >= rhs;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef JSON_IMPLEMENT_OPERATOR
|
||||
|
||||
/// @}
|
||||
|
||||
@ -5031,10 +5125,14 @@ struct less< ::nlohmann::detail::value_t> // do not remove the space after '<',
|
||||
@brief compare two value_t enum values
|
||||
@since version 3.0.0
|
||||
*/
|
||||
bool operator()(nlohmann::detail::value_t lhs,
|
||||
nlohmann::detail::value_t rhs) const noexcept
|
||||
bool operator()(::nlohmann::detail::value_t lhs,
|
||||
::nlohmann::detail::value_t rhs) const noexcept
|
||||
{
|
||||
return nlohmann::detail::operator<(lhs, rhs);
|
||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||
return std::is_lt(lhs <=> rhs); // *NOPAD*
|
||||
#else
|
||||
return ::nlohmann::detail::operator<(lhs, rhs);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -123,6 +123,15 @@ foreach(file ${files})
|
||||
json_test_add_test_for(${file} MAIN test_main CXX_STANDARDS ${test_cxx_standards} ${test_force})
|
||||
endforeach()
|
||||
|
||||
# test legacy comparison of discarded values
|
||||
json_test_set_test_options(test-comparison_legacy
|
||||
COMPILE_DEFINITIONS JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON=1
|
||||
)
|
||||
json_test_add_test_for(src/unit-comparison.cpp
|
||||
NAME test-comparison_legacy
|
||||
MAIN test_main CXX_STANDARDS ${test_cxx_standards} ${test_force}
|
||||
)
|
||||
|
||||
# *DO NOT* use json_test_set_test_options() below this line
|
||||
|
||||
#############################################################################
|
||||
|
@ -1454,17 +1454,17 @@ TEST_CASE("parser class")
|
||||
|
||||
SECTION("filter specific element")
|
||||
{
|
||||
json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json & j) noexcept
|
||||
json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t event, const json & j) noexcept
|
||||
{
|
||||
// filter all number(2) elements
|
||||
return j != json(2);
|
||||
return event != json::parse_event_t::value || j != json(2);
|
||||
});
|
||||
|
||||
CHECK (j_object == json({{"bar", {{"baz", 1}}}}));
|
||||
|
||||
json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json & j) noexcept
|
||||
json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t event, const json & j) noexcept
|
||||
{
|
||||
return j != json(2);
|
||||
return event != json::parse_event_t::value || j != json(2);
|
||||
});
|
||||
|
||||
CHECK (j_array == json({1, {3, 4, 5}, 4, 5}));
|
||||
|
@ -27,11 +27,49 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
// cmake/test.cmake selects the C++ standard versions with which to build a
|
||||
// unit test based on the presence of JSON_HAS_CPP_<VERSION> macros.
|
||||
// When using macros that are only defined for particular versions of the standard
|
||||
// (e.g., JSON_HAS_FILESYSTEM for C++17 and up), please mention the corresponding
|
||||
// version macro in a comment close by, like this:
|
||||
// JSON_HAS_CPP_<VERSION> (do not remove; see note at top of file)
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#define JSON_TESTS_PRIVATE
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||
// this can be replaced with the doctest stl extension header in version 2.5
|
||||
namespace doctest
|
||||
{
|
||||
template<> struct StringMaker<std::partial_ordering>
|
||||
{
|
||||
static String convert(const std::partial_ordering& order)
|
||||
{
|
||||
if (order == std::partial_ordering::less)
|
||||
{
|
||||
return "std::partial_ordering::less";
|
||||
}
|
||||
if (order == std::partial_ordering::equivalent)
|
||||
{
|
||||
return "std::partial_ordering::equivalent";
|
||||
}
|
||||
if (order == std::partial_ordering::greater)
|
||||
{
|
||||
return "std::partial_ordering::greater";
|
||||
}
|
||||
if (order == std::partial_ordering::unordered)
|
||||
{
|
||||
return "std::partial_ordering::unordered";
|
||||
}
|
||||
return "{?}";
|
||||
}
|
||||
};
|
||||
} // namespace doctest
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
// helper function to check std::less<json::value_t>
|
||||
@ -45,6 +83,27 @@ bool f(A a, B b, U u = U())
|
||||
|
||||
TEST_CASE("lexicographical comparison operators")
|
||||
{
|
||||
constexpr auto f_ = false;
|
||||
constexpr auto _t = true;
|
||||
constexpr auto nan = std::numeric_limits<json::number_float_t>::quiet_NaN();
|
||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||
constexpr auto lt = std::partial_ordering::less;
|
||||
constexpr auto gt = std::partial_ordering::greater;
|
||||
constexpr auto eq = std::partial_ordering::equivalent;
|
||||
constexpr auto un = std::partial_ordering::unordered;
|
||||
#endif
|
||||
|
||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||
INFO("using 3-way comparison");
|
||||
#endif
|
||||
|
||||
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
INFO("using legacy comparison");
|
||||
#endif
|
||||
|
||||
//REQUIRE(std::numeric_limits<json::number_float_t>::has_quiet_NaN);
|
||||
REQUIRE(std::isnan(nan));
|
||||
|
||||
SECTION("types")
|
||||
{
|
||||
std::vector<json::value_t> j_types =
|
||||
@ -57,97 +116,268 @@ TEST_CASE("lexicographical comparison operators")
|
||||
json::value_t::object,
|
||||
json::value_t::array,
|
||||
json::value_t::string,
|
||||
json::value_t::binary
|
||||
json::value_t::binary,
|
||||
json::value_t::discarded
|
||||
};
|
||||
|
||||
std::vector<std::vector<bool>> expected_lt =
|
||||
{
|
||||
//0 1 2 3 4 5 6 7 8 9
|
||||
{f_, _t, _t, _t, _t, _t, _t, _t, _t, f_}, // 0
|
||||
{f_, f_, _t, _t, _t, _t, _t, _t, _t, f_}, // 1
|
||||
{f_, f_, f_, f_, f_, _t, _t, _t, _t, f_}, // 2
|
||||
{f_, f_, f_, f_, f_, _t, _t, _t, _t, f_}, // 3
|
||||
{f_, f_, f_, f_, f_, _t, _t, _t, _t, f_}, // 4
|
||||
{f_, f_, f_, f_, f_, f_, _t, _t, _t, f_}, // 5
|
||||
{f_, f_, f_, f_, f_, f_, f_, _t, _t, f_}, // 6
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, _t, f_}, // 7
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 8
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 9
|
||||
};
|
||||
|
||||
SECTION("comparison: less")
|
||||
{
|
||||
std::vector<std::vector<bool>> expected =
|
||||
{
|
||||
{false, true, true, true, true, true, true, true, true},
|
||||
{false, false, true, true, true, true, true, true, true},
|
||||
{false, false, false, false, false, true, true, true, true},
|
||||
{false, false, false, false, false, true, true, true, true},
|
||||
{false, false, false, false, false, true, true, true, true},
|
||||
{false, false, false, false, false, false, true, true, true},
|
||||
{false, false, false, false, false, false, false, true, true},
|
||||
{false, false, false, false, false, false, false, false, true},
|
||||
{false, false, false, false, false, false, false, false, false}
|
||||
};
|
||||
|
||||
REQUIRE(expected_lt.size() == j_types.size());
|
||||
for (size_t i = 0; i < j_types.size(); ++i)
|
||||
{
|
||||
REQUIRE(expected_lt[i].size() == j_types.size());
|
||||
for (size_t j = 0; j < j_types.size(); ++j)
|
||||
{
|
||||
CAPTURE(i)
|
||||
CAPTURE(j)
|
||||
// check precomputed values
|
||||
CHECK(operator<(j_types[i], j_types[j]) == expected[i][j]);
|
||||
CHECK(f(j_types[i], j_types[j]) == expected[i][j]);
|
||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||
// JSON_HAS_CPP_20 (do not remove; see note at top of file)
|
||||
CHECK((j_types[i] < j_types[j]) == expected_lt[i][j]);
|
||||
#else
|
||||
CHECK(operator<(j_types[i], j_types[j]) == expected_lt[i][j]);
|
||||
#endif
|
||||
CHECK(f(j_types[i], j_types[j]) == expected_lt[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||
// JSON_HAS_CPP_20 (do not remove; see note at top of file)
|
||||
SECTION("comparison: 3-way")
|
||||
{
|
||||
std::vector<std::vector<std::partial_ordering>> expected =
|
||||
{
|
||||
//0 1 2 3 4 5 6 7 8 9
|
||||
{eq, lt, lt, lt, lt, lt, lt, lt, lt, un}, // 0
|
||||
{gt, eq, lt, lt, lt, lt, lt, lt, lt, un}, // 1
|
||||
{gt, gt, eq, eq, eq, lt, lt, lt, lt, un}, // 2
|
||||
{gt, gt, eq, eq, eq, lt, lt, lt, lt, un}, // 3
|
||||
{gt, gt, eq, eq, eq, lt, lt, lt, lt, un}, // 4
|
||||
{gt, gt, gt, gt, gt, eq, lt, lt, lt, un}, // 5
|
||||
{gt, gt, gt, gt, gt, gt, eq, lt, lt, un}, // 6
|
||||
{gt, gt, gt, gt, gt, gt, gt, eq, lt, un}, // 7
|
||||
{gt, gt, gt, gt, gt, gt, gt, gt, eq, un}, // 8
|
||||
{un, un, un, un, un, un, un, un, un, un}, // 9
|
||||
};
|
||||
|
||||
// check expected partial_ordering against expected boolean
|
||||
REQUIRE(expected.size() == expected_lt.size());
|
||||
for (size_t i = 0; i < expected.size(); ++i)
|
||||
{
|
||||
REQUIRE(expected[i].size() == expected_lt[i].size());
|
||||
for (size_t j = 0; j < expected[i].size(); ++j)
|
||||
{
|
||||
CAPTURE(i)
|
||||
CAPTURE(j)
|
||||
CHECK(std::is_lt(expected[i][j]) == expected_lt[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
// check 3-way comparison against expected partial_ordering
|
||||
REQUIRE(expected.size() == j_types.size());
|
||||
for (size_t i = 0; i < j_types.size(); ++i)
|
||||
{
|
||||
REQUIRE(expected[i].size() == j_types.size());
|
||||
for (size_t j = 0; j < j_types.size(); ++j)
|
||||
{
|
||||
CAPTURE(i)
|
||||
CAPTURE(j)
|
||||
CHECK((j_types[i] <=> j_types[j]) == expected[i][j]); // *NOPAD*
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("values")
|
||||
{
|
||||
json j_values =
|
||||
{
|
||||
nullptr, nullptr,
|
||||
-17, 42,
|
||||
8u, 13u,
|
||||
3.14159, 23.42,
|
||||
"foo", "bar",
|
||||
true, false,
|
||||
{1, 2, 3}, {"one", "two", "three"},
|
||||
{{"first", 1}, {"second", 2}}, {{"a", "A"}, {"b", {"B"}}},
|
||||
json::binary({1, 2, 3}), json::binary({1, 2, 4})
|
||||
nullptr, nullptr, // 0 1
|
||||
-17, 42, // 2 3
|
||||
8u, 13u, // 4 5
|
||||
3.14159, 23.42, // 6 7
|
||||
nan, nan, // 8 9
|
||||
"foo", "bar", // 10 11
|
||||
true, false, // 12 13
|
||||
{1, 2, 3}, {"one", "two", "three"}, // 14 15
|
||||
{{"first", 1}, {"second", 2}}, {{"a", "A"}, {"b", {"B"}}}, // 16 17
|
||||
json::binary({1, 2, 3}), json::binary({1, 2, 4}), // 18 19
|
||||
json(json::value_t::discarded), json(json::value_t::discarded) // 20 21
|
||||
};
|
||||
|
||||
SECTION("comparison: equal")
|
||||
std::vector<std::vector<bool>> expected_eq =
|
||||
{
|
||||
//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
||||
{_t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 0
|
||||
{_t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 1
|
||||
{f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 2
|
||||
{f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 3
|
||||
{f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 4
|
||||
{f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 5
|
||||
{f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 6
|
||||
{f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 7
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 8
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 9
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 10
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 11
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 12
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, f_}, // 13
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_}, // 14
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_}, // 15
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_}, // 16
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_}, // 17
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_}, // 18
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_}, // 19
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 20
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 21
|
||||
};
|
||||
|
||||
std::vector<std::vector<bool>> expected_lt =
|
||||
{
|
||||
//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
||||
{f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_}, // 0
|
||||
{f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_}, // 1
|
||||
{f_, f_, f_, _t, _t, _t, _t, _t, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 2
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 3
|
||||
{f_, f_, f_, _t, f_, _t, f_, _t, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 4
|
||||
{f_, f_, f_, _t, f_, f_, f_, _t, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 5
|
||||
{f_, f_, f_, _t, _t, _t, f_, _t, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 6
|
||||
{f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 7
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 8
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 9
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_}, // 10
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_}, // 11
|
||||
{f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 12
|
||||
{f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, f_, _t, _t, _t, _t, _t, _t, f_, f_}, // 13
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, _t, f_, f_, _t, _t, f_, f_}, // 14
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_}, // 15
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, f_, f_, _t, _t, f_, f_}, // 16
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, _t, _t, _t, f_, _t, _t, f_, f_}, // 17
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, f_, f_}, // 18
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 19
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 20
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 21
|
||||
};
|
||||
|
||||
SECTION("compares unordered")
|
||||
{
|
||||
std::vector<std::vector<bool>> expected =
|
||||
{
|
||||
{true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
|
||||
{true, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false},
|
||||
{false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true}
|
||||
//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 0
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 1
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 2
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 3
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 4
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 5
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 6
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 7
|
||||
{f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 8
|
||||
{f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 9
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 10
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 11
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 12
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 13
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 14
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 15
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 16
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 17
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 18
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 19
|
||||
{_t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t}, // 20
|
||||
{_t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t}, // 21
|
||||
};
|
||||
|
||||
// check if two values compare unordered as expected
|
||||
REQUIRE(expected.size() == j_values.size());
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
REQUIRE(expected[i].size() == j_values.size());
|
||||
for (size_t j = 0; j < j_values.size(); ++j)
|
||||
{
|
||||
CAPTURE(i)
|
||||
CAPTURE(j)
|
||||
CHECK(json::compares_unordered(j_values[i], j_values[j]) == expected[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
SECTION("compares unordered (inverse)")
|
||||
{
|
||||
std::vector<std::vector<bool>> expected =
|
||||
{
|
||||
//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 0
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 1
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 2
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 3
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 4
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 5
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 6
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 7
|
||||
{f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 8
|
||||
{f_, f_, _t, _t, _t, _t, _t, _t, _t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 9
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 10
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 11
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 12
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 13
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 14
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 15
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 16
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 17
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 18
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 19
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 20
|
||||
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 21
|
||||
};
|
||||
|
||||
// check that two values compare unordered as expected (with legacy-mode enabled)
|
||||
REQUIRE(expected.size() == j_values.size());
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
REQUIRE(expected[i].size() == j_values.size());
|
||||
for (size_t j = 0; j < j_values.size(); ++j)
|
||||
{
|
||||
CAPTURE(i)
|
||||
CAPTURE(j)
|
||||
CAPTURE(j_values[i])
|
||||
CAPTURE(j_values[j])
|
||||
// check precomputed values
|
||||
CHECK( (j_values[i] == j_values[j]) == expected[i][j] );
|
||||
CHECK(json::compares_unordered(j_values[i], j_values[j], true) == expected[i][j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// comparison with discarded elements
|
||||
json j_discarded(json::value_t::discarded);
|
||||
for (const auto& v : j_values)
|
||||
SECTION("comparison: equal")
|
||||
{
|
||||
// check that two values compare equal
|
||||
REQUIRE(expected_eq.size() == j_values.size());
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
CHECK( (v == j_discarded) == false);
|
||||
CHECK( (j_discarded == v) == false);
|
||||
CHECK( (j_discarded == j_discarded) == false);
|
||||
REQUIRE(expected_eq[i].size() == j_values.size());
|
||||
for (size_t j = 0; j < j_values.size(); ++j)
|
||||
{
|
||||
CAPTURE(i)
|
||||
CAPTURE(j)
|
||||
CHECK((j_values[i] == j_values[j]) == expected_eq[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
// compare with null pointer
|
||||
@ -158,121 +388,229 @@ TEST_CASE("lexicographical comparison operators")
|
||||
|
||||
SECTION("comparison: not equal")
|
||||
{
|
||||
// check that two values compare unequal as expected
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < j_values.size(); ++j)
|
||||
{
|
||||
CAPTURE(i)
|
||||
CAPTURE(j)
|
||||
// check definition
|
||||
CHECK( (j_values[i] != j_values[j]) == !(j_values[i] == j_values[j]) );
|
||||
|
||||
if (json::compares_unordered(j_values[i], j_values[j], true))
|
||||
{
|
||||
// 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
|
||||
json j_null;
|
||||
CHECK( (j_null != nullptr) == false);
|
||||
CHECK( (nullptr != j_null) == false);
|
||||
CHECK( (j_null != nullptr) == !(j_null == nullptr));
|
||||
CHECK( (nullptr != j_null) == !(nullptr == j_null));
|
||||
CHECK((j_null != nullptr) == false);
|
||||
CHECK((nullptr != j_null) == false);
|
||||
CHECK((j_null != nullptr) == !(j_null == nullptr));
|
||||
CHECK((nullptr != j_null) == !(nullptr == j_null));
|
||||
}
|
||||
|
||||
SECTION("comparison: less")
|
||||
{
|
||||
std::vector<std::vector<bool>> expected =
|
||||
{
|
||||
{false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true},
|
||||
{false, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true},
|
||||
{false, false, false, true, true, true, true, true, true, true, false, false, true, true, true, true, true, true},
|
||||
{false, false, false, false, false, false, false, false, true, true, false, false, true, true, true, true, true, true},
|
||||
{false, false, false, true, false, true, false, true, true, true, false, false, true, true, true, true, true, true},
|
||||
{false, false, false, true, false, false, false, true, true, true, false, false, true, true, true, true, true, true},
|
||||
{false, false, false, true, true, true, false, true, true, true, false, false, true, true, true, true, true, true},
|
||||
{false, false, false, true, false, false, false, false, true, true, false, false, true, true, true, true, true, true},
|
||||
{false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, true},
|
||||
{false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, true, true},
|
||||
{false, false, true, true, true, true, true, true, true, true, false, false, true, true, true, true, true, true},
|
||||
{false, false, true, true, true, true, true, true, true, true, true, false, true, true, true, true, true, true},
|
||||
{false, false, false, false, false, false, false, false, true, true, false, false, false, true, false, false, true, true},
|
||||
{false, false, false, false, false, false, false, false, true, true, false, false, false, false, false, false, true, true},
|
||||
{false, false, false, false, false, false, false, false, true, true, false, false, true, true, false, false, true, true},
|
||||
{false, false, false, false, false, false, false, false, true, true, false, false, true, true, true, false, true, true},
|
||||
{false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true},
|
||||
{false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false}
|
||||
};
|
||||
|
||||
// check that two values compare less than as expected
|
||||
REQUIRE(expected_lt.size() == j_values.size());
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
REQUIRE(expected_lt[i].size() == j_values.size());
|
||||
for (size_t j = 0; j < j_values.size(); ++j)
|
||||
{
|
||||
// Skip comparing indicies 12 and 13, and 13 and 12 in C++20 pending fix
|
||||
// See issue #3207
|
||||
#if defined(JSON_HAS_CPP_20) || JSON_HAS_THREE_WAY_COMPARISON
|
||||
if ((i == 12 && j == 13) || (i == 13 && j == 12))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
CAPTURE(i)
|
||||
CAPTURE(j)
|
||||
CAPTURE(j_values[i])
|
||||
CAPTURE(j_values[j])
|
||||
// check precomputed values
|
||||
CHECK( (j_values[i] < j_values[j]) == expected[i][j] );
|
||||
CHECK((j_values[i] < j_values[j]) == expected_lt[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
// comparison with discarded elements
|
||||
json j_discarded(json::value_t::discarded);
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
CAPTURE(i)
|
||||
CHECK( (j_values[i] < j_discarded) == false);
|
||||
CHECK( (j_discarded < j_values[i]) == false);
|
||||
CHECK( (j_discarded < j_discarded) == false);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("comparison: less than or equal equal")
|
||||
{
|
||||
// check that two values compare less than or equal as expected
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < j_values.size(); ++j)
|
||||
{
|
||||
CAPTURE(i)
|
||||
CAPTURE(j)
|
||||
// check definition
|
||||
CHECK( (j_values[i] <= j_values[j]) == !(j_values[j] < j_values[i]) );
|
||||
if (json::compares_unordered(j_values[i], j_values[j], true))
|
||||
{
|
||||
// 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 less than with the operand order reversed
|
||||
CHECK((j_values[i] <= j_values[j]) == !(j_values[j] < j_values[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("comparison: greater than")
|
||||
{
|
||||
// check that two values compare greater than as expected
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < j_values.size(); ++j)
|
||||
{
|
||||
CAPTURE(i)
|
||||
CAPTURE(j)
|
||||
// check definition
|
||||
CHECK( (j_values[i] > j_values[j]) == (j_values[j] < j_values[i]) );
|
||||
if (json::compares_unordered(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 less than or equal which is defined as
|
||||
// the inverse of less than with the operand order reversed
|
||||
CHECK((j_values[i] > j_values[j]) == !(j_values[i] <= j_values[j]));
|
||||
CHECK((j_values[i] > j_values[j]) == !!(j_values[j] < j_values[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("comparison: greater than or equal")
|
||||
{
|
||||
// check that two values compare greater than or equal as expected
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
for (size_t j = 0; j < j_values.size(); ++j)
|
||||
{
|
||||
CAPTURE(i)
|
||||
CAPTURE(j)
|
||||
// check definition
|
||||
CHECK( (j_values[i] >= j_values[j]) == !(j_values[i] < j_values[j]) );
|
||||
if (json::compares_unordered(j_values[i], j_values[j], true))
|
||||
{
|
||||
// if two values compare unordered,
|
||||
// check that the boolean 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 less than
|
||||
CHECK((j_values[i] >= j_values[j]) == !(j_values[i] < j_values[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if JSON_HAS_THREE_WAY_COMPARISON
|
||||
// JSON_HAS_CPP_20 (do not remove; see note at top of file)
|
||||
SECTION("comparison: 3-way")
|
||||
{
|
||||
std::vector<std::vector<std::partial_ordering>> expected =
|
||||
{
|
||||
//0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
||||
{eq, eq, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, un, un}, // 0
|
||||
{eq, eq, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, un, un}, // 1
|
||||
{gt, gt, eq, lt, lt, lt, lt, lt, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 2
|
||||
{gt, gt, gt, eq, gt, gt, gt, gt, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 3
|
||||
{gt, gt, gt, lt, eq, lt, gt, lt, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 4
|
||||
{gt, gt, gt, lt, gt, eq, gt, lt, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 5
|
||||
{gt, gt, gt, lt, lt, lt, eq, lt, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 6
|
||||
{gt, gt, gt, lt, gt, gt, gt, eq, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 7
|
||||
{gt, gt, un, un, un, un, un, un, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 8
|
||||
{gt, gt, un, un, un, un, un, un, un, un, lt, lt, gt, gt, lt, lt, lt, lt, lt, lt, un, un}, // 9
|
||||
{gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, eq, gt, gt, gt, gt, gt, gt, gt, lt, lt, un, un}, // 10
|
||||
{gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, lt, eq, gt, gt, gt, gt, gt, gt, lt, lt, un, un}, // 11
|
||||
{gt, gt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, eq, gt, lt, lt, lt, lt, lt, lt, un, un}, // 12
|
||||
{gt, gt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, eq, lt, lt, lt, lt, lt, lt, un, un}, // 13
|
||||
{gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, lt, lt, gt, gt, eq, lt, gt, gt, lt, lt, un, un}, // 14
|
||||
{gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, lt, lt, gt, gt, gt, eq, gt, gt, lt, lt, un, un}, // 15
|
||||
{gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, lt, lt, gt, gt, lt, lt, eq, gt, lt, lt, un, un}, // 16
|
||||
{gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, lt, lt, gt, gt, lt, lt, lt, eq, lt, lt, un, un}, // 17
|
||||
{gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, eq, lt, un, un}, // 18
|
||||
{gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, gt, eq, un, un}, // 19
|
||||
{un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un}, // 20
|
||||
{un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un}, // 21
|
||||
};
|
||||
|
||||
// check expected partial_ordering against expected booleans
|
||||
REQUIRE(expected.size() == expected_eq.size());
|
||||
REQUIRE(expected.size() == expected_lt.size());
|
||||
for (size_t i = 0; i < expected.size(); ++i)
|
||||
{
|
||||
REQUIRE(expected[i].size() == expected_eq[i].size());
|
||||
REQUIRE(expected[i].size() == expected_lt[i].size());
|
||||
for (size_t j = 0; j < expected[i].size(); ++j)
|
||||
{
|
||||
CAPTURE(i)
|
||||
CAPTURE(j)
|
||||
CHECK(std::is_eq(expected[i][j]) == expected_eq[i][j]);
|
||||
CHECK(std::is_lt(expected[i][j]) == expected_lt[i][j]);
|
||||
if (std::is_gt(expected[i][j]))
|
||||
{
|
||||
CHECK((!expected_eq[i][j] && !expected_lt[i][j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check that two values compare according to their expected ordering
|
||||
REQUIRE(expected.size() == j_values.size());
|
||||
for (size_t i = 0; i < j_values.size(); ++i)
|
||||
{
|
||||
REQUIRE(expected[i].size() == j_values.size());
|
||||
for (size_t j = 0; j < j_values.size(); ++j)
|
||||
{
|
||||
CAPTURE(i)
|
||||
CAPTURE(j)
|
||||
CHECK((j_values[i] <=> j_values[j]) == expected[i][j]); // *NOPAD*
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
|
||||
SECTION("parser callback regression")
|
||||
{
|
||||
SECTION("filter specific element")
|
||||
{
|
||||
const auto* s_object = R"(
|
||||
{
|
||||
"foo": 2,
|
||||
"bar": {
|
||||
"baz": 1
|
||||
}
|
||||
}
|
||||
)";
|
||||
const auto* s_array = R"(
|
||||
[1,2,[3,4,5],4,5]
|
||||
)";
|
||||
|
||||
json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json & j) noexcept
|
||||
{
|
||||
// filter all number(2) elements
|
||||
return j != json(2);
|
||||
});
|
||||
|
||||
CHECK (j_object == json({{"bar", {{"baz", 1}}}}));
|
||||
|
||||
json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json & j) noexcept
|
||||
{
|
||||
return j != json(2);
|
||||
});
|
||||
|
||||
CHECK (j_array == json({1, {3, 4, 5}, 4, 5}));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -27,6 +27,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
// cmake/test.cmake selects the C++ standard versions with which to build a
|
||||
// unit test based on the presence of JSON_HAS_CPP_<VERSION> macros.
|
||||
// When using macros that are only defined for particular versions of the standard
|
||||
// (e.g., JSON_HAS_FILESYSTEM for C++17 and up), please mention the corresponding
|
||||
// version macro in a comment close by, like this:
|
||||
// JSON_HAS_CPP_<VERSION> (do not remove; see note at top of file)
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#define JSON_TESTS_PRIVATE
|
||||
@ -1582,12 +1589,4 @@ TEST_CASE("JSON to enum mapping")
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#undef JSON_HAS_CPP_17
|
||||
#endif
|
||||
|
||||
#ifdef JSON_HAS_CPP_14
|
||||
#undef JSON_HAS_CPP_14
|
||||
#endif
|
||||
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_POP
|
||||
|
@ -80,7 +80,7 @@ TEST_CASE("iterator_wrapper")
|
||||
json j = { {"A", 1}, {"B", 2} };
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : json::iterator_wrapper(j))
|
||||
for (auto& i : json::iterator_wrapper(j)) // NOLINT(readability-qualified-auto)
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
@ -226,7 +226,7 @@ TEST_CASE("iterator_wrapper")
|
||||
const json j = { {"A", 1}, {"B", 2} };
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : json::iterator_wrapper(j))
|
||||
for (auto& i : json::iterator_wrapper(j)) // NOLINT(readability-qualified-auto)
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
@ -361,7 +361,7 @@ TEST_CASE("iterator_wrapper")
|
||||
json j = { "A", "B" };
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : json::iterator_wrapper(j))
|
||||
for (auto& i : json::iterator_wrapper(j)) // NOLINT(readability-qualified-auto)
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
@ -507,7 +507,7 @@ TEST_CASE("iterator_wrapper")
|
||||
const json j = { "A", "B" };
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : json::iterator_wrapper(j))
|
||||
for (auto& i : json::iterator_wrapper(j)) // NOLINT(readability-qualified-auto)
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
@ -624,7 +624,7 @@ TEST_CASE("iterator_wrapper")
|
||||
json j = 1;
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : json::iterator_wrapper(j))
|
||||
for (auto& i : json::iterator_wrapper(j)) // NOLINT(readability-qualified-auto)
|
||||
{
|
||||
++counter;
|
||||
CHECK(i.key() == "");
|
||||
@ -693,7 +693,7 @@ TEST_CASE("iterator_wrapper")
|
||||
const json j = 1;
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : json::iterator_wrapper(j))
|
||||
for (auto& i : json::iterator_wrapper(j)) // NOLINT(readability-qualified-auto)
|
||||
{
|
||||
++counter;
|
||||
CHECK(i.key() == "");
|
||||
@ -777,7 +777,7 @@ TEST_CASE("items()")
|
||||
json j = { {"A", 1}, {"B", 2} };
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : j.items())
|
||||
for (auto& i : j.items()) // NOLINT(readability-qualified-auto)
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
@ -939,7 +939,7 @@ TEST_CASE("items()")
|
||||
const json j = { {"A", 1}, {"B", 2} };
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : j.items())
|
||||
for (auto& i : j.items()) // NOLINT(readability-qualified-auto)
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
@ -1074,7 +1074,7 @@ TEST_CASE("items()")
|
||||
json j = { "A", "B" };
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : j.items())
|
||||
for (auto& i : j.items()) // NOLINT(readability-qualified-auto)
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
@ -1220,7 +1220,7 @@ TEST_CASE("items()")
|
||||
const json j = { "A", "B" };
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : j.items())
|
||||
for (auto& i : j.items()) // NOLINT(readability-qualified-auto)
|
||||
{
|
||||
switch (counter++)
|
||||
{
|
||||
@ -1337,7 +1337,7 @@ TEST_CASE("items()")
|
||||
json j = 1;
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : j.items())
|
||||
for (auto& i : j.items()) // NOLINT(readability-qualified-auto)
|
||||
{
|
||||
++counter;
|
||||
CHECK(i.key() == "");
|
||||
@ -1406,7 +1406,7 @@ TEST_CASE("items()")
|
||||
const json j = 1;
|
||||
int counter = 1;
|
||||
|
||||
for (auto& i : j.items())
|
||||
for (auto& i : j.items()) // NOLINT(readability-qualified-auto)
|
||||
{
|
||||
++counter;
|
||||
CHECK(i.key() == "");
|
||||
@ -1448,13 +1448,5 @@ TEST_CASE("items()")
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#undef JSON_HAS_CPP_17
|
||||
#endif
|
||||
|
||||
#ifdef JSON_HAS_CPP_14
|
||||
#undef JSON_HAS_CPP_14
|
||||
#endif
|
||||
|
||||
DOCTEST_GCC_SUPPRESS_WARNING_POP
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_POP
|
||||
|
@ -27,11 +27,23 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
// cmake/test.cmake selects the C++ standard versions with which to build a
|
||||
// unit test based on the presence of JSON_HAS_CPP_<VERSION> macros.
|
||||
// When using macros that are only defined for particular versions of the standard
|
||||
// (e.g., JSON_HAS_FILESYSTEM for C++17 and up), please mention the corresponding
|
||||
// version macro in a comment close by, like this:
|
||||
// JSON_HAS_CPP_<VERSION> (do not remove; see note at top of file)
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#if JSON_HAS_RANGES
|
||||
#include <algorithm>
|
||||
#include <ranges>
|
||||
#endif
|
||||
|
||||
TEST_CASE("iterators 2")
|
||||
{
|
||||
SECTION("iterator comparisons")
|
||||
@ -881,4 +893,101 @@ TEST_CASE("iterators 2")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if JSON_HAS_RANGES
|
||||
// JSON_HAS_CPP_20 (do not remove; see note at top of file)
|
||||
SECTION("ranges")
|
||||
{
|
||||
SECTION("concepts")
|
||||
{
|
||||
using nlohmann::detail::iteration_proxy_value;
|
||||
CHECK(std::bidirectional_iterator<json::iterator>);
|
||||
CHECK(std::input_iterator<iteration_proxy_value<json::iterator>>);
|
||||
|
||||
CHECK(std::is_same<json::iterator, std::ranges::iterator_t<json>>::value);
|
||||
CHECK(std::ranges::bidirectional_range<json>);
|
||||
|
||||
using nlohmann::detail::iteration_proxy;
|
||||
using items_type = decltype(std::declval<json&>().items());
|
||||
CHECK(std::is_same<items_type, iteration_proxy<json::iterator>>::value);
|
||||
CHECK(std::is_same<iteration_proxy_value<json::iterator>, std::ranges::iterator_t<items_type>>::value);
|
||||
CHECK(std::ranges::input_range<items_type>);
|
||||
}
|
||||
|
||||
// libstdc++ algorithms don't work with Clang 15 (04/2022)
|
||||
#if !defined(__clang__) || (defined(__clang__) && defined(__GLIBCXX__))
|
||||
SECTION("algorithms")
|
||||
{
|
||||
SECTION("copy")
|
||||
{
|
||||
json j{"foo", "bar"};
|
||||
auto j_copied = json::array();
|
||||
|
||||
std::ranges::copy(j, std::back_inserter(j_copied));
|
||||
|
||||
CHECK(j == j_copied);
|
||||
}
|
||||
|
||||
SECTION("find_if")
|
||||
{
|
||||
json j{1, 3, 2, 4};
|
||||
auto j_even = json::array();
|
||||
|
||||
#if JSON_USE_IMPLICIT_CONVERSIONS
|
||||
auto it = std::ranges::find_if(j, [](int v) noexcept
|
||||
{
|
||||
return (v % 2) == 0;
|
||||
});
|
||||
#else
|
||||
auto it = std::ranges::find_if(j, [](const json & j) noexcept
|
||||
{
|
||||
int v;
|
||||
j.get_to(v);
|
||||
return (v % 2) == 0;
|
||||
});
|
||||
#endif
|
||||
|
||||
CHECK(*it == 2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// libstdc++ views don't work with Clang 15 (04/2022)
|
||||
// libc++ hides limited ranges implementation behind guard macro
|
||||
#if !(defined(__clang__) && (defined(__GLIBCXX__) || defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)))
|
||||
SECTION("views")
|
||||
{
|
||||
SECTION("reverse")
|
||||
{
|
||||
json j{1, 2, 3, 4, 5};
|
||||
json j_expected{5, 4, 3, 2, 1};
|
||||
|
||||
auto reversed = j | std::views::reverse;
|
||||
CHECK(reversed == j_expected);
|
||||
}
|
||||
|
||||
SECTION("transform")
|
||||
{
|
||||
json j
|
||||
{
|
||||
{ "a_key", "a_value"},
|
||||
{ "b_key", "b_value"},
|
||||
{ "c_key", "c_value"},
|
||||
};
|
||||
json j_expected{"a_key", "b_key", "c_key"};
|
||||
|
||||
auto transformed = j.items() | std::views::transform([](const auto & item)
|
||||
{
|
||||
return item.key();
|
||||
});
|
||||
auto j_transformed = json::array();
|
||||
std::ranges::copy(transformed, std::back_inserter(j_transformed));
|
||||
|
||||
CHECK(j_transformed == j_expected);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -27,6 +27,13 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
// cmake/test.cmake selects the C++ standard versions with which to build a
|
||||
// unit test based on the presence of JSON_HAS_CPP_<VERSION> macros.
|
||||
// When using macros that are only defined for particular versions of the standard
|
||||
// (e.g., JSON_HAS_FILESYSTEM for C++17 and up), please mention the corresponding
|
||||
// version macro in a comment close by, like this:
|
||||
// JSON_HAS_CPP_<VERSION> (do not remove; see note at top of file)
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
// for some reason including this after the json header leads to linker errors with VS 2017...
|
||||
@ -48,7 +55,6 @@ using ordered_json = nlohmann::ordered_json;
|
||||
#endif
|
||||
|
||||
#if JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||
// JSON_HAS_CPP_17 (magic keyword; do not remove)
|
||||
#include <experimental/filesystem>
|
||||
namespace nlohmann::detail
|
||||
{
|
||||
@ -788,6 +794,7 @@ TEST_CASE("regression tests 2")
|
||||
}
|
||||
|
||||
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
|
||||
// JSON_HAS_CPP_17 (do not remove; see note at top of file)
|
||||
SECTION("issue #3070 - Version 3.10.3 breaks backward-compatibility with 3.10.2 ")
|
||||
{
|
||||
nlohmann::detail::std_fs::path text_path("/tmp/text.txt");
|
||||
|
Loading…
Reference in New Issue
Block a user