Merge 04b4d79ec2 into a8a547d7a2
This commit is contained in:
commit
ccd80c0bd8
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()
|
||||
|
||||
4
doc/mkdocs/docs/css/custom.css
Normal file
4
doc/mkdocs/docs/css/custom.css
Normal file
@ -0,0 +1,4 @@
|
||||
/* disable ligatures in code and preformatted blocks */
|
||||
code, pre {
|
||||
font-variant-ligatures: none;
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -44,13 +54,17 @@ Linear.
|
||||
|
||||
## Notes
|
||||
|
||||
!!! note
|
||||
!!! note "Comparison of 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.
|
||||
|
||||
!!! note
|
||||
!!! note "Floating-point comparison with epsilon"
|
||||
|
||||
Floating-point numbers inside JSON values numbers are compared with `json::number_float_t::operator==` which is
|
||||
`double::operator==` by default. To compare floating-point while respecting an epsilon, an alternative
|
||||
@ -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 "Comparison of `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 "Comparison of `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 "Comparison of `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 "Comparison of `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 "Comparison of `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
|
||||
|
||||
- `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
|
||||
|
||||
## Version history
|
||||
|
||||
|
||||
@ -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.
|
||||
@ -733,6 +733,28 @@ The dynamic type of the object cannot be represented in the requested serializat
|
||||
|
||||
Encapsulate the JSON value in an object. That is, instead of serializing `#!json true`, serialize `#!json {"value": true}`
|
||||
|
||||
### json.exception.type_error.318
|
||||
|
||||
The given callable cannot be invoked with the stored JSON value and the arguments provided.
|
||||
|
||||
!!! failure "Example message"
|
||||
|
||||
Calling `apply()` on a numeric JSON value with an unary non-member function accepting a string:
|
||||
```
|
||||
[json.exception.type_error.318] cannot invoke callable with JSON value of type number
|
||||
```
|
||||
|
||||
### json.exception.type_error.319
|
||||
|
||||
The result callback cannot be invoked with the callback argument, in case of a non-static member function pointer callback, and the result of the invocation of the callable.
|
||||
|
||||
!!! failure "Example message"
|
||||
|
||||
Calling `apply_cb()` with an unary non-member function result callback when the result of the invocation of the callable is not convertible to the argument type of the result callback:
|
||||
```
|
||||
[json.exception.type_error.319] cannot invoke callback
|
||||
```
|
||||
|
||||
## Out of range
|
||||
|
||||
This exception is thrown in case a library function is called on an input parameter that exceeds the expected range, for instance in case of array indices or nonexisting object keys.
|
||||
|
||||
@ -152,15 +152,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
|
||||
@ -243,6 +244,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
|
||||
@ -250,6 +253,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
|
||||
@ -316,5 +320,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
|
||||
|
||||
@ -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,20 +104,36 @@
|
||||
#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_THREE_WAY_COMPARISON
|
||||
#define JSON_HAS_THREE_WAY_COMPARISON 0
|
||||
#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
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef JSON_HAS_RANGES
|
||||
#define JSON_HAS_RANGES 0
|
||||
#endif
|
||||
|
||||
#if JSON_HEDLEY_HAS_ATTRIBUTE(no_unique_address)
|
||||
#define JSON_NO_UNIQUE_ADDRESS [[no_unique_address]]
|
||||
#else
|
||||
#define JSON_NO_UNIQUE_ADDRESS
|
||||
#endif
|
||||
|
||||
|
||||
// disable documentation warnings on clang
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
@ -429,3 +451,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
|
||||
|
||||
@ -26,6 +26,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>
|
||||
|
||||
@ -136,6 +136,61 @@ using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
|
||||
// the following utilities are natively available in C++17
|
||||
using std::conjunction;
|
||||
using std::disjunction;
|
||||
using std::negation;
|
||||
|
||||
using std::as_const;
|
||||
|
||||
#else
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/conjunction
|
||||
template<class...> struct conjunction : std::true_type {};
|
||||
template<class B> struct conjunction<B> : B {};
|
||||
template<class B, class... Bn>
|
||||
struct conjunction<B, Bn...>
|
||||
: std::conditional<bool(B::value), conjunction<Bn...>, B>::type {};
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/disjunction
|
||||
template<class...> struct disjunction : std::false_type {};
|
||||
template<class B> struct disjunction<B> : B {};
|
||||
template<class B, class... Bn>
|
||||
struct disjunction<B, Bn...>
|
||||
: std::conditional<bool(B::value), B, disjunction<Bn...>>::type {};
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/negation
|
||||
template<class B> struct negation : std::integral_constant < bool, !B::value > {};
|
||||
|
||||
// https://en.cppreference.com/w/cpp/utility/as_const
|
||||
template <typename T>
|
||||
constexpr typename std::add_const<T>::type& as_const(T& t) noexcept
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void as_const(const T&&) = delete;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef JSON_HAS_CPP_20
|
||||
|
||||
// the following utilities are natively available in C++20
|
||||
using std::type_identity;
|
||||
|
||||
#else
|
||||
|
||||
template<typename T>
|
||||
struct type_identity
|
||||
{
|
||||
using type = T;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// dispatch utility (taken from ranges-v3)
|
||||
template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
|
||||
template<> struct priority_tag<0> {};
|
||||
|
||||
145
include/nlohmann/detail/meta/invoke.hpp
Normal file
145
include/nlohmann/detail/meta/invoke.hpp
Normal file
@ -0,0 +1,145 @@
|
||||
#pragma once
|
||||
|
||||
#include "nlohmann/detail/meta/cpp_future.hpp"
|
||||
#ifdef JSON_HAS_CPP_17
|
||||
#include <functional> // invoke
|
||||
#endif
|
||||
#include <type_traits> // is_base_of, is_function, is_object, is_same, remove_reference
|
||||
#include <utility> // declval, forward
|
||||
|
||||
#include <nlohmann/detail/macro_scope.hpp>
|
||||
#include <nlohmann/detail/meta/detected.hpp>
|
||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// invoke_impl derived from the C++ standard draft [func.require] for qslib (proprietary)
|
||||
// modified to use standard library type traits and utilities where possible
|
||||
|
||||
namespace internal
|
||||
{
|
||||
|
||||
template<typename Fn, typename... Args,
|
||||
typename = decltype(std::declval<Fn>()(std::forward<Args>(std::declval<Args>())...))>
|
||||
auto invoke_impl(Fn && f, Args && ...args) -> decltype(f(std::forward<Args>(args)...))
|
||||
{
|
||||
return f(std::forward<Args>(args)...);
|
||||
};
|
||||
|
||||
template < typename T, typename U, typename V, typename... Args, enable_if_t <
|
||||
std::is_function<T>::value
|
||||
&& std::is_base_of<U, typename std::remove_reference<V>::type>::value, int > = 0 >
|
||||
auto invoke_impl(T U::*f, V && v, Args && ...args) -> decltype((v.*f)(std::forward<Args>(args)...))
|
||||
{
|
||||
return (v.*f)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < typename T, typename U, typename V, typename... Args, enable_if_t <
|
||||
std::is_function<T>::value
|
||||
&& !std::is_base_of<U, typename std::remove_reference<V>::type>::value, int > = 0 >
|
||||
auto invoke_impl(T U::*f, V && v, Args && ...args) -> decltype(((*v).*f)(std::forward<Args>(args)...))
|
||||
{
|
||||
return ((*v).*f)(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < typename T, typename U, typename V, typename... Args, enable_if_t <
|
||||
std::is_object<T>::value
|
||||
&& sizeof...(Args) == 0, int > = 0 >
|
||||
auto invoke_impl(T U::*f, V && v, Args && ... /*unused*/) -> decltype((*v).*f)
|
||||
{
|
||||
return (*v).*f;
|
||||
}
|
||||
|
||||
// allow setting values by "invoking" data member pointers with one argument
|
||||
template < typename T, typename U, typename V, typename Arg, enable_if_t<
|
||||
std::is_object<T>::value, int> = 0>
|
||||
auto invoke_impl(T U::*f, V && v, Arg && arg) -> decltype((*v).*f = std::forward<Arg>(arg))
|
||||
{
|
||||
return (*v).*f = std::forward<Arg>(arg);
|
||||
}
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
using detect_invocable = decltype(invoke_impl(std::declval<Fn>(), std::declval<Args>()...));
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/result_of
|
||||
template <typename AlwaysVoid, typename, typename...>
|
||||
struct invoke_result {};
|
||||
|
||||
template <typename Fn, typename...Args>
|
||||
struct invoke_result<decltype(void(invoke_impl(std::declval<Fn>(), std::declval<Args>()...))), Fn, Args...>
|
||||
{
|
||||
using type = decltype(invoke_impl(std::declval<Fn>(), std::declval<Args>()...));
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
auto invoke(Fn&& f, Args&& ... args) -> decltype(internal::invoke_impl(std::forward<Fn>(f), std::forward<Args>(args)...))
|
||||
{
|
||||
return internal::invoke_impl(std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
using invoke_result = internal::invoke_result<void, Fn, Args...>;
|
||||
|
||||
template <typename Fn, typename... Args>
|
||||
using is_invocable = typename is_detected<internal::detect_invocable, Fn, Args...>::type;
|
||||
|
||||
// used as a dummy argument
|
||||
struct null_arg_t
|
||||
{
|
||||
explicit null_arg_t() = default;
|
||||
};
|
||||
|
||||
static constexpr null_arg_t null_arg{};
|
||||
|
||||
template<typename T>
|
||||
using is_null_arg = typename std::is_same<uncvref_t<T>, null_arg_t>::type;
|
||||
|
||||
template<typename T>
|
||||
using detect_type = typename T::type;
|
||||
|
||||
template<typename Value, typename Arg, bool HasType = is_detected<detect_type, Arg>::value>
|
||||
struct apply_value_or_value_as_if_castable
|
||||
{
|
||||
using type = Value;
|
||||
};
|
||||
|
||||
template<typename Value, typename Arg>
|
||||
struct apply_value_or_value_as_if_castable<Value, Arg, true>
|
||||
{
|
||||
using as_type = typename Arg::type;
|
||||
using type = typename std::conditional <
|
||||
detail::is_static_castable<Value, as_type>::value,
|
||||
as_type, Value >::type;
|
||||
};
|
||||
|
||||
template<typename Value, typename Arg>
|
||||
using apply_value_or_value_as_t = typename std::conditional <
|
||||
is_basic_json_value_as_placeholder<Arg>::value,
|
||||
typename apply_value_or_value_as_if_castable<Value, uncvref_t<Arg>>::type,
|
||||
Value >::type;
|
||||
|
||||
template<typename Value, typename Tuple, std::size_t I>
|
||||
struct apply_value_or_arg
|
||||
{
|
||||
using element_type = typename std::tuple_element<I, Tuple>::type;
|
||||
using type = typename std::conditional <
|
||||
is_any_basic_json_value_placeholder<element_type>::value,
|
||||
apply_value_or_value_as_t<Value, element_type>,
|
||||
element_type >::type;
|
||||
};
|
||||
|
||||
template<typename Value, typename Fn, typename Tuple, std::size_t... I>
|
||||
using apply_invoke_result_t = typename detail::invoke_result<Fn,
|
||||
typename apply_value_or_arg<Value, Tuple, I>::type...>::type;
|
||||
|
||||
template<typename Value, typename Fn, typename Tuple, std::size_t... I>
|
||||
using apply_is_invocable = typename detail::is_invocable<Fn,
|
||||
typename apply_value_or_arg<Value, Tuple, I>::type...>::type;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
@ -12,6 +12,7 @@
|
||||
#include <nlohmann/detail/meta/call_std/end.hpp>
|
||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
#include <nlohmann/detail/meta/detected.hpp>
|
||||
#include <nlohmann/detail/placeholders.hpp>
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
|
||||
namespace nlohmann
|
||||
@ -178,16 +179,6 @@ using actual_object_comparator_t = typename actual_object_comparator<BasicJsonTy
|
||||
// is_ functions //
|
||||
///////////////////
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/conjunction
|
||||
template<class...> struct conjunction : std::true_type { };
|
||||
template<class B> struct conjunction<B> : B { };
|
||||
template<class B, class... Bn>
|
||||
struct conjunction<B, Bn...>
|
||||
: std::conditional<bool(B::value), conjunction<Bn...>, B>::type {};
|
||||
|
||||
// https://en.cppreference.com/w/cpp/types/negation
|
||||
template<class B> struct negation : std::integral_constant < bool, !B::value > { };
|
||||
|
||||
// Reimplementation of is_constructible and is_default_constructible, due to them being broken for
|
||||
// std::pair and std::tuple until LWG 2367 fix (see https://cplusplus.github.io/LWG/lwg-defects.html#2367).
|
||||
// This causes compile errors in e.g. clang 3.5 or gcc 4.9.
|
||||
@ -564,6 +555,25 @@ struct is_ordered_map
|
||||
enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
|
||||
};
|
||||
|
||||
// checks if a type is a basic_json_value placeholder
|
||||
template<typename T>
|
||||
using is_basic_json_value_placeholder =
|
||||
typename std::is_same<uncvref_t<T>, ::nlohmann::placeholders::basic_json_value_placeholder_t>::type;
|
||||
|
||||
template<typename T>
|
||||
using is_basic_json_value_as_placeholder =
|
||||
typename is_specialization_of<::nlohmann::placeholders::basic_json_value_as_placeholder_t, uncvref_t<T>>::type;
|
||||
|
||||
template<typename T>
|
||||
using is_any_basic_json_value_placeholder =
|
||||
typename disjunction<is_basic_json_value_placeholder<T>, is_basic_json_value_as_placeholder<T>>::type;
|
||||
|
||||
template<typename From, typename To>
|
||||
using detect_is_static_castable = decltype(static_cast<To>(std::declval<From>()));
|
||||
|
||||
template<typename From, typename To>
|
||||
using is_static_castable = is_detected<detect_is_static_castable, From, To>;
|
||||
|
||||
// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324)
|
||||
template < typename T, typename U, enable_if_t < !std::is_same<T, U>::value, int > = 0 >
|
||||
T conditional_static_cast(U value)
|
||||
@ -577,5 +587,17 @@ T conditional_static_cast(U value)
|
||||
return value;
|
||||
}
|
||||
|
||||
// non-standard conditional version of as_const
|
||||
template <bool AsConst, typename T>
|
||||
constexpr typename std::conditional<AsConst,
|
||||
typename std::add_const<T>::type, T>::type&
|
||||
conditional_as_const(T& t) noexcept
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
template <bool AsConst, typename T>
|
||||
void conditional_as_const(const T&&) = delete;
|
||||
|
||||
} // namespace detail
|
||||
} // namespace nlohmann
|
||||
|
||||
29
include/nlohmann/detail/placeholders.hpp
Normal file
29
include/nlohmann/detail/placeholders.hpp
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
namespace nlohmann
|
||||
{
|
||||
namespace placeholders
|
||||
{
|
||||
|
||||
struct basic_json_value_placeholder_t
|
||||
{
|
||||
explicit basic_json_value_placeholder_t() = default;
|
||||
};
|
||||
|
||||
static constexpr basic_json_value_placeholder_t basic_json_value{};
|
||||
|
||||
template<typename T>
|
||||
struct basic_json_value_as_placeholder_t
|
||||
{
|
||||
using type = T;
|
||||
explicit basic_json_value_as_placeholder_t() = default;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline constexpr basic_json_value_as_placeholder_t<T> basic_json_value_as() noexcept
|
||||
{
|
||||
return basic_json_value_as_placeholder_t<T> {};
|
||||
}
|
||||
|
||||
} // namespace placeholders
|
||||
} // namespace nlohmann
|
||||
@ -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,25 @@ 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 disagrees with Clang, MSVC, and ICC; selects builtin operator over user-defined
|
||||
// (see GCC bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105200)
|
||||
// ICC may produce incorrect result; test and add if needed
|
||||
#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
|
||||
|
||||
@ -62,6 +62,7 @@ SOFTWARE.
|
||||
#include <memory> // unique_ptr
|
||||
#include <numeric> // accumulate
|
||||
#include <string> // string, stoi, to_string
|
||||
#include <tuple> // forward_as_tuple, tuple
|
||||
#include <utility> // declval, forward, move, pair, swap
|
||||
#include <vector> // vector
|
||||
|
||||
@ -86,10 +87,12 @@ SOFTWARE.
|
||||
#include <nlohmann/detail/string_concat.hpp>
|
||||
#include <nlohmann/detail/string_escape.hpp>
|
||||
#include <nlohmann/detail/meta/cpp_future.hpp>
|
||||
#include <nlohmann/detail/meta/invoke.hpp>
|
||||
#include <nlohmann/detail/meta/type_traits.hpp>
|
||||
#include <nlohmann/detail/output/binary_writer.hpp>
|
||||
#include <nlohmann/detail/output/output_adapters.hpp>
|
||||
#include <nlohmann/detail/output/serializer.hpp>
|
||||
#include <nlohmann/detail/placeholders.hpp>
|
||||
#include <nlohmann/detail/value_t.hpp>
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <nlohmann/ordered_map.hpp>
|
||||
@ -207,6 +210,17 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/// SAX interface type, see @ref nlohmann::json_sax
|
||||
using json_sax_t = json_sax<basic_json>;
|
||||
|
||||
// placeholder for the stored JSON value used in apply*() functions
|
||||
static constexpr decltype(::nlohmann::placeholders::basic_json_value) value_placeholder
|
||||
= ::nlohmann::placeholders::basic_json_value;
|
||||
|
||||
template<typename T>
|
||||
static constexpr auto value_as_placeholder()
|
||||
noexcept -> decltype(::nlohmann::placeholders::basic_json_value_as<T>())
|
||||
{
|
||||
return ::nlohmann::placeholders::basic_json_value_as<T>();
|
||||
}
|
||||
|
||||
////////////////
|
||||
// exceptions //
|
||||
////////////////
|
||||
@ -1905,7 +1919,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 +3551,6 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
/// @}
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////
|
||||
// lexicographical comparison operators //
|
||||
//////////////////////////////////////////
|
||||
@ -3546,6 +3558,222 @@ 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: not equal
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/operator_ne/
|
||||
template<typename ScalarType>
|
||||
requires std::is_scalar_v<ScalarType>
|
||||
bool operator!=(ScalarType rhs) const noexcept
|
||||
{
|
||||
return *this != basic_json(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 the inverse of another operation, unless
|
||||
// that operation is itself computed as the inverse of yet another operation,
|
||||
// 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 +3782,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 +3810,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 +3839,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 +3867,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 +3896,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 +3926,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 +3950,9 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
{
|
||||
return basic_json(lhs) >= rhs;
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef JSON_IMPLEMENT_OPERATOR
|
||||
|
||||
/// @}
|
||||
|
||||
@ -5016,8 +5134,328 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
private:
|
||||
template<typename Arg, typename Value,
|
||||
detail::enable_if_t<detail::is_basic_json_value_placeholder<Arg>::value, int> = 0>
|
||||
auto apply_resolve_placeholder(Arg && /*arg*/, Value && val) const -> decltype(std::forward<Value>(val))
|
||||
{
|
||||
return std::forward<Value>(val);
|
||||
}
|
||||
|
||||
template < typename Arg, typename Value, typename AsType = typename detail::uncvref_t<Arg>::type,
|
||||
detail::enable_if_t < detail::is_basic_json_value_as_placeholder<Arg>::value
|
||||
&& detail::is_static_castable<Value, AsType>::value, int > = 0 >
|
||||
auto apply_resolve_placeholder(Arg && /*arg*/, Value && val) const -> decltype(static_cast<AsType>(std::forward<Value>(val)))
|
||||
{
|
||||
return static_cast<AsType>(std::forward<Value>(val));
|
||||
}
|
||||
|
||||
template < typename Arg, typename Value, typename AsType = typename detail::uncvref_t<Arg>::type,
|
||||
detail::enable_if_t < detail::is_basic_json_value_as_placeholder<Arg>::value
|
||||
&& !detail::is_static_castable<Value, AsType>::value, int > = 0 >
|
||||
//static auto apply_resolve_placeholder(Arg && /*arg*/, Value && val) -> decltype(std::forward<Value>(val))
|
||||
auto apply_resolve_placeholder(Arg && /*arg*/, Value && val) const -> decltype(std::forward<Value>(val))
|
||||
{
|
||||
JSON_THROW(type_error::create(399, detail::concat("cannot cast to requested type"), this));
|
||||
return std::forward<Value>(val);
|
||||
}
|
||||
|
||||
template < typename Arg, typename Value,
|
||||
detail::enable_if_t < !detail::is_any_basic_json_value_placeholder<Arg>::value, int > = 0 >
|
||||
auto apply_resolve_placeholder(Arg && arg, Value&& /*val*/) const -> decltype(std::forward<Arg>(arg))
|
||||
{
|
||||
return std::forward<Arg>(arg);
|
||||
}
|
||||
|
||||
// invoke the result callback
|
||||
template < typename ResultCallback, typename CallbackArg, typename R,
|
||||
detail::enable_if_t <
|
||||
detail::is_null_arg<ResultCallback>::value
|
||||
&& detail::is_null_arg<CallbackArg>::value, int > = 0 >
|
||||
void apply_invoke_cb(ResultCallback && /*cb*/, CallbackArg && /*cb_arg*/, R&& /*r*/) const
|
||||
{}
|
||||
|
||||
template < typename ResultCallback, typename CallbackArg, typename R,
|
||||
detail::enable_if_t <
|
||||
!detail::is_null_arg<ResultCallback>::value
|
||||
&& detail::is_null_arg<CallbackArg>::value
|
||||
&& detail::is_invocable<ResultCallback, R>::value, int > = 0 >
|
||||
void apply_invoke_cb(ResultCallback && cb, CallbackArg && /*cb_arg*/, R && r) const
|
||||
{
|
||||
detail::invoke(std::forward<ResultCallback>(cb), std::forward<R>(r));
|
||||
}
|
||||
|
||||
template < typename ResultCallback, typename CallbackArg, typename R,
|
||||
detail::enable_if_t <
|
||||
!detail::is_null_arg<ResultCallback>::value
|
||||
&& !detail::is_null_arg<CallbackArg>::value
|
||||
&& detail::is_invocable<ResultCallback, CallbackArg, R>::value, int > = 0 >
|
||||
void apply_invoke_cb(ResultCallback && cb, CallbackArg && cb_arg, R && r) const
|
||||
{
|
||||
detail::invoke(std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg), std::forward<R>(r));
|
||||
}
|
||||
|
||||
template < typename ResultCallback, typename CallbackArg, typename R,
|
||||
detail::enable_if_t <
|
||||
(!detail::is_null_arg<ResultCallback>::value
|
||||
&& !detail::is_null_arg<CallbackArg>::value
|
||||
&& !detail::is_invocable<ResultCallback, CallbackArg, R>::value)
|
||||
|| (!detail::is_null_arg<ResultCallback>::value
|
||||
&& detail::is_null_arg<CallbackArg>::value
|
||||
&& !detail::is_invocable<ResultCallback, R>::value), int > = 0 >
|
||||
void apply_invoke_cb(ResultCallback && /*cb*/, CallbackArg && /*cb_arg*/, R&& /*r*/) const
|
||||
{
|
||||
JSON_THROW(type_error::create(319, detail::concat("cannot invoke callback"), this));
|
||||
}
|
||||
|
||||
template<bool ConstThis>
|
||||
void apply_error() const
|
||||
{
|
||||
if (ConstThis)
|
||||
{
|
||||
JSON_THROW(type_error::create(318, detail::concat("cannot invoke callable with const JSON value of type ", type_name()), this));
|
||||
}
|
||||
JSON_THROW(type_error::create(318, detail::concat("cannot invoke callable with JSON value of type ", type_name()), this));
|
||||
}
|
||||
|
||||
// invoke function and possibly delegate result
|
||||
template < bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename Tuple, std::size_t... I,
|
||||
detail::enable_if_t < detail::apply_is_invocable<Value, Fn, Tuple, I...>::value
|
||||
&& std::is_same<detail::apply_invoke_result_t<Value, Fn, Tuple, I...>, void>::value, int > = 0 >
|
||||
void apply_invoke(Value && val, ResultCallback && /*cb*/, CallbackArg && /*cb_arg*/, Fn && f, Tuple && t, detail::index_sequence<I...> /*unused*/) const
|
||||
{
|
||||
detail::invoke(std::forward<Fn>(f), apply_resolve_placeholder(std::get<I>(t), std::forward<Value>(val))...);
|
||||
}
|
||||
|
||||
template < bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename Tuple, std::size_t... I,
|
||||
detail::enable_if_t < detail::apply_is_invocable<Value, Fn, Tuple, I...>::value
|
||||
&& !std::is_same<detail::apply_invoke_result_t<Value, Fn, Tuple, I...>, void>::value, int > = 0 >
|
||||
void apply_invoke(Value && val, ResultCallback && cb, CallbackArg && cb_arg, Fn && f, Tuple && t, detail::index_sequence<I...> /*unused*/) const
|
||||
{
|
||||
auto&& r = detail::invoke(std::forward<Fn>(f), apply_resolve_placeholder(std::get<I>(t), std::forward<Value>(val))...);
|
||||
apply_invoke_cb(std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg), std::forward<decltype(r)>(r));
|
||||
}
|
||||
|
||||
template < bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename Tuple, std::size_t... I,
|
||||
detail::enable_if_t < !detail::apply_is_invocable<Value, Fn, Tuple, I...>::value, int > = 0 >
|
||||
void apply_invoke(Value && /*val*/, ResultCallback && /*cb*/, CallbackArg && /*cb_arg*/, Fn && /*f*/, Tuple && /*t*/, detail::index_sequence<I...> /*unused*/) const
|
||||
{
|
||||
apply_error<ConstThis>();
|
||||
}
|
||||
|
||||
// workaround Clang <4 and GCC <5.2 not being able to construct tuples
|
||||
// of basic_json by wrapping it using std::reference_wrapper
|
||||
#if (defined(__clang__) && __clang_major__ < 4) || \
|
||||
(defined(__GNUC__) && !JSON_HEDLEY_GCC_VERSION_CHECK(5, 2, 0))
|
||||
using apply_basic_json_needs_to_be_wrapped = std::true_type;
|
||||
#else
|
||||
using apply_basic_json_needs_to_be_wrapped = std::false_type;
|
||||
#endif
|
||||
|
||||
template<typename Arg>
|
||||
using apply_arg_needs_to_be_wrapped = std::integral_constant < bool,
|
||||
(apply_basic_json_needs_to_be_wrapped::value
|
||||
&& detail::is_basic_json<detail::uncvref_t<Arg>>::value) >;
|
||||
|
||||
template < typename Arg,
|
||||
detail::enable_if_t < apply_arg_needs_to_be_wrapped<Arg>::value&& std::is_const<Arg>::value, int > = 0 >
|
||||
static auto apply_maybe_wrap_arg(Arg && arg) -> decltype(std::cref(std::forward<Arg>(arg)))
|
||||
{
|
||||
return std::cref(std::forward<Arg>(arg)); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
template < typename Arg,
|
||||
detail::enable_if_t < apply_arg_needs_to_be_wrapped<Arg>::value&& !std::is_const<Arg>::value, int > = 0 >
|
||||
static auto apply_maybe_wrap_arg(Arg && arg) -> decltype(std::ref(std::forward<Arg>(arg)))
|
||||
{
|
||||
return std::ref(std::forward<Arg>(arg)); // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
template < typename Arg,
|
||||
detail::enable_if_t < !apply_arg_needs_to_be_wrapped<Arg>::value, int > = 0 >
|
||||
static auto apply_maybe_wrap_arg(Arg && arg) -> decltype(std::forward<Arg>(arg))
|
||||
{
|
||||
return std::forward<Arg>(arg);
|
||||
}
|
||||
|
||||
// convert arguments to tuple; insert basic_json_value placeholder if missing
|
||||
template < bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename FnArg, typename... Args,
|
||||
detail::enable_if_t < std::is_member_pointer<Fn>::value
|
||||
&& !detail::is_any_basic_json_value_placeholder<FnArg>::value
|
||||
&& !detail::disjunction<detail::is_any_basic_json_value_placeholder<Args>...>::value, int > = 0 >
|
||||
void apply_make_tuple(Value && val, ResultCallback && cb, CallbackArg && cb_arg, Fn && f, FnArg && f_arg, Args && ... args) const
|
||||
{
|
||||
apply_invoke<ConstThis>(
|
||||
std::forward<Value>(val),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward_as_tuple(f_arg, value_placeholder, apply_maybe_wrap_arg(args)...),
|
||||
detail::make_index_sequence < 2 + sizeof...(args) > ());
|
||||
}
|
||||
|
||||
template < bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename... Args,
|
||||
detail::enable_if_t < !std::is_member_pointer<Fn>::value
|
||||
&& !detail::disjunction<detail::is_any_basic_json_value_placeholder<Args>...>::value, int > = 0 >
|
||||
void apply_make_tuple(Value && val, ResultCallback && cb, CallbackArg && cb_arg, Fn && f, Args && ... args) const
|
||||
{
|
||||
apply_invoke<ConstThis>(
|
||||
std::forward<Value>(val),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward_as_tuple(value_placeholder, apply_maybe_wrap_arg(args)...),
|
||||
detail::make_index_sequence < 1 + sizeof...(args) > ());
|
||||
}
|
||||
|
||||
template<bool ConstThis, typename Value, typename ResultCallback, typename CallbackArg, typename Fn, typename... Args,
|
||||
detail::enable_if_t<detail::disjunction<detail::is_any_basic_json_value_placeholder<Args>...>::value, int> = 0>
|
||||
void apply_make_tuple(Value && val, ResultCallback && cb, CallbackArg && cb_arg, Fn && f, Args && ... args) const
|
||||
{
|
||||
apply_invoke<ConstThis>(
|
||||
std::forward<Value>(val),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward_as_tuple(apply_maybe_wrap_arg(args)...),
|
||||
detail::make_index_sequence<sizeof...(args)>());
|
||||
}
|
||||
|
||||
// dispatch based on stored value type
|
||||
template<bool ConstThis, typename ResultCallback, typename CallbackArg, typename Fn, typename... Args>
|
||||
void apply_dispatch(ResultCallback&& cb, CallbackArg&& cb_arg, Fn&& f, Args&& ... args) const
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case value_t::null:
|
||||
return apply_make_tuple<ConstThis>(nullptr,
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::object:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(*m_value.object),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::array:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(*m_value.array),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::string:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(*m_value.string),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::boolean:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(m_value.boolean),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::number_integer:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(m_value.number_integer),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::number_unsigned:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(m_value.number_unsigned),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::number_float:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(m_value.number_float),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::binary:
|
||||
return apply_make_tuple<ConstThis>(detail::conditional_as_const<ConstThis>(*m_value.binary),
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
case value_t::discarded:
|
||||
return apply_error<ConstThis>();
|
||||
default: // LCOV_EXCL_LINE
|
||||
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
template<typename Fn, typename... Args>
|
||||
void apply(Fn&& f, Args&& ... args)
|
||||
{
|
||||
apply_dispatch<false>(
|
||||
detail::null_arg, detail::null_arg,
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Fn, typename... Args>
|
||||
void apply(Fn&& f, Args&& ... args) const
|
||||
{
|
||||
apply_dispatch<true>(
|
||||
detail::null_arg, detail::null_arg,
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename ResultCallback, typename CallbackArg, typename Fn, typename... Args, detail::enable_if_t<
|
||||
std::is_member_pointer<ResultCallback>::value, int> = 0>
|
||||
void apply_cb(ResultCallback && cb, CallbackArg && cb_arg, Fn && f, Args && ... args)
|
||||
{
|
||||
apply_dispatch<false>(
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename ResultCallback, typename CallbackArg, typename Fn, typename... Args, detail::enable_if_t<
|
||||
std::is_member_pointer<ResultCallback>::value, int> = 0>
|
||||
void apply_cb(ResultCallback && cb, CallbackArg && cb_arg, Fn && f, Args && ... args) const
|
||||
{
|
||||
apply_dispatch<true>(
|
||||
std::forward<ResultCallback>(cb), std::forward<CallbackArg>(cb_arg),
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < typename ResultCallback, typename Fn, typename... Args, detail::enable_if_t <
|
||||
!std::is_member_pointer<ResultCallback>::value, int > = 0 >
|
||||
void apply_cb(ResultCallback && cb, Fn && f, Args && ... args)
|
||||
{
|
||||
apply_dispatch<false>(
|
||||
std::forward<ResultCallback>(cb), detail::null_arg,
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template < typename ResultCallback, typename Fn, typename... Args, detail::enable_if_t <
|
||||
!std::is_member_pointer<ResultCallback>::value, int > = 0 >
|
||||
void apply_cb(ResultCallback && cb, Fn && f, Args && ... args) const
|
||||
{
|
||||
apply_dispatch<true>(
|
||||
std::forward<ResultCallback>(cb), detail::null_arg,
|
||||
std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename R, typename Fn, typename... Args>
|
||||
R apply_r(Fn&& f, Args&& ... args)
|
||||
{
|
||||
R out;
|
||||
// dynamic noexcept specifier fails to compile on Clang <3.6
|
||||
apply_cb([&out](R && r)
|
||||
#if !defined(__clang__) || (defined(__clang__) && __clang_major__ == 3 && __clang_minor__ > 5)
|
||||
noexcept(noexcept(out = std::forward<decltype(r)>(r)))
|
||||
#endif
|
||||
{
|
||||
out = std::forward<decltype(r)>(r);
|
||||
}, std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename R, typename Fn, typename... Args>
|
||||
R apply_r(Fn&& f, Args&& ... args) const
|
||||
{
|
||||
R out;
|
||||
// dynamic noexcept specifier fails to compile on Clang <3.6
|
||||
apply_cb([&out](R && r)
|
||||
#if !defined(__clang__) || (defined(__clang__) && __clang_major__ == 3 && __clang_minor__ > 5)
|
||||
noexcept(noexcept(out = std::forward<decltype(r)>(r)))
|
||||
#endif
|
||||
{
|
||||
out = std::forward<decltype(r)>(r);
|
||||
}, std::forward<Fn>(f), std::forward<Args>(args)...);
|
||||
return out;
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef JSON_HAS_CPP_17
|
||||
|
||||
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||
constexpr decltype(::nlohmann::placeholders::basic_json_value) NLOHMANN_BASIC_JSON_TPL::value_placeholder; // NOLINT(readability-redundant-declaration)
|
||||
|
||||
#endif
|
||||
|
||||
/// @brief user-defined to_string function for JSON values
|
||||
/// @sa https://json.nlohmann.me/api/basic_json/to_string/
|
||||
NLOHMANN_BASIC_JSON_TPL_DECLARATION
|
||||
@ -5054,10 +5492,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
|
||||
|
||||
#############################################################################
|
||||
|
||||
667
tests/src/unit-apply.cpp
Normal file
667
tests/src/unit-apply.cpp
Normal file
@ -0,0 +1,667 @@
|
||||
// invoke implementation fails to compile on GCC 8.1 (MinGW)
|
||||
// apply_invoke overload resolution fails for unknown reason on MSVC 2015
|
||||
#if !(defined(__GNUC__) || defined(_MSC_VER)) || (defined (__GNUC__) && !(__GNUC__ == 8 && __GNUC_MINOR__ == 1)) \
|
||||
|| (defined(_MSC_VER) && _MSC_VER > 1900)
|
||||
|
||||
#include "doctest_compatibility.h"
|
||||
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING("-Wshorten-64-to-32")
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING("-Wfloat-conversion")
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING("-Wimplicit-int-float-conversion")
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING("-Wsign-conversion")
|
||||
|
||||
DOCTEST_GCC_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_GCC_SUPPRESS_WARNING("-Wconversion")
|
||||
DOCTEST_GCC_SUPPRESS_WARNING("-Wfloat-conversion")
|
||||
DOCTEST_GCC_SUPPRESS_WARNING("-Wsign-conversion")
|
||||
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING_PUSH
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING(4244) // 'conversion' conversion from 'type1' to 'type2', possible loss of data
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING(4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
using nlohmann::json;
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#if JSON_HAS_RANGES
|
||||
// JSON_HAS_CPP_20 (magic keyword; do not remove)
|
||||
#include <ranges>
|
||||
#endif
|
||||
|
||||
// MSSTL defines as_const in the global namespace :facepalm:
|
||||
template<typename... Args>
|
||||
static auto const_(Args&& ... args) -> decltype(nlohmann::detail::as_const(std::forward<Args>(args)...))
|
||||
{
|
||||
return nlohmann::detail::as_const(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
static void array_push_back(json::array_t& arr, json val)
|
||||
{
|
||||
arr.emplace_back(std::move(val));
|
||||
}
|
||||
|
||||
static void array_push_front(json val, json::array_t& arr)
|
||||
{
|
||||
arr.emplace(arr.begin(), std::move(val));
|
||||
}
|
||||
|
||||
struct foo
|
||||
{
|
||||
int bar = 0;
|
||||
void set_bar(int i) noexcept
|
||||
{
|
||||
bar = i;
|
||||
}
|
||||
|
||||
static int static_bar;
|
||||
static void static_set_bar(int i) noexcept
|
||||
{
|
||||
static_bar = i;
|
||||
}
|
||||
};
|
||||
|
||||
int foo::static_bar = 0;
|
||||
|
||||
struct functor
|
||||
{
|
||||
int arg;
|
||||
int value = 0;
|
||||
|
||||
explicit functor(int arg_ = 0) noexcept : arg(arg_) {}
|
||||
|
||||
void operator()(int a, int b = 0, int c = 0) noexcept
|
||||
{
|
||||
switch (arg)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
value = a;
|
||||
break;
|
||||
case 1:
|
||||
value = b;
|
||||
break;
|
||||
case 2:
|
||||
value = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static int get_value(int i) noexcept
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
static int callback_value = 0;
|
||||
|
||||
static void callback(int i) noexcept
|
||||
{
|
||||
callback_value = i;
|
||||
}
|
||||
|
||||
struct not_an_int
|
||||
{
|
||||
explicit not_an_int() = default;
|
||||
};
|
||||
|
||||
static not_an_int get_not_an_int(int /*unused*/)
|
||||
{
|
||||
return not_an_int{};
|
||||
}
|
||||
|
||||
TEST_CASE("apply*() functions")
|
||||
{
|
||||
SECTION("placeholder")
|
||||
{
|
||||
using nlohmann::placeholders::basic_json_value;
|
||||
using nlohmann::detail::is_basic_json_value_placeholder;
|
||||
CHECK(std::is_same<decltype(basic_json_value), decltype(json::value_placeholder)>::value);
|
||||
CHECK(is_basic_json_value_placeholder<decltype(json::value_placeholder)>::value);
|
||||
CHECK_FALSE(is_basic_json_value_placeholder<json>::value);
|
||||
}
|
||||
|
||||
SECTION("apply()")
|
||||
{
|
||||
SECTION("plain function")
|
||||
{
|
||||
SECTION("const")
|
||||
{
|
||||
const json j = json::array({"foo"});
|
||||
CHECK_THROWS_WITH_AS(j.apply(array_push_back, 42),
|
||||
"[json.exception.type_error.318] cannot invoke callable with const JSON value of type array",
|
||||
json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
SECTION("without explicit placeholder")
|
||||
{
|
||||
json j = json::array({"foo"});
|
||||
json j_expected = json::array({"foo", 42});
|
||||
|
||||
j.apply(array_push_back, 42);
|
||||
|
||||
CHECK(j == j_expected);
|
||||
}
|
||||
|
||||
SECTION("with explicit placeholder")
|
||||
{
|
||||
json j = json::array({"foo"});
|
||||
json j_expected = json::array({42, "foo"});
|
||||
json j_expected2 = json::array({42, "foo", 24});
|
||||
|
||||
j.apply(array_push_front, 42, json::value_placeholder);
|
||||
|
||||
CHECK(j == j_expected);
|
||||
|
||||
j.apply(array_push_back, json::value_placeholder, 24);
|
||||
|
||||
CHECK(j == j_expected2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("static member function pointer")
|
||||
{
|
||||
json j(42);
|
||||
|
||||
SECTION("const (without explicit placeholder)")
|
||||
{
|
||||
foo::static_bar = 0;
|
||||
const_(j).apply(&foo::static_set_bar);
|
||||
|
||||
CHECK(foo::static_bar == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("const (with explicit placeholder)")
|
||||
{
|
||||
foo::static_bar = 0;
|
||||
const_(j).apply(&foo::static_set_bar, json::value_placeholder);
|
||||
|
||||
CHECK(foo::static_bar == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const (without explicit placeholder)")
|
||||
{
|
||||
foo::static_bar = 0;
|
||||
j.apply(&foo::static_set_bar);
|
||||
|
||||
CHECK(foo::static_bar == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const (with explicit placeholder)")
|
||||
{
|
||||
foo::static_bar = 0;
|
||||
j.apply(&foo::static_set_bar, json::value_placeholder);
|
||||
|
||||
CHECK(foo::static_bar == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("non-static member function pointer")
|
||||
{
|
||||
json j(42);
|
||||
|
||||
SECTION("const (without explicit placeholder)")
|
||||
{
|
||||
foo f;
|
||||
|
||||
const_(j).apply(&foo::set_bar, f);
|
||||
|
||||
CHECK(f.bar == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("const (with explicit placeholder)")
|
||||
{
|
||||
foo f;
|
||||
|
||||
const_(j).apply(&foo::set_bar, f, json::value_placeholder);
|
||||
|
||||
CHECK(f.bar == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const (without explicit placeholder)")
|
||||
{
|
||||
foo f;
|
||||
|
||||
j.apply(&foo::set_bar, f);
|
||||
|
||||
CHECK(f.bar == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const (with explicit placeholder)")
|
||||
{
|
||||
foo f;
|
||||
|
||||
j.apply(&foo::set_bar, f, json::value_placeholder);
|
||||
|
||||
CHECK(f.bar == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("non-static function member pointer (json::array_t::resize)")
|
||||
{
|
||||
json j = json::array();
|
||||
json j_expected = json::array({42, 42});
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS(const_(j).apply(static_cast<void (json::array_t::*)(json::array_t::size_type, const json&)>(&json::array_t::resize), json::value_placeholder, 2, json(42)),
|
||||
"[json.exception.type_error.318] cannot invoke callable with const JSON value of type array",
|
||||
json::type_error&);
|
||||
CHECK(j.empty());
|
||||
}
|
||||
|
||||
SECTION("non-const (without explicit placeholder)")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS(
|
||||
j.apply(static_cast<void (json::array_t::*)(json::array_t::size_type, const json&)>(&json::array_t::resize), 2, json(42)),
|
||||
"[json.exception.type_error.318] cannot invoke callable with JSON value of type array",
|
||||
json::type_error&);
|
||||
CHECK(j.empty());
|
||||
}
|
||||
|
||||
SECTION("non-const (with explicit placeholder)")
|
||||
{
|
||||
j.apply(static_cast<void (json::array_t::*)(json::array_t::size_type, const json&)>(&json::array_t::resize), json::value_placeholder, 2, json(42));
|
||||
|
||||
CHECK(j == j_expected);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("functor")
|
||||
{
|
||||
json j(42);
|
||||
|
||||
SECTION("const (without explicit placeholder)")
|
||||
{
|
||||
functor f{0};
|
||||
const_(j).apply(f, -1, -2);
|
||||
|
||||
CHECK(f.value == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("const (with explicit placeholder)")
|
||||
{
|
||||
functor f{1};
|
||||
const_(j).apply(f, 0, json::value_placeholder, -2);
|
||||
|
||||
CHECK(f.value == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const (without explicit placeholder)")
|
||||
{
|
||||
functor f{0};
|
||||
j.apply(f, -1, -2);
|
||||
|
||||
CHECK(f.value == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const (with explicit placeholder)")
|
||||
{
|
||||
functor f{1};
|
||||
j.apply(f, 0, json::value_placeholder, -2);
|
||||
|
||||
CHECK(f.value == 42);
|
||||
CHECK(j == 42);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("discarded JSON value")
|
||||
{
|
||||
json j(json::value_t::discarded);
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS(
|
||||
const_(j).apply(nlohmann::detail::null_arg),
|
||||
"[json.exception.type_error.318] cannot invoke callable with const JSON value of type discarded",
|
||||
json::type_error&);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS(
|
||||
j.apply(nlohmann::detail::null_arg),
|
||||
"[json.exception.type_error.318] cannot invoke callable with JSON value of type discarded",
|
||||
json::type_error&);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("apply_r()")
|
||||
{
|
||||
SECTION("value types")
|
||||
{
|
||||
SECTION("null")
|
||||
{
|
||||
json j;
|
||||
|
||||
auto is_null = [](std::nullptr_t) noexcept
|
||||
{
|
||||
return true;
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_null());
|
||||
CHECK(const_(j).apply_r<bool>(is_null));
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_null());
|
||||
CHECK(j.apply_r<bool>(is_null));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("object")
|
||||
{
|
||||
json j{{"foo", 0}, {"bar", 42}};
|
||||
|
||||
auto get_bar = [](const json::object_t& obj)
|
||||
{
|
||||
#if JSON_USE_IMPLICIT_CONVERSIONS
|
||||
return obj.at("bar");
|
||||
#else
|
||||
return obj.at("bar").get<int>();
|
||||
#endif
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_object());
|
||||
CHECK(const_(j).apply_r<int>(get_bar) == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_object());
|
||||
CHECK(j.apply_r<int>(get_bar) == 42);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
json j{0, 1, 42, 3, 4};
|
||||
|
||||
auto get_2 = [](const json::array_t& arr)
|
||||
{
|
||||
#if JSON_USE_IMPLICIT_CONVERSIONS
|
||||
return arr[2];
|
||||
#else
|
||||
return arr[2].get<int>();
|
||||
#endif
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_array());
|
||||
CHECK(const_(j).apply_r<int>(get_2) == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_array());
|
||||
CHECK(j.apply_r<int>(get_2) == 42);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("string")
|
||||
{
|
||||
json j("fourty two");
|
||||
|
||||
auto length = [](const json::string_t& str) noexcept
|
||||
{
|
||||
return str.size();
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_string());
|
||||
CHECK(const_(j).apply_r<std::size_t>(length) == 10);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_string());
|
||||
CHECK(j.apply_r<std::size_t>(length) == 10);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("boolean")
|
||||
{
|
||||
json j(false);
|
||||
|
||||
auto negate = [](bool b) noexcept
|
||||
{
|
||||
return !b;
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_boolean());
|
||||
CHECK(const_(j).apply_r<bool>(negate));
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_boolean());
|
||||
CHECK(j.apply_r<bool>(negate));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number_integer")
|
||||
{
|
||||
json j(-7);
|
||||
|
||||
auto calc = [](json::number_integer_t i) noexcept
|
||||
{
|
||||
return i * i + i;
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_number_integer());
|
||||
CHECK(const_(j).apply_r<int>(calc) == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_number_integer());
|
||||
CHECK(j.apply_r<int>(calc) == 42);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number_unsigned")
|
||||
{
|
||||
json j(static_cast<json::number_unsigned_t>(7));
|
||||
|
||||
auto calc = [](json::number_unsigned_t i) noexcept
|
||||
{
|
||||
return i * i - i;
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_number_unsigned());
|
||||
CHECK(const_(j).apply_r<int>(calc) == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_number_unsigned());
|
||||
CHECK(j.apply_r<int>(calc) == 42);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("number_float")
|
||||
{
|
||||
json j(6.480741);
|
||||
|
||||
auto square = [](json::number_float_t f) noexcept
|
||||
{
|
||||
return f * f;
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_number_float());
|
||||
CHECK(const_(j).apply_r<double>(square) == doctest::Approx(42.0));
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_number_float());
|
||||
CHECK(j.apply_r<double>(square) == doctest::Approx(42.0));
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("binary")
|
||||
{
|
||||
json j = json::binary(std::vector<std::uint8_t> {0xC0, 0xFF, 0xEE});
|
||||
|
||||
auto get_1 = [](const json::binary_t& bin) noexcept
|
||||
{
|
||||
return bin[1];
|
||||
};
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
CHECK(j.is_binary());
|
||||
CHECK(const_(j).apply_r<std::uint8_t>(get_1) == 0xFF);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
CHECK(j.is_binary());
|
||||
CHECK(j.apply_r<std::uint8_t>(get_1) == 0xFF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if JSON_HAS_RANGES
|
||||
SECTION("std::ranges::min")
|
||||
{
|
||||
json j = json::array({5, 3, 4, 2});
|
||||
|
||||
SECTION("const (without explicit placeholder)")
|
||||
{
|
||||
CHECK(const_(j).apply_r<int>(std::ranges::min) == 2);
|
||||
}
|
||||
|
||||
SECTION("const (with explicit placeholder)")
|
||||
{
|
||||
CHECK(const_(j).apply_r<int>(std::ranges::min, json::value_placeholder) == 2);
|
||||
}
|
||||
|
||||
SECTION("non-const (without explicit placeholder)")
|
||||
{
|
||||
CHECK(j.apply_r<int>(std::ranges::min) == 2);
|
||||
}
|
||||
|
||||
SECTION("non-const (with explicit placeholder)")
|
||||
{
|
||||
CHECK(j.apply_r<int>(std::ranges::min, json::value_placeholder) == 2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
SECTION("apply_cb()")
|
||||
{
|
||||
SECTION("plain function callback")
|
||||
{
|
||||
json j(42);
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
callback_value = 0;
|
||||
const_(j).apply_cb(callback, get_value);
|
||||
|
||||
CHECK(callback_value == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
callback_value = 0;
|
||||
j.apply_cb(callback, get_value);
|
||||
|
||||
CHECK(callback_value == 42);
|
||||
}
|
||||
|
||||
SECTION("exception")
|
||||
{
|
||||
CHECK_THROWS_WITH_AS(
|
||||
j.apply_cb(callback, get_not_an_int),
|
||||
"[json.exception.type_error.319] cannot invoke callback",
|
||||
json::type_error&);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("static member function pointer")
|
||||
{
|
||||
json j(42);
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
foo::static_bar = 0;
|
||||
const_(j).apply_cb(&foo::static_set_bar, get_value);
|
||||
|
||||
CHECK(foo::static_bar == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
foo::static_bar = 0;
|
||||
j.apply_cb(&foo::static_set_bar, get_value);
|
||||
|
||||
CHECK(foo::static_bar == 42);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("non-static member function pointer")
|
||||
{
|
||||
json j(42);
|
||||
|
||||
SECTION("const")
|
||||
{
|
||||
foo f;
|
||||
|
||||
const_(j).apply_cb(&foo::set_bar, f, get_value);
|
||||
|
||||
CHECK(f.bar == 42);
|
||||
}
|
||||
|
||||
SECTION("non-const")
|
||||
{
|
||||
foo f;
|
||||
|
||||
j.apply_cb(&foo::set_bar, f, get_value);
|
||||
|
||||
CHECK(f.bar == 42);
|
||||
}
|
||||
}
|
||||
|
||||
// add functor
|
||||
}
|
||||
}
|
||||
|
||||
DOCTEST_CLANG_SUPPRESS_WARNING_POP
|
||||
DOCTEST_GCC_SUPPRESS_WARNING_POP
|
||||
DOCTEST_MSVC_SUPPRESS_WARNING_POP
|
||||
|
||||
#endif
|
||||
@ -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,265 @@ 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
|
||||
};
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
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 precomputed values
|
||||
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
|
||||
};
|
||||
|
||||
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
|
||||
};
|
||||
|
||||
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")
|
||||
{
|
||||
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 precomputed values
|
||||
CHECK((j_values[i] == j_values[j]) == expected_eq[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
// compare with null pointer
|
||||
@ -164,73 +391,41 @@ TEST_CASE("lexicographical comparison operators")
|
||||
{
|
||||
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))
|
||||
{
|
||||
CHECK_FALSE(j_values[i] != j_values[j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// check definition
|
||||
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}
|
||||
};
|
||||
|
||||
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")
|
||||
@ -241,8 +436,15 @@ TEST_CASE("lexicographical comparison operators")
|
||||
{
|
||||
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))
|
||||
{
|
||||
CHECK_FALSE(j_values[i] <= j_values[j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// check definition
|
||||
CHECK((j_values[i] <= j_values[j]) == !(j_values[j] < j_values[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -255,8 +457,15 @@ TEST_CASE("lexicographical comparison operators")
|
||||
{
|
||||
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]))
|
||||
{
|
||||
CHECK_FALSE(j_values[i] > j_values[j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// check definition
|
||||
CHECK((j_values[i] > j_values[j]) == (j_values[j] < j_values[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -269,10 +478,112 @@ TEST_CASE("lexicographical comparison operators")
|
||||
{
|
||||
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))
|
||||
{
|
||||
CHECK_FALSE(j_values[i] >= j_values[j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// check definition
|
||||
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
|
||||
};
|
||||
|
||||
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]);
|
||||
}
|
||||
}
|
||||
|
||||
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