🎨 use Clang-Format

This commit is contained in:
Niels Lohmann committed 2023-11-29 18:01:57 +01:00
1 parent 9cca280a4d
commit 311ad0b877
123 files changed
+17729 -15754

No files matched your search

+4 -5
View File
@@ -1,4 +1,3 @@
#AccessModifierOffset: 2
AlignAfterOpenBracket: Align AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false AlignConsecutiveAssignments: false
#AlignConsecutiveBitFields: false #AlignConsecutiveBitFields: false
@@ -12,7 +11,7 @@ AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Empty AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false
#AllowShortEnumsOnASingleLine: true AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Empty AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: Empty AllowShortLambdasOnASingleLine: Empty
@@ -36,8 +35,8 @@ BraceWrapping:
AfterExternBlock: false AfterExternBlock: false
BeforeCatch: true BeforeCatch: true
BeforeElse: true BeforeElse: true
#BeforeLambdaBody: false BeforeLambdaBody: false
#BeforeWhile: false BeforeWhile: false
SplitEmptyFunction: false SplitEmptyFunction: false
SplitEmptyRecord: false SplitEmptyRecord: false
SplitEmptyNamespace: false SplitEmptyNamespace: false
@@ -60,7 +59,7 @@ KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 1 MaxEmptyLinesToKeep: 1
NamespaceIndentation: None NamespaceIndentation: None
ReflowComments: false ReflowComments: false
SortIncludes: true SortIncludes: CaseSensitive
SortUsingDeclarations: true SortUsingDeclarations: true
SpaceAfterCStyleCast: false SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false SpaceAfterLogicalNot: false
+1 -1
View File
@@ -50,7 +50,7 @@ To make changes, you need to edit the following files:
## Note ## Note
- If you open a pull request, the code will be automatically tested with [Valgrind](http://valgrind.org)'s Memcheck tool to detect memory leaks. Please be aware that the execution with Valgrind _may_ in rare cases yield different behavior than running the code directly. This can result in failing unit tests which run successfully without Valgrind. - If you open a pull request, the code will be automatically tested with [Valgrind](http://valgrind.org)'s Memcheck tool to detect memory leaks. Please be aware that the execution with Valgrind _may_ in rare cases yield different behavior than running the code directly. This can result in failing unit tests which run successfully without Valgrind.
- There is a Makefile target `make pretty` which runs [Artistic Style](http://astyle.sourceforge.net) to fix indentation. If possible, run it before opening the pull request. Otherwise, we shall run it afterward. - There is a Makefile target `make pretty` which runs [Clang-Format](https://clang.llvm.org/docs/ClangFormat.html) to fix indentation. If possible, run it before opening the pull request. Otherwise, we shall run it afterward.
## Please don't ## Please don't
+1 -28
View File
@@ -23,13 +23,6 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
env: env:
MAIN_DIR: ${{ github.workspace }}/main MAIN_DIR: ${{ github.workspace }}/main
INCLUDE_DIR: ${{ github.workspace }}/main/single_include/nlohmann
TOOL_DIR: ${{ github.workspace }}/tools/tools/amalgamate
ASTYLE_FLAGS: >
--style=allman --indent=spaces=4 --indent-modifiers --indent-switches --indent-preproc-block
--indent-preproc-define --indent-col1-comments --pad-oper --pad-header --align-pointer=type
--align-reference=type --add-brackets --convert-tabs --close-templates --lineend=linux --preserve-date
--formatted
steps: steps:
- name: Checkout pull request - name: Checkout pull request
@@ -44,27 +37,7 @@ jobs:
path: tools path: tools
ref: develop ref: develop
- name: Install astyle
run: |
sudo apt-get update
sudo apt-get install astyle
- name: Check amalgamation - name: Check amalgamation
run: | run: |
cd $MAIN_DIR cd $MAIN_DIR
make check-amalgamation
rm -fr $INCLUDE_DIR/json.hpp~ $INCLUDE_DIR/json_fwd.hpp~
cp $INCLUDE_DIR/json.hpp $INCLUDE_DIR/json.hpp~
cp $INCLUDE_DIR/json_fwd.hpp $INCLUDE_DIR/json_fwd.hpp~
python3 $TOOL_DIR/amalgamate.py -c $TOOL_DIR/config_json.json -s .
python3 $TOOL_DIR/amalgamate.py -c $TOOL_DIR/config_json_fwd.json -s .
echo "Format (1)"
astyle $ASTYLE_FLAGS --suffix=none --quiet $INCLUDE_DIR/json.hpp $INCLUDE_DIR/json_fwd.hpp
diff $INCLUDE_DIR/json.hpp~ $INCLUDE_DIR/json.hpp
diff $INCLUDE_DIR/json_fwd.hpp~ $INCLUDE_DIR/json_fwd.hpp
astyle $ASTYLE_FLAGS $(find docs/examples include tests -type f \( -name '*.hpp' -o -name '*.cpp' -o -name '*.cu' \) -not -path 'tests/thirdparty/*' -not -path 'tests/abi/include/nlohmann/*' | sort)
echo Check
find $MAIN_DIR -name '*.orig' -exec false {} \+
+2 -26
View File
@@ -142,33 +142,9 @@ pvs_studio:
# Code format and source amalgamation # Code format and source amalgamation
########################################################################## ##########################################################################
# call the Artistic Style pretty printer on all source files
pretty:
astyle \
--style=allman \
--indent=spaces=4 \
--indent-modifiers \
--indent-switches \
--indent-preproc-block \
--indent-preproc-define \
--indent-col1-comments \
--pad-oper \
--pad-header \
--align-pointer=type \
--align-reference=type \
--add-braces \
--squeeze-lines=2 \
--convert-tabs \
--close-templates \
--lineend=linux \
--preserve-date \
--suffix=none \
--formatted \
$(SRCS) $(TESTS_SRCS) $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) docs/examples/*.cpp
# call the Clang-Format on all source files # call the Clang-Format on all source files
pretty_format: pretty:
for FILE in $(SRCS) $(TESTS_SRCS) $(AMALGAMATED_FILE) docs/examples/*.cpp; do echo $$FILE; clang-format -i $$FILE; done clang-format --Werror --verbose -i $(SRCS) $(TESTS_SRCS) $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE)
# create single header files and pretty print # create single header files and pretty print
amalgamate: $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE) amalgamate: $(AMALGAMATED_FILE) $(AMALGAMATED_FWD_FILE)
+1 -1
View File
@@ -1774,8 +1774,8 @@ The library itself consists of a single header file licensed under the MIT licen
- [**amalgamate.py - Amalgamate C source and header files**](https://github.com/edlund/amalgamate) to create a single header file - [**amalgamate.py - Amalgamate C source and header files**](https://github.com/edlund/amalgamate) to create a single header file
- [**American fuzzy lop**](https://lcamtuf.coredump.cx/afl/) for fuzz testing - [**American fuzzy lop**](https://lcamtuf.coredump.cx/afl/) for fuzz testing
- [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows - [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows
- [**Artistic Style**](http://astyle.sourceforge.net) for automatic source code indentation
- [**Clang**](https://clang.llvm.org) for compilation with code sanitizers - [**Clang**](https://clang.llvm.org) for compilation with code sanitizers
- [**Clang-Format**](https://clang.llvm.org/docs/ClangFormat.html) for automatic source code indentation
- [**CMake**](https://cmake.org) for build automation - [**CMake**](https://cmake.org) for build automation
- [**Codacy**](https://www.codacy.com) for further [code analysis](https://www.codacy.com/app/nlohmann/json) - [**Codacy**](https://www.codacy.com) for further [code analysis](https://www.codacy.com/app/nlohmann/json)
- [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json) - [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json)
+6 -31
View File
@@ -8,16 +8,16 @@ set(N 10)
include(FindPython3) include(FindPython3)
find_package(Python3 COMPONENTS Interpreter) find_package(Python3 COMPONENTS Interpreter)
find_program(ASTYLE_TOOL NAMES astyle)
execute_process(COMMAND ${ASTYLE_TOOL} --version OUTPUT_VARIABLE ASTYLE_TOOL_VERSION ERROR_VARIABLE ASTYLE_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" ASTYLE_TOOL_VERSION "${ASTYLE_TOOL_VERSION}")
message(STATUS "🔖 Artistic Style ${ASTYLE_TOOL_VERSION} (${ASTYLE_TOOL})")
find_program(CLANG_TOOL NAMES clang++-HEAD clang++ clang++-17 clang++-16 clang++-15 clang++-14 clang++-13 clang++-12 clang++-11 clang++) find_program(CLANG_TOOL NAMES clang++-HEAD clang++ clang++-17 clang++-16 clang++-15 clang++-14 clang++-13 clang++-12 clang++-11 clang++)
execute_process(COMMAND ${CLANG_TOOL} --version OUTPUT_VARIABLE CLANG_TOOL_VERSION ERROR_VARIABLE CLANG_TOOL_VERSION) execute_process(COMMAND ${CLANG_TOOL} --version OUTPUT_VARIABLE CLANG_TOOL_VERSION ERROR_VARIABLE CLANG_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_TOOL_VERSION "${CLANG_TOOL_VERSION}") string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_TOOL_VERSION "${CLANG_TOOL_VERSION}")
message(STATUS "🔖 Clang ${CLANG_TOOL_VERSION} (${CLANG_TOOL})") message(STATUS "🔖 Clang ${CLANG_TOOL_VERSION} (${CLANG_TOOL})")
find_program(CLANG_FORMAT_TOOL NAMES clang-format)
execute_process(COMMAND ${CLANG_FORMAT_TOOL} --version OUTPUT_VARIABLE CLANG_FORMAT_TOOL_VERSION ERROR_VARIABLE CLANG_FORMAT_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_FORMAT_TOOL_VERSION "${CLANG_FORMAT_TOOL_VERSION}")
message(STATUS "🔖 Clang-Format ${CLANG_FORMAT_TOOL_VERSION} (${CLANG_FORMAT_TOOL})")
find_program(CLANG_TIDY_TOOL NAMES clang-tidy-17 clang-tidy-16 clang-tidy-15 clang-tidy-14 clang-tidy-13 clang-tidy-12 clang-tidy-11 clang-tidy) find_program(CLANG_TIDY_TOOL NAMES clang-tidy-17 clang-tidy-16 clang-tidy-15 clang-tidy-14 clang-tidy-13 clang-tidy-12 clang-tidy-11 clang-tidy)
execute_process(COMMAND ${CLANG_TIDY_TOOL} --version OUTPUT_VARIABLE CLANG_TIDY_TOOL_VERSION ERROR_VARIABLE CLANG_TIDY_TOOL_VERSION) execute_process(COMMAND ${CLANG_TIDY_TOOL} --version OUTPUT_VARIABLE CLANG_TIDY_TOOL_VERSION ERROR_VARIABLE CLANG_TIDY_TOOL_VERSION)
string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_TIDY_TOOL_VERSION "${CLANG_TIDY_TOOL_VERSION}") string(REGEX MATCH "[0-9]+(\\.[0-9]+)+" CLANG_TIDY_TOOL_VERSION "${CLANG_TIDY_TOOL_VERSION}")
@@ -581,33 +581,8 @@ add_custom_target(ci_test_clang_sanitizer
# Check if header is amalgamated and sources are properly indented. # Check if header is amalgamated and sources are properly indented.
############################################################################### ###############################################################################
set(ASTYLE_FLAGS --style=allman --indent=spaces=4 --indent-modifiers --indent-switches --indent-preproc-block --indent-preproc-define --indent-col1-comments --pad-oper --pad-header --align-pointer=type --align-reference=type --add-brackets --convert-tabs --close-templates --lineend=linux --preserve-date --formatted)
file(GLOB_RECURSE INDENT_FILES
${PROJECT_SOURCE_DIR}/include/nlohmann/*.hpp
${PROJECT_SOURCE_DIR}/tests/src/*.cpp
${PROJECT_SOURCE_DIR}/tests/src/*.hpp
${PROJECT_SOURCE_DIR}/tests/benchmarks/src/benchmarks.cpp
${PROJECT_SOURCE_DIR}/docs/examples/*.cpp
)
set(include_dir ${PROJECT_SOURCE_DIR}/single_include/nlohmann)
set(tool_dir ${PROJECT_SOURCE_DIR}/tools/amalgamate)
add_custom_target(ci_test_amalgamation add_custom_target(ci_test_amalgamation
COMMAND rm -fr ${include_dir}/json.hpp~ ${include_dir}/json_fwd.hpp~ COMMAND make check-amalgamation
COMMAND cp ${include_dir}/json.hpp ${include_dir}/json.hpp~
COMMAND cp ${include_dir}/json_fwd.hpp ${include_dir}/json_fwd.hpp~
COMMAND ${Python3_EXECUTABLE} ${tool_dir}/amalgamate.py -c ${tool_dir}/config_json.json -s .
COMMAND ${Python3_EXECUTABLE} ${tool_dir}/amalgamate.py -c ${tool_dir}/config_json_fwd.json -s .
COMMAND ${ASTYLE_TOOL} ${ASTYLE_FLAGS} --suffix=none --quiet ${include_dir}/json.hpp ${include_dir}/json_fwd.hpp
COMMAND diff ${include_dir}/json.hpp~ ${include_dir}/json.hpp
COMMAND diff ${include_dir}/json_fwd.hpp~ ${include_dir}/json_fwd.hpp
COMMAND ${ASTYLE_TOOL} ${ASTYLE_FLAGS} ${INDENT_FILES}
COMMAND for FILE in `find . -name '*.orig'`\; do false \; done
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
COMMENT "Check amalgamation and indentation" COMMENT "Check amalgamation and indentation"
) )
+8 -8
View File
@@ -24,9 +24,9 @@ struct adl_serializer
/// @brief convert a JSON value to any value type /// @brief convert a JSON value to any value type
/// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/
template<typename BasicJsonType, typename TargetType = ValueType> template<typename BasicJsonType, typename TargetType = ValueType>
static auto from_json(BasicJsonType && j, TargetType& val) noexcept( static auto from_json(BasicJsonType&& j, TargetType& val) noexcept(
noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val))) noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), val)))
-> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void()) -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), val), void())
{ {
::nlohmann::from_json(std::forward<BasicJsonType>(j), val); ::nlohmann::from_json(std::forward<BasicJsonType>(j), val);
} }
@@ -34,19 +34,19 @@ struct adl_serializer
/// @brief convert a JSON value to any value type /// @brief convert a JSON value to any value type
/// @sa https://json.nlohmann.me/api/adl_serializer/from_json/ /// @sa https://json.nlohmann.me/api/adl_serializer/from_json/
template<typename BasicJsonType, typename TargetType = ValueType> template<typename BasicJsonType, typename TargetType = ValueType>
static auto from_json(BasicJsonType && j) noexcept( static auto from_json(BasicJsonType&& j) noexcept(
noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {}))) noexcept(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType>{})))
-> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {})) -> decltype(::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType>{}))
{ {
return ::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType> {}); return ::nlohmann::from_json(std::forward<BasicJsonType>(j), detail::identity_tag<TargetType>{});
} }
/// @brief convert any value type to a JSON value /// @brief convert any value type to a JSON value
/// @sa https://json.nlohmann.me/api/adl_serializer/to_json/ /// @sa https://json.nlohmann.me/api/adl_serializer/to_json/
template<typename BasicJsonType, typename TargetType = ValueType> template<typename BasicJsonType, typename TargetType = ValueType>
static auto to_json(BasicJsonType& j, TargetType && val) noexcept( static auto to_json(BasicJsonType& j, TargetType&& val) noexcept(
noexcept(::nlohmann::to_json(j, std::forward<TargetType>(val)))) noexcept(::nlohmann::to_json(j, std::forward<TargetType>(val))))
-> decltype(::nlohmann::to_json(j, std::forward<TargetType>(val)), void()) -> decltype(::nlohmann::to_json(j, std::forward<TargetType>(val)), void())
{ {
::nlohmann::to_json(j, std::forward<TargetType>(val)); ::nlohmann::to_json(j, std::forward<TargetType>(val));
} }
@@ -8,9 +8,9 @@
#pragma once #pragma once
#include <cstdint> // uint8_t, uint64_t #include <cstdint> // uint8_t, uint64_t
#include <tuple> // tie #include <tuple> // tie
#include <utility> // move #include <utility> // move
#include <nlohmann/detail/abi_macros.hpp> #include <nlohmann/detail/abi_macros.hpp>
@@ -27,31 +27,31 @@ class byte_container_with_subtype : public BinaryType
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
byte_container_with_subtype() noexcept(noexcept(container_type())) byte_container_with_subtype() noexcept(noexcept(container_type()))
: container_type() : container_type()
{} {}
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b))) byte_container_with_subtype(const container_type& b) noexcept(noexcept(container_type(b)))
: container_type(b) : container_type(b)
{} {}
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b)))) byte_container_with_subtype(container_type&& b) noexcept(noexcept(container_type(std::move(b))))
: container_type(std::move(b)) : container_type(std::move(b))
{} {}
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b))) byte_container_with_subtype(const container_type& b, subtype_type subtype_) noexcept(noexcept(container_type(b)))
: container_type(b) : container_type(b)
, m_subtype(subtype_) , m_subtype(subtype_)
, m_has_subtype(true) , m_has_subtype(true)
{} {}
/// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/ /// @sa https://json.nlohmann.me/api/byte_container_with_subtype/byte_container_with_subtype/
byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b)))) byte_container_with_subtype(container_type&& b, subtype_type subtype_) noexcept(noexcept(container_type(std::move(b))))
: container_type(std::move(b)) : container_type(std::move(b))
, m_subtype(subtype_) , m_subtype(subtype_)
, m_has_subtype(true) , m_has_subtype(true)
{} {}
bool operator==(const byte_container_with_subtype& rhs) const bool operator==(const byte_container_with_subtype& rhs) const
+23 -25
View File
@@ -47,54 +47,52 @@
#endif #endif
// Construct the namespace ABI tags component // Construct the namespace ABI tags component
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b #define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi##a##b
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ #define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b)
#define NLOHMANN_JSON_ABI_TAGS \ #define NLOHMANN_JSON_ABI_TAGS \
NLOHMANN_JSON_ABI_TAGS_CONCAT( \ NLOHMANN_JSON_ABI_TAGS_CONCAT( \
NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON)
// Construct the namespace version component // Construct the namespace version component
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ #define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
_v ## major ## _ ## minor ## _ ## patch _v##major##_##minor##_##patch
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ #define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)
#if NLOHMANN_JSON_NAMESPACE_NO_VERSION #if NLOHMANN_JSON_NAMESPACE_NO_VERSION
#define NLOHMANN_JSON_NAMESPACE_VERSION #define NLOHMANN_JSON_NAMESPACE_VERSION
#else #else
#define NLOHMANN_JSON_NAMESPACE_VERSION \ #define NLOHMANN_JSON_NAMESPACE_VERSION \
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \
NLOHMANN_JSON_VERSION_MINOR, \ NLOHMANN_JSON_VERSION_MINOR, \
NLOHMANN_JSON_VERSION_PATCH) NLOHMANN_JSON_VERSION_PATCH)
#endif #endif
// Combine namespace components // Combine namespace components
#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b #define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a##b
#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ #define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \
NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)
#ifndef NLOHMANN_JSON_NAMESPACE #ifndef NLOHMANN_JSON_NAMESPACE
#define NLOHMANN_JSON_NAMESPACE \ #define NLOHMANN_JSON_NAMESPACE \
nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \
NLOHMANN_JSON_ABI_TAGS, \ NLOHMANN_JSON_ABI_TAGS, \
NLOHMANN_JSON_NAMESPACE_VERSION) NLOHMANN_JSON_NAMESPACE_VERSION)
#endif #endif
#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN #ifndef NLOHMANN_JSON_NAMESPACE_BEGIN
#define NLOHMANN_JSON_NAMESPACE_BEGIN \ #define NLOHMANN_JSON_NAMESPACE_BEGIN \
namespace nlohmann \ namespace nlohmann { \
{ \ inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \
inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ NLOHMANN_JSON_ABI_TAGS, \
NLOHMANN_JSON_ABI_TAGS, \ NLOHMANN_JSON_NAMESPACE_VERSION) {
NLOHMANN_JSON_NAMESPACE_VERSION) \
{
#endif #endif
#ifndef NLOHMANN_JSON_NAMESPACE_END #ifndef NLOHMANN_JSON_NAMESPACE_END
#define NLOHMANN_JSON_NAMESPACE_END \ #define NLOHMANN_JSON_NAMESPACE_END \
} /* namespace (inline namespace) NOLINT(readability/namespace) */ \ } /* namespace (inline namespace) NOLINT(readability/namespace) */ \
} // namespace nlohmann } // namespace nlohmann
#endif #endif
+73 -113
View File
@@ -8,17 +8,17 @@
#pragma once #pragma once
#include <algorithm> // transform #include <algorithm> // transform
#include <array> // array #include <array> // array
#include <forward_list> // forward_list #include <forward_list> // forward_list
#include <iterator> // inserter, front_inserter, end #include <iterator> // inserter, front_inserter, end
#include <map> // map #include <map> // map
#include <string> // string #include <string> // string
#include <tuple> // tuple, make_tuple #include <tuple> // tuple, make_tuple
#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible #include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible
#include <unordered_map> // unordered_map #include <unordered_map> // unordered_map
#include <utility> // pair, declval #include <utility> // pair, declval
#include <valarray> // valarray #include <valarray> // valarray
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
@@ -30,8 +30,7 @@
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
template<typename BasicJsonType> template<typename BasicJsonType>
inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n) inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
@@ -44,10 +43,7 @@ inline void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
} }
// overloads for basic_json template parameters // overloads for basic_json template parameters
template < typename BasicJsonType, typename ArithmeticType, template<typename BasicJsonType, typename ArithmeticType, enable_if_t<std::is_arithmetic<ArithmeticType>::value && !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value, int> = 0>
enable_if_t < std::is_arithmetic<ArithmeticType>::value&&
!std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
int > = 0 >
void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val) void get_arithmetic_value(const BasicJsonType& j, ArithmeticType& val)
{ {
switch (static_cast<value_t>(j)) switch (static_cast<value_t>(j))
@@ -100,13 +96,12 @@ inline void from_json(const BasicJsonType& j, typename BasicJsonType::string_t&
s = *j.template get_ptr<const typename BasicJsonType::string_t*>(); s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
} }
template < template<
typename BasicJsonType, typename StringType, typename BasicJsonType,
enable_if_t < typename StringType,
std::is_assignable<StringType&, const typename BasicJsonType::string_t>::value enable_if_t<
&& is_detected_exact<typename BasicJsonType::string_t::value_type, value_type_t, StringType>::value std::is_assignable<StringType&, const typename BasicJsonType::string_t>::value && is_detected_exact<typename BasicJsonType::string_t::value_type, value_type_t, StringType>::value && !std::is_same<typename BasicJsonType::string_t, StringType>::value && !is_json_ref<StringType>::value,
&& !std::is_same<typename BasicJsonType::string_t, StringType>::value int> = 0>
&& !is_json_ref<StringType>::value, int > = 0 >
inline void from_json(const BasicJsonType& j, StringType& s) inline void from_json(const BasicJsonType& j, StringType& s)
{ {
if (JSON_HEDLEY_UNLIKELY(!j.is_string())) if (JSON_HEDLEY_UNLIKELY(!j.is_string()))
@@ -136,8 +131,7 @@ inline void from_json(const BasicJsonType& j, typename BasicJsonType::number_int
} }
#if !JSON_DISABLE_ENUM_SERIALIZATION #if !JSON_DISABLE_ENUM_SERIALIZATION
template<typename BasicJsonType, typename EnumType, template<typename BasicJsonType, typename EnumType, enable_if_t<std::is_enum<EnumType>::value, int> = 0>
enable_if_t<std::is_enum<EnumType>::value, int> = 0>
inline void from_json(const BasicJsonType& j, EnumType& e) inline void from_json(const BasicJsonType& j, EnumType& e)
{ {
typename std::underlying_type<EnumType>::type val; typename std::underlying_type<EnumType>::type val;
@@ -147,8 +141,7 @@ inline void from_json(const BasicJsonType& j, EnumType& e)
#endif // JSON_DISABLE_ENUM_SERIALIZATION #endif // JSON_DISABLE_ENUM_SERIALIZATION
// forward_list doesn't have an insert method // forward_list doesn't have an insert method
template<typename BasicJsonType, typename T, typename Allocator, template<typename BasicJsonType, typename T, typename Allocator, enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l) inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l)
{ {
if (JSON_HEDLEY_UNLIKELY(!j.is_array())) if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
@@ -156,16 +149,13 @@ inline void from_json(const BasicJsonType& j, std::forward_list<T, Allocator>& l
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
} }
l.clear(); l.clear();
std::transform(j.rbegin(), j.rend(), std::transform(j.rbegin(), j.rend(), std::front_inserter(l), [](const BasicJsonType& i) {
std::front_inserter(l), [](const BasicJsonType & i)
{
return i.template get<T>(); return i.template get<T>();
}); });
} }
// valarray doesn't have an insert method // valarray doesn't have an insert method
template<typename BasicJsonType, typename T, template<typename BasicJsonType, typename T, enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
enable_if_t<is_getable<BasicJsonType, T>::value, int> = 0>
inline void from_json(const BasicJsonType& j, std::valarray<T>& l) inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
{ {
if (JSON_HEDLEY_UNLIKELY(!j.is_array())) if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
@@ -173,16 +163,14 @@ inline void from_json(const BasicJsonType& j, std::valarray<T>& l)
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
} }
l.resize(j.size()); l.resize(j.size());
std::transform(j.begin(), j.end(), std::begin(l), std::transform(j.begin(), j.end(), std::begin(l), [](const BasicJsonType& elem) {
[](const BasicJsonType & elem)
{
return elem.template get<T>(); return elem.template get<T>();
}); });
} }
template<typename BasicJsonType, typename T, std::size_t N> template<typename BasicJsonType, typename T, std::size_t N>
auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) auto from_json(const BasicJsonType& j, T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
-> decltype(j.template get<T>(), void()) -> decltype(j.template get<T>(), void())
{ {
for (std::size_t i = 0; i < N; ++i) for (std::size_t i = 0; i < N; ++i)
{ {
@@ -197,9 +185,8 @@ inline void from_json_array_impl(const BasicJsonType& j, typename BasicJsonType:
} }
template<typename BasicJsonType, typename T, std::size_t N> template<typename BasicJsonType, typename T, std::size_t N>
auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr, auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr, priority_tag<2> /*unused*/)
priority_tag<2> /*unused*/) -> decltype(j.template get<T>(), void())
-> decltype(j.template get<T>(), void())
{ {
for (std::size_t i = 0; i < N; ++i) for (std::size_t i = 0; i < N; ++i)
{ {
@@ -207,23 +194,17 @@ auto from_json_array_impl(const BasicJsonType& j, std::array<T, N>& arr,
} }
} }
template<typename BasicJsonType, typename ConstructibleArrayType, template<typename BasicJsonType, typename ConstructibleArrayType, enable_if_t<std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value, int> = 0>
enable_if_t<
std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
int> = 0>
auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/) auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<1> /*unused*/)
-> decltype( -> decltype(arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()),
arr.reserve(std::declval<typename ConstructibleArrayType::size_type>()), j.template get<typename ConstructibleArrayType::value_type>(),
j.template get<typename ConstructibleArrayType::value_type>(), void())
void())
{ {
using std::end; using std::end;
ConstructibleArrayType ret; ConstructibleArrayType ret;
ret.reserve(j.size()); ret.reserve(j.size());
std::transform(j.begin(), j.end(), std::transform(j.begin(), j.end(), std::inserter(ret, end(ret)), [](const BasicJsonType& i) {
std::inserter(ret, end(ret)), [](const BasicJsonType & i)
{
// get<BasicJsonType>() returns *this, this won't call a from_json // get<BasicJsonType>() returns *this, this won't call a from_json
// method when value_type is BasicJsonType // method when value_type is BasicJsonType
return i.template get<typename ConstructibleArrayType::value_type>(); return i.template get<typename ConstructibleArrayType::value_type>();
@@ -231,65 +212,56 @@ auto from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, p
arr = std::move(ret); arr = std::move(ret);
} }
template<typename BasicJsonType, typename ConstructibleArrayType, template<typename BasicJsonType, typename ConstructibleArrayType, enable_if_t<std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value, int> = 0>
enable_if_t< inline void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr, priority_tag<0> /*unused*/)
std::is_assignable<ConstructibleArrayType&, ConstructibleArrayType>::value,
int> = 0>
inline void from_json_array_impl(const BasicJsonType& j, ConstructibleArrayType& arr,
priority_tag<0> /*unused*/)
{ {
using std::end; using std::end;
ConstructibleArrayType ret; ConstructibleArrayType ret;
std::transform( std::transform(
j.begin(), j.end(), std::inserter(ret, end(ret)), j.begin(),
[](const BasicJsonType & i) j.end(),
{ std::inserter(ret, end(ret)),
// get<BasicJsonType>() returns *this, this won't call a from_json [](const BasicJsonType& i) {
// method when value_type is BasicJsonType // get<BasicJsonType>() returns *this, this won't call a from_json
return i.template get<typename ConstructibleArrayType::value_type>(); // method when value_type is BasicJsonType
}); return i.template get<typename ConstructibleArrayType::value_type>();
});
arr = std::move(ret); arr = std::move(ret);
} }
template < typename BasicJsonType, typename ConstructibleArrayType, template<typename BasicJsonType, typename ConstructibleArrayType, enable_if_t<is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value && !is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value && !is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value && !std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value && !is_basic_json<ConstructibleArrayType>::value, int> = 0>
enable_if_t <
is_constructible_array_type<BasicJsonType, ConstructibleArrayType>::value&&
!is_constructible_object_type<BasicJsonType, ConstructibleArrayType>::value&&
!is_constructible_string_type<BasicJsonType, ConstructibleArrayType>::value&&
!std::is_same<ConstructibleArrayType, typename BasicJsonType::binary_t>::value&&
!is_basic_json<ConstructibleArrayType>::value,
int > = 0 >
auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr) auto from_json(const BasicJsonType& j, ConstructibleArrayType& arr)
-> decltype(from_json_array_impl(j, arr, priority_tag<3> {}), -> decltype(from_json_array_impl(j, arr, priority_tag<3>{}),
j.template get<typename ConstructibleArrayType::value_type>(), j.template get<typename ConstructibleArrayType::value_type>(),
void()) void())
{ {
if (JSON_HEDLEY_UNLIKELY(!j.is_array())) if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{ {
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
} }
from_json_array_impl(j, arr, priority_tag<3> {}); from_json_array_impl(j, arr, priority_tag<3>{});
} }
template < typename BasicJsonType, typename T, std::size_t... Idx > template<typename BasicJsonType, typename T, std::size_t... Idx>
std::array<T, sizeof...(Idx)> from_json_inplace_array_impl(BasicJsonType&& j, std::array<T, sizeof...(Idx)> from_json_inplace_array_impl(BasicJsonType&& j,
identity_tag<std::array<T, sizeof...(Idx)>> /*unused*/, index_sequence<Idx...> /*unused*/) identity_tag<std::array<T, sizeof...(Idx)>> /*unused*/,
index_sequence<Idx...> /*unused*/)
{ {
return { { std::forward<BasicJsonType>(j).at(Idx).template get<T>()... } }; return {{std::forward<BasicJsonType>(j).at(Idx).template get<T>()...}};
} }
template < typename BasicJsonType, typename T, std::size_t N > template<typename BasicJsonType, typename T, std::size_t N>
auto from_json(BasicJsonType&& j, identity_tag<std::array<T, N>> tag) auto from_json(BasicJsonType&& j, identity_tag<std::array<T, N>> tag)
-> decltype(from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {})) -> decltype(from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N>{}))
{ {
if (JSON_HEDLEY_UNLIKELY(!j.is_array())) if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{ {
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
} }
return from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N> {}); return from_json_inplace_array_impl(std::forward<BasicJsonType>(j), tag, make_index_sequence<N>{});
} }
template<typename BasicJsonType> template<typename BasicJsonType>
@@ -303,8 +275,7 @@ inline void from_json(const BasicJsonType& j, typename BasicJsonType::binary_t&
bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>(); bin = *j.template get_ptr<const typename BasicJsonType::binary_t*>();
} }
template<typename BasicJsonType, typename ConstructibleObjectType, template<typename BasicJsonType, typename ConstructibleObjectType, enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
enable_if_t<is_constructible_object_type<BasicJsonType, ConstructibleObjectType>::value, int> = 0>
inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj) inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
{ {
if (JSON_HEDLEY_UNLIKELY(!j.is_object())) if (JSON_HEDLEY_UNLIKELY(!j.is_object()))
@@ -316,12 +287,12 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>(); const auto* inner_object = j.template get_ptr<const typename BasicJsonType::object_t*>();
using value_type = typename ConstructibleObjectType::value_type; using value_type = typename ConstructibleObjectType::value_type;
std::transform( std::transform(
inner_object->begin(), inner_object->end(), inner_object->begin(),
inner_object->end(),
std::inserter(ret, ret.begin()), std::inserter(ret, ret.begin()),
[](typename BasicJsonType::object_t::value_type const & p) [](typename BasicJsonType::object_t::value_type const& p) {
{ return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>());
return value_type(p.first, p.second.template get<typename ConstructibleObjectType::mapped_type>()); });
});
obj = std::move(ret); obj = std::move(ret);
} }
@@ -329,14 +300,7 @@ inline void from_json(const BasicJsonType& j, ConstructibleObjectType& obj)
// (BooleanType, etc..); note: Is it really necessary to provide explicit // (BooleanType, etc..); note: Is it really necessary to provide explicit
// overloads for boolean_t etc. in case of a custom BooleanType which is not // overloads for boolean_t etc. in case of a custom BooleanType which is not
// an arithmetic type? // an arithmetic type?
template < typename BasicJsonType, typename ArithmeticType, template<typename BasicJsonType, typename ArithmeticType, enable_if_t<std::is_arithmetic<ArithmeticType>::value && !std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value && !std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value && !std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value && !std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value, int> = 0>
enable_if_t <
std::is_arithmetic<ArithmeticType>::value&&
!std::is_same<ArithmeticType, typename BasicJsonType::number_unsigned_t>::value&&
!std::is_same<ArithmeticType, typename BasicJsonType::number_integer_t>::value&&
!std::is_same<ArithmeticType, typename BasicJsonType::number_float_t>::value&&
!std::is_same<ArithmeticType, typename BasicJsonType::boolean_t>::value,
int > = 0 >
inline void from_json(const BasicJsonType& j, ArithmeticType& val) inline void from_json(const BasicJsonType& j, ArithmeticType& val)
{ {
switch (static_cast<value_t>(j)) switch (static_cast<value_t>(j))
@@ -379,7 +343,7 @@ std::tuple<Args...> from_json_tuple_impl_base(BasicJsonType&& j, index_sequence<
return std::make_tuple(std::forward<BasicJsonType>(j).at(Idx).template get<Args>()...); return std::make_tuple(std::forward<BasicJsonType>(j).at(Idx).template get<Args>()...);
} }
template < typename BasicJsonType, class A1, class A2 > template<typename BasicJsonType, class A1, class A2>
std::pair<A1, A2> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::pair<A1, A2>> /*unused*/, priority_tag<0> /*unused*/) std::pair<A1, A2> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::pair<A1, A2>> /*unused*/, priority_tag<0> /*unused*/)
{ {
return {std::forward<BasicJsonType>(j).at(0).template get<A1>(), return {std::forward<BasicJsonType>(j).at(0).template get<A1>(),
@@ -389,36 +353,34 @@ std::pair<A1, A2> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::pair
template<typename BasicJsonType, typename A1, typename A2> template<typename BasicJsonType, typename A1, typename A2>
inline void from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priority_tag<1> /*unused*/) inline void from_json_tuple_impl(BasicJsonType&& j, std::pair<A1, A2>& p, priority_tag<1> /*unused*/)
{ {
p = from_json_tuple_impl(std::forward<BasicJsonType>(j), identity_tag<std::pair<A1, A2>> {}, priority_tag<0> {}); p = from_json_tuple_impl(std::forward<BasicJsonType>(j), identity_tag<std::pair<A1, A2>>{}, priority_tag<0>{});
} }
template<typename BasicJsonType, typename... Args> template<typename BasicJsonType, typename... Args>
std::tuple<Args...> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/) std::tuple<Args...> from_json_tuple_impl(BasicJsonType&& j, identity_tag<std::tuple<Args...>> /*unused*/, priority_tag<2> /*unused*/)
{ {
return from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {}); return from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...>{});
} }
template<typename BasicJsonType, typename... Args> template<typename BasicJsonType, typename... Args>
inline void from_json_tuple_impl(BasicJsonType&& j, std::tuple<Args...>& t, priority_tag<3> /*unused*/) inline void from_json_tuple_impl(BasicJsonType&& j, std::tuple<Args...>& t, priority_tag<3> /*unused*/)
{ {
t = from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...> {}); t = from_json_tuple_impl_base<BasicJsonType, Args...>(std::forward<BasicJsonType>(j), index_sequence_for<Args...>{});
} }
template<typename BasicJsonType, typename TupleRelated> template<typename BasicJsonType, typename TupleRelated>
auto from_json(BasicJsonType&& j, TupleRelated&& t) auto from_json(BasicJsonType&& j, TupleRelated&& t)
-> decltype(from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {})) -> decltype(from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3>{}))
{ {
if (JSON_HEDLEY_UNLIKELY(!j.is_array())) if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
{ {
JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j)); JSON_THROW(type_error::create(302, concat("type must be array, but is ", j.type_name()), &j));
} }
return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3> {}); return from_json_tuple_impl(std::forward<BasicJsonType>(j), std::forward<TupleRelated>(t), priority_tag<3>{});
} }
template < typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, template<typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator, typename = enable_if_t<!std::is_constructible<typename BasicJsonType::string_t, Key>::value>>
typename = enable_if_t < !std::is_constructible <
typename BasicJsonType::string_t, Key >::value >>
inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m) inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
{ {
if (JSON_HEDLEY_UNLIKELY(!j.is_array())) if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
@@ -436,9 +398,7 @@ inline void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allo
} }
} }
template < typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, template<typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator, typename = enable_if_t<!std::is_constructible<typename BasicJsonType::string_t, Key>::value>>
typename = enable_if_t < !std::is_constructible <
typename BasicJsonType::string_t, Key >::value >>
inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m) inline void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
{ {
if (JSON_HEDLEY_UNLIKELY(!j.is_array())) if (JSON_HEDLEY_UNLIKELY(!j.is_array()))
@@ -472,8 +432,8 @@ struct from_json_fn
{ {
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
auto operator()(const BasicJsonType& j, T&& val) const auto operator()(const BasicJsonType& j, T&& val) const
noexcept(noexcept(from_json(j, std::forward<T>(val)))) noexcept(noexcept(from_json(j, std::forward<T>(val))))
-> decltype(from_json(j, std::forward<T>(val))) -> decltype(from_json(j, std::forward<T>(val)))
{ {
return from_json(j, std::forward<T>(val)); return from_json(j, std::forward<T>(val));
} }
@@ -485,10 +445,10 @@ struct from_json_fn
/// namespace to hold default `from_json` function /// namespace to hold default `from_json` function
/// to see why this is required: /// to see why this is required:
/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html /// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)
{ {
#endif #endif
JSON_INLINE_VARIABLE constexpr const auto& from_json = // NOLINT(misc-definitions-in-headers) JSON_INLINE_VARIABLE constexpr const auto& from_json = // NOLINT(misc-definitions-in-headers)
detail::static_const<detail::from_json_fn>::value; detail::static_const<detail::from_json_fn>::value;
#ifndef JSON_HAS_CPP_17 #ifndef JSON_HAS_CPP_17
} // namespace } // namespace
+142 -148
View File
@@ -9,18 +9,17 @@
#pragma once #pragma once
#include <array> // array #include <array> // array
#include <cmath> // signbit, isfinite #include <cmath> // signbit, isfinite
#include <cstdint> // intN_t, uintN_t #include <cstdint> // intN_t, uintN_t
#include <cstring> // memcpy, memmove #include <cstring> // memcpy, memmove
#include <limits> // numeric_limits #include <limits> // numeric_limits
#include <type_traits> // conditional #include <type_traits> // conditional
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
/*! /*!
@brief implements the Grisu2 algorithm for binary to decimal floating-point @brief implements the Grisu2 algorithm for binary to decimal floating-point
@@ -41,8 +40,7 @@ For a detailed description of the algorithm see:
Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language Proceedings of the ACM SIGPLAN 1996 Conference on Programming Language
Design and Implementation, PLDI 1996 Design and Implementation, PLDI 1996
*/ */
namespace dtoa_impl namespace dtoa_impl {
{
template<typename Target, typename Source> template<typename Target, typename Source>
Target reinterpret_bits(const Source source) Target reinterpret_bits(const Source source)
@@ -54,14 +52,17 @@ Target reinterpret_bits(const Source source)
return target; return target;
} }
struct diyfp // f * 2^e struct diyfp // f * 2^e
{ {
static constexpr int kPrecision = 64; // = q static constexpr int kPrecision = 64; // = q
std::uint64_t f = 0; std::uint64_t f = 0;
int e = 0; int e = 0;
constexpr diyfp(std::uint64_t f_, int e_) noexcept : f(f_), e(e_) {} constexpr diyfp(std::uint64_t f_, int e_) noexcept
: f(f_)
, e(e_)
{}
/*! /*!
@brief returns x - y @brief returns x - y
@@ -133,7 +134,7 @@ struct diyfp // f * 2^e
// Effectively we only need to add the highest bit in p_lo to p_hi (and // Effectively we only need to add the highest bit in p_lo to p_hi (and
// Q_hi + 1 does not overflow). // Q_hi + 1 does not overflow).
Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up
const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u); const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u);
@@ -201,12 +202,12 @@ boundaries compute_boundaries(FloatType value)
static_assert(std::numeric_limits<FloatType>::is_iec559, static_assert(std::numeric_limits<FloatType>::is_iec559,
"internal error: dtoa_short requires an IEEE-754 floating-point implementation"); "internal error: dtoa_short requires an IEEE-754 floating-point implementation");
constexpr int kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit) constexpr int kPrecision = std::numeric_limits<FloatType>::digits; // = p (includes the hidden bit)
constexpr int kBias = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1); constexpr int kBias = std::numeric_limits<FloatType>::max_exponent - 1 + (kPrecision - 1);
constexpr int kMinExp = 1 - kBias; constexpr int kMinExp = 1 - kBias;
constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1) constexpr std::uint64_t kHiddenBit = std::uint64_t{1} << (kPrecision - 1); // = 2^(p-1)
using bits_type = typename std::conditional<kPrecision == 24, std::uint32_t, std::uint64_t >::type; using bits_type = typename std::conditional<kPrecision == 24, std::uint32_t, std::uint64_t>::type;
const auto bits = static_cast<std::uint64_t>(reinterpret_bits<bits_type>(value)); const auto bits = static_cast<std::uint64_t>(reinterpret_bits<bits_type>(value));
const std::uint64_t E = bits >> (kPrecision - 1); const std::uint64_t E = bits >> (kPrecision - 1);
@@ -214,8 +215,8 @@ boundaries compute_boundaries(FloatType value)
const bool is_denormal = E == 0; const bool is_denormal = E == 0;
const diyfp v = is_denormal const diyfp v = is_denormal
? diyfp(F, kMinExp) ? diyfp(F, kMinExp)
: diyfp(F + kHiddenBit, static_cast<int>(E) - kBias); : diyfp(F + kHiddenBit, static_cast<int>(E) - kBias);
// Compute the boundaries m- and m+ of the floating-point value // Compute the boundaries m- and m+ of the floating-point value
// v = f * 2^e. // v = f * 2^e.
@@ -241,8 +242,8 @@ boundaries compute_boundaries(FloatType value)
const bool lower_boundary_is_closer = F == 0 && E > 1; const bool lower_boundary_is_closer = F == 0 && E > 1;
const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1); const diyfp m_plus = diyfp(2 * v.f + 1, v.e - 1);
const diyfp m_minus = lower_boundary_is_closer const diyfp m_minus = lower_boundary_is_closer
? diyfp(4 * v.f - 1, v.e - 2) // (B) ? diyfp(4 * v.f - 1, v.e - 2) // (B)
: diyfp(2 * v.f - 1, v.e - 1); // (A) : diyfp(2 * v.f - 1, v.e - 1); // (A)
// Determine the normalized w+ = m+. // Determine the normalized w+ = m+.
const diyfp w_plus = diyfp::normalize(m_plus); const diyfp w_plus = diyfp::normalize(m_plus);
@@ -311,7 +312,7 @@ boundaries compute_boundaries(FloatType value)
constexpr int kAlpha = -60; constexpr int kAlpha = -60;
constexpr int kGamma = -32; constexpr int kGamma = -32;
struct cached_power // c = f * 2^e ~= 10^k struct cached_power // c = f * 2^e ~= 10^k
{ {
std::uint64_t f; std::uint64_t f;
int e; int e;
@@ -381,96 +382,95 @@ inline cached_power get_cached_power_for_binary_exponent(int e)
constexpr int kCachedPowersDecStep = 8; constexpr int kCachedPowersDecStep = 8;
static constexpr std::array<cached_power, 79> kCachedPowers = static constexpr std::array<cached_power, 79> kCachedPowers =
{
{ {
{ 0xAB70FE17C79AC6CA, -1060, -300 }, {
{ 0xFF77B1FCBEBCDC4F, -1034, -292 }, {0xAB70FE17C79AC6CA, -1060, -300},
{ 0xBE5691EF416BD60C, -1007, -284 }, {0xFF77B1FCBEBCDC4F, -1034, -292},
{ 0x8DD01FAD907FFC3C, -980, -276 }, {0xBE5691EF416BD60C, -1007, -284},
{ 0xD3515C2831559A83, -954, -268 }, {0x8DD01FAD907FFC3C, -980, -276},
{ 0x9D71AC8FADA6C9B5, -927, -260 }, {0xD3515C2831559A83, -954, -268},
{ 0xEA9C227723EE8BCB, -901, -252 }, {0x9D71AC8FADA6C9B5, -927, -260},
{ 0xAECC49914078536D, -874, -244 }, {0xEA9C227723EE8BCB, -901, -252},
{ 0x823C12795DB6CE57, -847, -236 }, {0xAECC49914078536D, -874, -244},
{ 0xC21094364DFB5637, -821, -228 }, {0x823C12795DB6CE57, -847, -236},
{ 0x9096EA6F3848984F, -794, -220 }, {0xC21094364DFB5637, -821, -228},
{ 0xD77485CB25823AC7, -768, -212 }, {0x9096EA6F3848984F, -794, -220},
{ 0xA086CFCD97BF97F4, -741, -204 }, {0xD77485CB25823AC7, -768, -212},
{ 0xEF340A98172AACE5, -715, -196 }, {0xA086CFCD97BF97F4, -741, -204},
{ 0xB23867FB2A35B28E, -688, -188 }, {0xEF340A98172AACE5, -715, -196},
{ 0x84C8D4DFD2C63F3B, -661, -180 }, {0xB23867FB2A35B28E, -688, -188},
{ 0xC5DD44271AD3CDBA, -635, -172 }, {0x84C8D4DFD2C63F3B, -661, -180},
{ 0x936B9FCEBB25C996, -608, -164 }, {0xC5DD44271AD3CDBA, -635, -172},
{ 0xDBAC6C247D62A584, -582, -156 }, {0x936B9FCEBB25C996, -608, -164},
{ 0xA3AB66580D5FDAF6, -555, -148 }, {0xDBAC6C247D62A584, -582, -156},
{ 0xF3E2F893DEC3F126, -529, -140 }, {0xA3AB66580D5FDAF6, -555, -148},
{ 0xB5B5ADA8AAFF80B8, -502, -132 }, {0xF3E2F893DEC3F126, -529, -140},
{ 0x87625F056C7C4A8B, -475, -124 }, {0xB5B5ADA8AAFF80B8, -502, -132},
{ 0xC9BCFF6034C13053, -449, -116 }, {0x87625F056C7C4A8B, -475, -124},
{ 0x964E858C91BA2655, -422, -108 }, {0xC9BCFF6034C13053, -449, -116},
{ 0xDFF9772470297EBD, -396, -100 }, {0x964E858C91BA2655, -422, -108},
{ 0xA6DFBD9FB8E5B88F, -369, -92 }, {0xDFF9772470297EBD, -396, -100},
{ 0xF8A95FCF88747D94, -343, -84 }, {0xA6DFBD9FB8E5B88F, -369, -92},
{ 0xB94470938FA89BCF, -316, -76 }, {0xF8A95FCF88747D94, -343, -84},
{ 0x8A08F0F8BF0F156B, -289, -68 }, {0xB94470938FA89BCF, -316, -76},
{ 0xCDB02555653131B6, -263, -60 }, {0x8A08F0F8BF0F156B, -289, -68},
{ 0x993FE2C6D07B7FAC, -236, -52 }, {0xCDB02555653131B6, -263, -60},
{ 0xE45C10C42A2B3B06, -210, -44 }, {0x993FE2C6D07B7FAC, -236, -52},
{ 0xAA242499697392D3, -183, -36 }, {0xE45C10C42A2B3B06, -210, -44},
{ 0xFD87B5F28300CA0E, -157, -28 }, {0xAA242499697392D3, -183, -36},
{ 0xBCE5086492111AEB, -130, -20 }, {0xFD87B5F28300CA0E, -157, -28},
{ 0x8CBCCC096F5088CC, -103, -12 }, {0xBCE5086492111AEB, -130, -20},
{ 0xD1B71758E219652C, -77, -4 }, {0x8CBCCC096F5088CC, -103, -12},
{ 0x9C40000000000000, -50, 4 }, {0xD1B71758E219652C, -77, -4},
{ 0xE8D4A51000000000, -24, 12 }, {0x9C40000000000000, -50, 4},
{ 0xAD78EBC5AC620000, 3, 20 }, {0xE8D4A51000000000, -24, 12},
{ 0x813F3978F8940984, 30, 28 }, {0xAD78EBC5AC620000, 3, 20},
{ 0xC097CE7BC90715B3, 56, 36 }, {0x813F3978F8940984, 30, 28},
{ 0x8F7E32CE7BEA5C70, 83, 44 }, {0xC097CE7BC90715B3, 56, 36},
{ 0xD5D238A4ABE98068, 109, 52 }, {0x8F7E32CE7BEA5C70, 83, 44},
{ 0x9F4F2726179A2245, 136, 60 }, {0xD5D238A4ABE98068, 109, 52},
{ 0xED63A231D4C4FB27, 162, 68 }, {0x9F4F2726179A2245, 136, 60},
{ 0xB0DE65388CC8ADA8, 189, 76 }, {0xED63A231D4C4FB27, 162, 68},
{ 0x83C7088E1AAB65DB, 216, 84 }, {0xB0DE65388CC8ADA8, 189, 76},
{ 0xC45D1DF942711D9A, 242, 92 }, {0x83C7088E1AAB65DB, 216, 84},
{ 0x924D692CA61BE758, 269, 100 }, {0xC45D1DF942711D9A, 242, 92},
{ 0xDA01EE641A708DEA, 295, 108 }, {0x924D692CA61BE758, 269, 100},
{ 0xA26DA3999AEF774A, 322, 116 }, {0xDA01EE641A708DEA, 295, 108},
{ 0xF209787BB47D6B85, 348, 124 }, {0xA26DA3999AEF774A, 322, 116},
{ 0xB454E4A179DD1877, 375, 132 }, {0xF209787BB47D6B85, 348, 124},
{ 0x865B86925B9BC5C2, 402, 140 }, {0xB454E4A179DD1877, 375, 132},
{ 0xC83553C5C8965D3D, 428, 148 }, {0x865B86925B9BC5C2, 402, 140},
{ 0x952AB45CFA97A0B3, 455, 156 }, {0xC83553C5C8965D3D, 428, 148},
{ 0xDE469FBD99A05FE3, 481, 164 }, {0x952AB45CFA97A0B3, 455, 156},
{ 0xA59BC234DB398C25, 508, 172 }, {0xDE469FBD99A05FE3, 481, 164},
{ 0xF6C69A72A3989F5C, 534, 180 }, {0xA59BC234DB398C25, 508, 172},
{ 0xB7DCBF5354E9BECE, 561, 188 }, {0xF6C69A72A3989F5C, 534, 180},
{ 0x88FCF317F22241E2, 588, 196 }, {0xB7DCBF5354E9BECE, 561, 188},
{ 0xCC20CE9BD35C78A5, 614, 204 }, {0x88FCF317F22241E2, 588, 196},
{ 0x98165AF37B2153DF, 641, 212 }, {0xCC20CE9BD35C78A5, 614, 204},
{ 0xE2A0B5DC971F303A, 667, 220 }, {0x98165AF37B2153DF, 641, 212},
{ 0xA8D9D1535CE3B396, 694, 228 }, {0xE2A0B5DC971F303A, 667, 220},
{ 0xFB9B7CD9A4A7443C, 720, 236 }, {0xA8D9D1535CE3B396, 694, 228},
{ 0xBB764C4CA7A44410, 747, 244 }, {0xFB9B7CD9A4A7443C, 720, 236},
{ 0x8BAB8EEFB6409C1A, 774, 252 }, {0xBB764C4CA7A44410, 747, 244},
{ 0xD01FEF10A657842C, 800, 260 }, {0x8BAB8EEFB6409C1A, 774, 252},
{ 0x9B10A4E5E9913129, 827, 268 }, {0xD01FEF10A657842C, 800, 260},
{ 0xE7109BFBA19C0C9D, 853, 276 }, {0x9B10A4E5E9913129, 827, 268},
{ 0xAC2820D9623BF429, 880, 284 }, {0xE7109BFBA19C0C9D, 853, 276},
{ 0x80444B5E7AA7CF85, 907, 292 }, {0xAC2820D9623BF429, 880, 284},
{ 0xBF21E44003ACDD2D, 933, 300 }, {0x80444B5E7AA7CF85, 907, 292},
{ 0x8E679C2F5E44FF8F, 960, 308 }, {0xBF21E44003ACDD2D, 933, 300},
{ 0xD433179D9C8CB841, 986, 316 }, {0x8E679C2F5E44FF8F, 960, 308},
{ 0x9E19DB92B4E31BA9, 1013, 324 }, {0xD433179D9C8CB841, 986, 316},
} {0x9E19DB92B4E31BA9, 1013, 324},
}; }};
// This computation gives exactly the same results for k as // This computation gives exactly the same results for k as
// k = ceil((kAlpha - e - 1) * 0.30102999566398114) // k = ceil((kAlpha - e - 1) * 0.30102999566398114)
// for |e| <= 1500, but doesn't require floating-point operations. // for |e| <= 1500, but doesn't require floating-point operations.
// NB: log_10(2) ~= 78913 / 2^18 // NB: log_10(2) ~= 78913 / 2^18
JSON_ASSERT(e >= -1500); JSON_ASSERT(e >= -1500);
JSON_ASSERT(e <= 1500); JSON_ASSERT(e <= 1500);
const int f = kAlpha - e - 1; const int f = kAlpha - e - 1;
const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0); const int k = (f * 78913) / (1 << 18) + static_cast<int>(f > 0);
@@ -501,50 +501,49 @@ inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10)
if (n >= 100000000) if (n >= 100000000)
{ {
pow10 = 100000000; pow10 = 100000000;
return 9; return 9;
} }
if (n >= 10000000) if (n >= 10000000)
{ {
pow10 = 10000000; pow10 = 10000000;
return 8; return 8;
} }
if (n >= 1000000) if (n >= 1000000)
{ {
pow10 = 1000000; pow10 = 1000000;
return 7; return 7;
} }
if (n >= 100000) if (n >= 100000)
{ {
pow10 = 100000; pow10 = 100000;
return 6; return 6;
} }
if (n >= 10000) if (n >= 10000)
{ {
pow10 = 10000; pow10 = 10000;
return 5; return 5;
} }
if (n >= 1000) if (n >= 1000)
{ {
pow10 = 1000; pow10 = 1000;
return 4; return 4;
} }
if (n >= 100) if (n >= 100)
{ {
pow10 = 100; pow10 = 100;
return 3; return 3;
} }
if (n >= 10) if (n >= 10)
{ {
pow10 = 10; pow10 = 10;
return 2; return 2;
} }
pow10 = 1; pow10 = 1;
return 1; return 1;
} }
inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta, std::uint64_t rest, std::uint64_t ten_k)
std::uint64_t rest, std::uint64_t ten_k)
{ {
JSON_ASSERT(len >= 1); JSON_ASSERT(len >= 1);
JSON_ASSERT(dist <= delta); JSON_ASSERT(dist <= delta);
@@ -570,9 +569,7 @@ inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t d
// The tests are written in this order to avoid overflow in unsigned // The tests are written in this order to avoid overflow in unsigned
// integer arithmetic. // integer arithmetic.
while (rest < dist while (rest < dist && delta - rest >= ten_k && (rest + ten_k < dist || dist - rest > rest + ten_k - dist))
&& delta - rest >= ten_k
&& (rest + ten_k < dist || dist - rest > rest + ten_k - dist))
{ {
JSON_ASSERT(buf[len - 1] != '0'); JSON_ASSERT(buf[len - 1] != '0');
buf[len - 1]--; buf[len - 1]--;
@@ -584,8 +581,7 @@ inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t d
Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+. Generates V = buffer * 10^decimal_exponent, such that M- <= V <= M+.
M- and M+ must be normalized and share the same exponent -60 <= e <= -32. M- and M+ must be normalized and share the same exponent -60 <= e <= -32.
*/ */
inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent, diyfp M_minus, diyfp w, diyfp M_plus)
diyfp M_minus, diyfp w, diyfp M_plus)
{ {
static_assert(kAlpha >= -60, "internal error"); static_assert(kAlpha >= -60, "internal error");
static_assert(kGamma <= -32, "internal error"); static_assert(kGamma <= -32, "internal error");
@@ -605,8 +601,8 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
JSON_ASSERT(M_plus.e >= kAlpha); JSON_ASSERT(M_plus.e >= kAlpha);
JSON_ASSERT(M_plus.e <= kGamma); JSON_ASSERT(M_plus.e <= kGamma);
std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e) std::uint64_t delta = diyfp::sub(M_plus, M_minus).f; // (significand of (M+ - M-), implicit exponent is e)
std::uint64_t dist = diyfp::sub(M_plus, w ).f; // (significand of (M+ - w ), implicit exponent is e) std::uint64_t dist = diyfp::sub(M_plus, w).f; // (significand of (M+ - w ), implicit exponent is e)
// Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0): // Split M+ = f * 2^e into two parts p1 and p2 (note: e < 0):
// //
@@ -617,8 +613,8 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e); const diyfp one(std::uint64_t{1} << -M_plus.e, M_plus.e);
auto p1 = static_cast<std::uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.) auto p1 = static_cast<std::uint32_t>(M_plus.f >> -one.e); // p1 = f div 2^-e (Since -e >= 32, p1 fits into a 32-bit int.)
std::uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e std::uint64_t p2 = M_plus.f & (one.f - 1); // p2 = f mod 2^-e
// 1) // 1)
// //
@@ -661,7 +657,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)
// //
JSON_ASSERT(d <= 9); JSON_ASSERT(d <= 9);
buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
// //
// M+ = buffer * 10^(n-1) + (r + p2 * 2^e) // M+ = buffer * 10^(n-1) + (r + p2 * 2^e)
// //
@@ -760,15 +756,15 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// //
JSON_ASSERT(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10); JSON_ASSERT(p2 <= (std::numeric_limits<std::uint64_t>::max)() / 10);
p2 *= 10; p2 *= 10;
const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e const std::uint64_t d = p2 >> -one.e; // d = (10 * p2) div 2^-e
const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e const std::uint64_t r = p2 & (one.f - 1); // r = (10 * p2) mod 2^-e
// //
// M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e // M+ = buffer * 10^-m + 10^-m * (1/10 * (d * 2^-e + r) * 2^e
// = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e)) // = buffer * 10^-m + 10^-m * (1/10 * (d + r * 2^e))
// = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e // = (buffer * 10 + d) * 10^(-m-1) + 10^(-m-1) * r * 2^e
// //
JSON_ASSERT(d <= 9); JSON_ASSERT(d <= 9);
buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d buffer[length++] = static_cast<char>('0' + d); // buffer := buffer * 10 + d
// //
// M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e // M+ = buffer * 10^(-m-1) + 10^(-m-1) * r * 2^e
// //
@@ -784,7 +780,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// p2 * 2^e <= 10^m * delta * 2^e // p2 * 2^e <= 10^m * delta * 2^e
// p2 <= 10^m * delta // p2 <= 10^m * delta
delta *= 10; delta *= 10;
dist *= 10; dist *= 10;
if (p2 <= delta) if (p2 <= delta)
{ {
break; break;
@@ -825,8 +821,7 @@ len is the length of the buffer (number of decimal digits)
The buffer must be large enough, i.e. >= max_digits10. The buffer must be large enough, i.e. >= max_digits10.
*/ */
JSON_HEDLEY_NON_NULL(1) JSON_HEDLEY_NON_NULL(1)
inline void grisu2(char* buf, int& len, int& decimal_exponent, inline void grisu2(char* buf, int& len, int& decimal_exponent, diyfp m_minus, diyfp v, diyfp m_plus)
diyfp m_minus, diyfp v, diyfp m_plus)
{ {
JSON_ASSERT(m_plus.e == m_minus.e); JSON_ASSERT(m_plus.e == m_minus.e);
JSON_ASSERT(m_plus.e == v.e); JSON_ASSERT(m_plus.e == v.e);
@@ -842,12 +837,12 @@ inline void grisu2(char* buf, int& len, int& decimal_exponent,
const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e); const cached_power cached = get_cached_power_for_binary_exponent(m_plus.e);
const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k const diyfp c_minus_k(cached.f, cached.e); // = c ~= 10^-k
// The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma] // The exponent of the products is = v.e + c_minus_k.e + q and is in the range [alpha,gamma]
const diyfp w = diyfp::mul(v, c_minus_k); const diyfp w = diyfp::mul(v, c_minus_k);
const diyfp w_minus = diyfp::mul(m_minus, c_minus_k); const diyfp w_minus = diyfp::mul(m_minus, c_minus_k);
const diyfp w_plus = diyfp::mul(m_plus, c_minus_k); const diyfp w_plus = diyfp::mul(m_plus, c_minus_k);
// ----(---+---)---------------(---+---)---------------(---+---)---- // ----(---+---)---------------(---+---)---------------(---+---)----
// w- w w+ // w- w w+
@@ -871,9 +866,9 @@ inline void grisu2(char* buf, int& len, int& decimal_exponent,
// Note that this does not mean that Grisu2 always generates the shortest // Note that this does not mean that Grisu2 always generates the shortest
// possible number in the interval (m-, m+). // possible number in the interval (m-, m+).
const diyfp M_minus(w_minus.f + 1, w_minus.e); const diyfp M_minus(w_minus.f + 1, w_minus.e);
const diyfp M_plus (w_plus.f - 1, w_plus.e ); const diyfp M_plus(w_plus.f - 1, w_plus.e);
decimal_exponent = -cached.k; // = -(-k) = k decimal_exponent = -cached.k; // = -(-k) = k
grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus); grisu2_digit_gen(buf, len, decimal_exponent, M_minus, w, M_plus);
} }
@@ -909,7 +904,7 @@ void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
// NB: If the neighbors are computed for single-precision numbers, there is a single float // NB: If the neighbors are computed for single-precision numbers, there is a single float
// (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision // (7.0385307e-26f) which can't be recovered using strtod. The resulting double precision
// value is off by 1 ulp. // value is off by 1 ulp.
#if 0 // NOLINT(readability-avoid-unconditional-preprocessor-if) #if 0 // NOLINT(readability-avoid-unconditional-preprocessor-if)
const boundaries w = compute_boundaries(static_cast<double>(value)); const boundaries w = compute_boundaries(static_cast<double>(value));
#else #else
const boundaries w = compute_boundaries(value); const boundaries w = compute_boundaries(value);
@@ -928,7 +923,7 @@ JSON_HEDLEY_RETURNS_NON_NULL
inline char* append_exponent(char* buf, int e) inline char* append_exponent(char* buf, int e)
{ {
JSON_ASSERT(e > -1000); JSON_ASSERT(e > -1000);
JSON_ASSERT(e < 1000); JSON_ASSERT(e < 1000);
if (e < 0) if (e < 0)
{ {
@@ -977,8 +972,7 @@ notation. Otherwise it will be printed in exponential notation.
*/ */
JSON_HEDLEY_NON_NULL(1) JSON_HEDLEY_NON_NULL(1)
JSON_HEDLEY_RETURNS_NON_NULL JSON_HEDLEY_RETURNS_NON_NULL
inline char* format_buffer(char* buf, int len, int decimal_exponent, inline char* format_buffer(char* buf, int len, int decimal_exponent, int min_exp, int max_exp)
int min_exp, int max_exp)
{ {
JSON_ASSERT(min_exp < 0); JSON_ASSERT(min_exp < 0);
JSON_ASSERT(max_exp > 0); JSON_ASSERT(max_exp > 0);
@@ -1062,9 +1056,9 @@ format. Returns an iterator pointing past-the-end of the decimal representation.
template<typename FloatType> template<typename FloatType>
JSON_HEDLEY_NON_NULL(1, 2) JSON_HEDLEY_NON_NULL(1, 2)
JSON_HEDLEY_RETURNS_NON_NULL JSON_HEDLEY_RETURNS_NON_NULL
char* to_chars(char* first, const char* last, FloatType value) char* to_chars(char* first, const char* last, FloatType value)
{ {
static_cast<void>(last); // maybe unused - fix warning static_cast<void>(last); // maybe unused - fix warning
JSON_ASSERT(std::isfinite(value)); JSON_ASSERT(std::isfinite(value));
// Use signbit(value) instead of (value < 0) since signbit works for -0. // Use signbit(value) instead of (value < 0) since signbit works for -0.
@@ -1075,10 +1069,10 @@ char* to_chars(char* first, const char* last, FloatType value)
} }
#ifdef __GNUC__ #ifdef __GNUC__
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal" #pragma GCC diagnostic ignored "-Wfloat-equal"
#endif #endif
if (value == 0) // +-0 if (value == 0) // +-0
{ {
*first++ = '0'; *first++ = '0';
// Make it look like a floating-point number (#362, #378) // Make it look like a floating-point number (#362, #378)
@@ -1087,7 +1081,7 @@ char* to_chars(char* first, const char* last, FloatType value)
return first; return first;
} }
#ifdef __GNUC__ #ifdef __GNUC__
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10); JSON_ASSERT(last - first >= std::numeric_limits<FloatType>::max_digits10);
+43 -70
View File
@@ -8,14 +8,14 @@
#pragma once #pragma once
#include <algorithm> // copy #include <algorithm> // copy
#include <iterator> // begin, end #include <iterator> // begin, end
#include <string> // string #include <string> // string
#include <tuple> // tuple, get #include <tuple> // tuple, get
#include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type #include <type_traits> // is_same, is_constructible, is_floating_point, is_enum, underlying_type
#include <utility> // move, forward, declval, pair #include <utility> // move, forward, declval, pair
#include <valarray> // valarray #include <valarray> // valarray
#include <vector> // vector #include <vector> // vector
#include <nlohmann/detail/iterators/iteration_proxy.hpp> #include <nlohmann/detail/iterators/iteration_proxy.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
@@ -25,8 +25,7 @@
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
////////////////// //////////////////
// constructors // // constructors //
@@ -39,7 +38,8 @@ namespace detail
* https://github.com/nlohmann/json/issues/2865 for more information. * https://github.com/nlohmann/json/issues/2865 for more information.
*/ */
template<value_t> struct external_constructor; template<value_t>
struct external_constructor;
template<> template<>
struct external_constructor<value_t::boolean> struct external_constructor<value_t::boolean>
@@ -75,9 +75,7 @@ struct external_constructor<value_t::string>
j.assert_invariant(); j.assert_invariant();
} }
template < typename BasicJsonType, typename CompatibleStringType, template<typename BasicJsonType, typename CompatibleStringType, enable_if_t<!std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value, int> = 0>
enable_if_t < !std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
int > = 0 >
static void construct(BasicJsonType& j, const CompatibleStringType& str) static void construct(BasicJsonType& j, const CompatibleStringType& str)
{ {
j.m_data.m_value.destroy(j.m_data.m_type); j.m_data.m_value.destroy(j.m_data.m_type);
@@ -171,9 +169,7 @@ struct external_constructor<value_t::array>
j.assert_invariant(); j.assert_invariant();
} }
template < typename BasicJsonType, typename CompatibleArrayType, template<typename BasicJsonType, typename CompatibleArrayType, enable_if_t<!std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value, int> = 0>
enable_if_t < !std::is_same<CompatibleArrayType, typename BasicJsonType::array_t>::value,
int > = 0 >
static void construct(BasicJsonType& j, const CompatibleArrayType& arr) static void construct(BasicJsonType& j, const CompatibleArrayType& arr)
{ {
using std::begin; using std::begin;
@@ -201,8 +197,7 @@ struct external_constructor<value_t::array>
j.assert_invariant(); j.assert_invariant();
} }
template<typename BasicJsonType, typename T, template<typename BasicJsonType, typename T, enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
static void construct(BasicJsonType& j, const std::valarray<T>& arr) static void construct(BasicJsonType& j, const std::valarray<T>& arr)
{ {
j.m_data.m_value.destroy(j.m_data.m_type); j.m_data.m_value.destroy(j.m_data.m_type);
@@ -241,8 +236,7 @@ struct external_constructor<value_t::object>
j.assert_invariant(); j.assert_invariant();
} }
template < typename BasicJsonType, typename CompatibleObjectType, template<typename BasicJsonType, typename CompatibleObjectType, enable_if_t<!std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int> = 0>
enable_if_t < !std::is_same<CompatibleObjectType, typename BasicJsonType::object_t>::value, int > = 0 >
static void construct(BasicJsonType& j, const CompatibleObjectType& obj) static void construct(BasicJsonType& j, const CompatibleObjectType& obj)
{ {
using std::begin; using std::begin;
@@ -260,28 +254,19 @@ struct external_constructor<value_t::object>
// to_json // // to_json //
///////////// /////////////
template<typename BasicJsonType, typename T, template<typename BasicJsonType, typename T, enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>
enable_if_t<std::is_same<T, typename BasicJsonType::boolean_t>::value, int> = 0>
inline void to_json(BasicJsonType& j, T b) noexcept inline void to_json(BasicJsonType& j, T b) noexcept
{ {
external_constructor<value_t::boolean>::construct(j, b); external_constructor<value_t::boolean>::construct(j, b);
} }
template < typename BasicJsonType, typename BoolRef, template<typename BasicJsonType, typename BoolRef, enable_if_t<((std::is_same<std::vector<bool>::reference, BoolRef>::value && !std::is_same<std::vector<bool>::reference, typename BasicJsonType::boolean_t&>::value) || (std::is_same<std::vector<bool>::const_reference, BoolRef>::value && !std::is_same<detail::uncvref_t<std::vector<bool>::const_reference>, typename BasicJsonType::boolean_t>::value)) && std::is_convertible<const BoolRef&, typename BasicJsonType::boolean_t>::value, int> = 0>
enable_if_t <
((std::is_same<std::vector<bool>::reference, BoolRef>::value
&& !std::is_same <std::vector<bool>::reference, typename BasicJsonType::boolean_t&>::value)
|| (std::is_same<std::vector<bool>::const_reference, BoolRef>::value
&& !std::is_same <detail::uncvref_t<std::vector<bool>::const_reference>,
typename BasicJsonType::boolean_t >::value))
&& std::is_convertible<const BoolRef&, typename BasicJsonType::boolean_t>::value, int > = 0 >
inline void to_json(BasicJsonType& j, const BoolRef& b) noexcept inline void to_json(BasicJsonType& j, const BoolRef& b) noexcept
{ {
external_constructor<value_t::boolean>::construct(j, static_cast<typename BasicJsonType::boolean_t>(b)); external_constructor<value_t::boolean>::construct(j, static_cast<typename BasicJsonType::boolean_t>(b));
} }
template<typename BasicJsonType, typename CompatibleString, template<typename BasicJsonType, typename CompatibleString, enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>
enable_if_t<std::is_constructible<typename BasicJsonType::string_t, CompatibleString>::value, int> = 0>
inline void to_json(BasicJsonType& j, const CompatibleString& s) inline void to_json(BasicJsonType& j, const CompatibleString& s)
{ {
external_constructor<value_t::string>::construct(j, s); external_constructor<value_t::string>::construct(j, s);
@@ -293,30 +278,26 @@ inline void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s)
external_constructor<value_t::string>::construct(j, std::move(s)); external_constructor<value_t::string>::construct(j, std::move(s));
} }
template<typename BasicJsonType, typename FloatType, template<typename BasicJsonType, typename FloatType, enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
enable_if_t<std::is_floating_point<FloatType>::value, int> = 0>
inline void to_json(BasicJsonType& j, FloatType val) noexcept inline void to_json(BasicJsonType& j, FloatType val) noexcept
{ {
external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val)); external_constructor<value_t::number_float>::construct(j, static_cast<typename BasicJsonType::number_float_t>(val));
} }
template<typename BasicJsonType, typename CompatibleNumberUnsignedType, template<typename BasicJsonType, typename CompatibleNumberUnsignedType, enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>
enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_unsigned_t, CompatibleNumberUnsignedType>::value, int> = 0>
inline void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept inline void to_json(BasicJsonType& j, CompatibleNumberUnsignedType val) noexcept
{ {
external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val)); external_constructor<value_t::number_unsigned>::construct(j, static_cast<typename BasicJsonType::number_unsigned_t>(val));
} }
template<typename BasicJsonType, typename CompatibleNumberIntegerType, template<typename BasicJsonType, typename CompatibleNumberIntegerType, enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>
enable_if_t<is_compatible_integer_type<typename BasicJsonType::number_integer_t, CompatibleNumberIntegerType>::value, int> = 0>
inline void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept inline void to_json(BasicJsonType& j, CompatibleNumberIntegerType val) noexcept
{ {
external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val)); external_constructor<value_t::number_integer>::construct(j, static_cast<typename BasicJsonType::number_integer_t>(val));
} }
#if !JSON_DISABLE_ENUM_SERIALIZATION #if !JSON_DISABLE_ENUM_SERIALIZATION
template<typename BasicJsonType, typename EnumType, template<typename BasicJsonType, typename EnumType, enable_if_t<std::is_enum<EnumType>::value, int> = 0>
enable_if_t<std::is_enum<EnumType>::value, int> = 0>
inline void to_json(BasicJsonType& j, EnumType e) noexcept inline void to_json(BasicJsonType& j, EnumType e) noexcept
{ {
using underlying_type = typename std::underlying_type<EnumType>::type; using underlying_type = typename std::underlying_type<EnumType>::type;
@@ -330,14 +311,7 @@ inline void to_json(BasicJsonType& j, const std::vector<bool>& e)
external_constructor<value_t::array>::construct(j, e); external_constructor<value_t::array>::construct(j, e);
} }
template < typename BasicJsonType, typename CompatibleArrayType, template<typename BasicJsonType, typename CompatibleArrayType, enable_if_t<is_compatible_array_type<BasicJsonType, CompatibleArrayType>::value && !is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value && !is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value && !std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value && !is_basic_json<CompatibleArrayType>::value, int> = 0>
enable_if_t < is_compatible_array_type<BasicJsonType,
CompatibleArrayType>::value&&
!is_compatible_object_type<BasicJsonType, CompatibleArrayType>::value&&
!is_compatible_string_type<BasicJsonType, CompatibleArrayType>::value&&
!std::is_same<typename BasicJsonType::binary_t, CompatibleArrayType>::value&&
!is_basic_json<CompatibleArrayType>::value,
int > = 0 >
inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr) inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
{ {
external_constructor<value_t::array>::construct(j, arr); external_constructor<value_t::array>::construct(j, arr);
@@ -349,8 +323,7 @@ inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bi
external_constructor<value_t::binary>::construct(j, bin); external_constructor<value_t::binary>::construct(j, bin);
} }
template<typename BasicJsonType, typename T, template<typename BasicJsonType, typename T, enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
inline void to_json(BasicJsonType& j, const std::valarray<T>& arr) inline void to_json(BasicJsonType& j, const std::valarray<T>& arr)
{ {
external_constructor<value_t::array>::construct(j, std::move(arr)); external_constructor<value_t::array>::construct(j, std::move(arr));
@@ -362,8 +335,7 @@ inline void to_json(BasicJsonType& j, typename BasicJsonType::array_t&& arr)
external_constructor<value_t::array>::construct(j, std::move(arr)); external_constructor<value_t::array>::construct(j, std::move(arr));
} }
template < typename BasicJsonType, typename CompatibleObjectType, template<typename BasicJsonType, typename CompatibleObjectType, enable_if_t<is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value && !is_basic_json<CompatibleObjectType>::value, int> = 0>
enable_if_t < is_compatible_object_type<BasicJsonType, CompatibleObjectType>::value&& !is_basic_json<CompatibleObjectType>::value, int > = 0 >
inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj) inline void to_json(BasicJsonType& j, const CompatibleObjectType& obj)
{ {
external_constructor<value_t::object>::construct(j, obj); external_constructor<value_t::object>::construct(j, obj);
@@ -375,40 +347,41 @@ inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj)
external_constructor<value_t::object>::construct(j, std::move(obj)); external_constructor<value_t::object>::construct(j, std::move(obj));
} }
template < template<
typename BasicJsonType, typename T, std::size_t N, typename BasicJsonType,
enable_if_t < !std::is_constructible<typename BasicJsonType::string_t, typename T,
const T(&)[N]>::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) std::size_t N,
int > = 0 > enable_if_t<!std::is_constructible<typename BasicJsonType::string_t,
inline void to_json(BasicJsonType& j, const T(&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) const T (&)[N]>::value, // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
int> = 0>
inline void to_json(BasicJsonType& j, const T (&arr)[N]) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
{ {
external_constructor<value_t::array>::construct(j, arr); external_constructor<value_t::array>::construct(j, arr);
} }
template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible<BasicJsonType, T1>::value&& std::is_constructible<BasicJsonType, T2>::value, int > = 0 > template<typename BasicJsonType, typename T1, typename T2, enable_if_t<std::is_constructible<BasicJsonType, T1>::value && std::is_constructible<BasicJsonType, T2>::value, int> = 0>
inline void to_json(BasicJsonType& j, const std::pair<T1, T2>& p) inline void to_json(BasicJsonType& j, const std::pair<T1, T2>& p)
{ {
j = { p.first, p.second }; j = {p.first, p.second};
} }
// for https://github.com/nlohmann/json/pull/1134 // for https://github.com/nlohmann/json/pull/1134
template<typename BasicJsonType, typename T, template<typename BasicJsonType, typename T, enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>
enable_if_t<std::is_same<T, iteration_proxy_value<typename BasicJsonType::iterator>>::value, int> = 0>
inline void to_json(BasicJsonType& j, const T& b) inline void to_json(BasicJsonType& j, const T& b)
{ {
j = { {b.key(), b.value()} }; j = {{b.key(), b.value()}};
} }
template<typename BasicJsonType, typename Tuple, std::size_t... Idx> template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/) inline void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...> /*unused*/)
{ {
j = { std::get<Idx>(t)... }; j = {std::get<Idx>(t)...};
} }
template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0> template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int> = 0>
inline void to_json(BasicJsonType& j, const T& t) inline void to_json(BasicJsonType& j, const T& t)
{ {
to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {}); to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value>{});
} }
#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM #if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM
@@ -423,7 +396,7 @@ struct to_json_fn
{ {
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val)))) auto operator()(BasicJsonType& j, T&& val) const noexcept(noexcept(to_json(j, std::forward<T>(val))))
-> decltype(to_json(j, std::forward<T>(val)), void()) -> decltype(to_json(j, std::forward<T>(val)), void())
{ {
return to_json(j, std::forward<T>(val)); return to_json(j, std::forward<T>(val));
} }
@@ -434,10 +407,10 @@ struct to_json_fn
/// namespace to hold default `to_json` function /// namespace to hold default `to_json` function
/// to see why this is required: /// to see why this is required:
/// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html /// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4381.html
namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces) namespace // NOLINT(cert-dcl59-cpp,fuchsia-header-anon-namespaces,google-build-namespaces)
{ {
#endif #endif
JSON_INLINE_VARIABLE constexpr const auto& to_json = // NOLINT(misc-definitions-in-headers) JSON_INLINE_VARIABLE constexpr const auto& to_json = // NOLINT(misc-definitions-in-headers)
detail::static_const<detail::to_json_fn>::value; detail::static_const<detail::to_json_fn>::value;
#ifndef JSON_HAS_CPP_17 #ifndef JSON_HAS_CPP_17
} // namespace } // namespace
+42 -37
View File
@@ -8,26 +8,25 @@
#pragma once #pragma once
#include <cstddef> // nullptr_t #include <cstddef> // nullptr_t
#include <exception> // exception #include <exception> // exception
#if JSON_DIAGNOSTICS #if JSON_DIAGNOSTICS
#include <numeric> // accumulate #include <numeric> // accumulate
#endif #endif
#include <stdexcept> // runtime_error #include <stdexcept> // runtime_error
#include <string> // to_string #include <string> // to_string
#include <vector> // vector #include <vector> // vector
#include <nlohmann/detail/value_t.hpp>
#include <nlohmann/detail/string_escape.hpp>
#include <nlohmann/detail/input/position_t.hpp> #include <nlohmann/detail/input/position_t.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp> #include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/meta/type_traits.hpp>
#include <nlohmann/detail/string_concat.hpp> #include <nlohmann/detail/string_concat.hpp>
#include <nlohmann/detail/string_escape.hpp>
#include <nlohmann/detail/value_t.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
//////////////// ////////////////
// exceptions // // exceptions //
@@ -45,11 +44,14 @@ class exception : public std::exception
} }
/// the id of the exception /// the id of the exception
const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes) const int id; // NOLINT(cppcoreguidelines-non-private-member-variables-in-classes)
protected: protected:
JSON_HEDLEY_NON_NULL(3) JSON_HEDLEY_NON_NULL(3)
exception(int id_, const char* what_arg) : id(id_), m(what_arg) {} // NOLINT(bugprone-throw-keyword-missing) exception(int id_, const char* what_arg)
: id(id_)
, m(what_arg)
{} // NOLINT(bugprone-throw-keyword-missing)
static std::string name(const std::string& ename, int id_) static std::string name(const std::string& ename, int id_)
{ {
@@ -96,16 +98,16 @@ class exception : public std::exception
break; break;
} }
case value_t::null: // LCOV_EXCL_LINE case value_t::null: // LCOV_EXCL_LINE
case value_t::string: // LCOV_EXCL_LINE case value_t::string: // LCOV_EXCL_LINE
case value_t::boolean: // LCOV_EXCL_LINE case value_t::boolean: // LCOV_EXCL_LINE
case value_t::number_integer: // LCOV_EXCL_LINE case value_t::number_integer: // LCOV_EXCL_LINE
case value_t::number_unsigned: // LCOV_EXCL_LINE case value_t::number_unsigned: // LCOV_EXCL_LINE
case value_t::number_float: // LCOV_EXCL_LINE case value_t::number_float: // LCOV_EXCL_LINE
case value_t::binary: // LCOV_EXCL_LINE case value_t::binary: // LCOV_EXCL_LINE
case value_t::discarded: // LCOV_EXCL_LINE case value_t::discarded: // LCOV_EXCL_LINE
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
break; // LCOV_EXCL_LINE break; // LCOV_EXCL_LINE
} }
} }
@@ -114,9 +116,7 @@ class exception : public std::exception
return ""; return "";
} }
auto str = std::accumulate(tokens.rbegin(), tokens.rend(), std::string{}, auto str = std::accumulate(tokens.rbegin(), tokens.rend(), std::string{}, [](const std::string& a, const std::string& b) {
[](const std::string & a, const std::string & b)
{
return concat(a, '/', detail::escape(b)); return concat(a, '/', detail::escape(b));
}); });
return concat('(', str, ") "); return concat('(', str, ") ");
@@ -148,17 +148,14 @@ class parse_error : public exception
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0> template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
static parse_error create(int id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context) static parse_error create(int id_, const position_t& pos, const std::string& what_arg, BasicJsonContext context)
{ {
const std::string w = concat(exception::name("parse_error", id_), "parse error", const std::string w = concat(exception::name("parse_error", id_), "parse error", position_string(pos), ": ", exception::diagnostics(context), what_arg);
position_string(pos), ": ", exception::diagnostics(context), what_arg);
return {id_, pos.chars_read_total, w.c_str()}; return {id_, pos.chars_read_total, w.c_str()};
} }
template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0> template<typename BasicJsonContext, enable_if_t<is_basic_json_context<BasicJsonContext>::value, int> = 0>
static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context) static parse_error create(int id_, std::size_t byte_, const std::string& what_arg, BasicJsonContext context)
{ {
const std::string w = concat(exception::name("parse_error", id_), "parse error", const std::string w = concat(exception::name("parse_error", id_), "parse error", (byte_ != 0 ? (concat(" at byte ", std::to_string(byte_))) : ""), ": ", exception::diagnostics(context), what_arg);
(byte_ != 0 ? (concat(" at byte ", std::to_string(byte_))) : ""),
": ", exception::diagnostics(context), what_arg);
return {id_, byte_, w.c_str()}; return {id_, byte_, w.c_str()};
} }
@@ -175,12 +172,13 @@ class parse_error : public exception
private: private:
parse_error(int id_, std::size_t byte_, const char* what_arg) parse_error(int id_, std::size_t byte_, const char* what_arg)
: exception(id_, what_arg), byte(byte_) {} : exception(id_, what_arg)
, byte(byte_)
{}
static std::string position_string(const position_t& pos) static std::string position_string(const position_t& pos)
{ {
return concat(" at line ", std::to_string(pos.lines_read + 1), return concat(" at line ", std::to_string(pos.lines_read + 1), ", column ", std::to_string(pos.chars_read_current_line));
", column ", std::to_string(pos.chars_read_current_line));
} }
}; };
@@ -199,7 +197,8 @@ class invalid_iterator : public exception
private: private:
JSON_HEDLEY_NON_NULL(3) JSON_HEDLEY_NON_NULL(3)
invalid_iterator(int id_, const char* what_arg) invalid_iterator(int id_, const char* what_arg)
: exception(id_, what_arg) {} : exception(id_, what_arg)
{}
}; };
/// @brief exception indicating executing a member function with a wrong type /// @brief exception indicating executing a member function with a wrong type
@@ -216,7 +215,9 @@ class type_error : public exception
private: private:
JSON_HEDLEY_NON_NULL(3) JSON_HEDLEY_NON_NULL(3)
type_error(int id_, const char* what_arg) : exception(id_, what_arg) {} type_error(int id_, const char* what_arg)
: exception(id_, what_arg)
{}
}; };
/// @brief exception indicating access out of the defined range /// @brief exception indicating access out of the defined range
@@ -233,7 +234,9 @@ class out_of_range : public exception
private: private:
JSON_HEDLEY_NON_NULL(3) JSON_HEDLEY_NON_NULL(3)
out_of_range(int id_, const char* what_arg) : exception(id_, what_arg) {} out_of_range(int id_, const char* what_arg)
: exception(id_, what_arg)
{}
}; };
/// @brief exception indicating other library errors /// @brief exception indicating other library errors
@@ -250,7 +253,9 @@ class other_error : public exception
private: private:
JSON_HEDLEY_NON_NULL(3) JSON_HEDLEY_NON_NULL(3)
other_error(int id_, const char* what_arg) : exception(id_, what_arg) {} other_error(int id_, const char* what_arg)
: exception(id_, what_arg)
{}
}; };
} // namespace detail } // namespace detail
+15 -16
View File
@@ -8,16 +8,15 @@
#pragma once #pragma once
#include <cstdint> // uint8_t #include <cstddef> // size_t
#include <cstddef> // size_t #include <cstdint> // uint8_t
#include <functional> // hash #include <functional> // hash
#include <nlohmann/detail/abi_macros.hpp> #include <nlohmann/detail/abi_macros.hpp>
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
// boost::hash_combine // boost::hash_combine
inline std::size_t combine(std::size_t seed, std::size_t h) noexcept inline std::size_t combine(std::size_t seed, std::size_t h) noexcept
@@ -59,7 +58,7 @@ std::size_t hash(const BasicJsonType& j)
auto seed = combine(type, j.size()); auto seed = combine(type, j.size());
for (const auto& element : j.items()) for (const auto& element : j.items())
{ {
const auto h = std::hash<string_t> {}(element.key()); const auto h = std::hash<string_t>{}(element.key());
seed = combine(seed, h); seed = combine(seed, h);
seed = combine(seed, hash(element.value())); seed = combine(seed, hash(element.value()));
} }
@@ -78,50 +77,50 @@ std::size_t hash(const BasicJsonType& j)
case BasicJsonType::value_t::string: case BasicJsonType::value_t::string:
{ {
const auto h = std::hash<string_t> {}(j.template get_ref<const string_t&>()); const auto h = std::hash<string_t>{}(j.template get_ref<const string_t&>());
return combine(type, h); return combine(type, h);
} }
case BasicJsonType::value_t::boolean: case BasicJsonType::value_t::boolean:
{ {
const auto h = std::hash<bool> {}(j.template get<bool>()); const auto h = std::hash<bool>{}(j.template get<bool>());
return combine(type, h); return combine(type, h);
} }
case BasicJsonType::value_t::number_integer: case BasicJsonType::value_t::number_integer:
{ {
const auto h = std::hash<number_integer_t> {}(j.template get<number_integer_t>()); const auto h = std::hash<number_integer_t>{}(j.template get<number_integer_t>());
return combine(type, h); return combine(type, h);
} }
case BasicJsonType::value_t::number_unsigned: case BasicJsonType::value_t::number_unsigned:
{ {
const auto h = std::hash<number_unsigned_t> {}(j.template get<number_unsigned_t>()); const auto h = std::hash<number_unsigned_t>{}(j.template get<number_unsigned_t>());
return combine(type, h); return combine(type, h);
} }
case BasicJsonType::value_t::number_float: case BasicJsonType::value_t::number_float:
{ {
const auto h = std::hash<number_float_t> {}(j.template get<number_float_t>()); const auto h = std::hash<number_float_t>{}(j.template get<number_float_t>());
return combine(type, h); return combine(type, h);
} }
case BasicJsonType::value_t::binary: case BasicJsonType::value_t::binary:
{ {
auto seed = combine(type, j.get_binary().size()); auto seed = combine(type, j.get_binary().size());
const auto h = std::hash<bool> {}(j.get_binary().has_subtype()); const auto h = std::hash<bool>{}(j.get_binary().has_subtype());
seed = combine(seed, h); seed = combine(seed, h);
seed = combine(seed, static_cast<std::size_t>(j.get_binary().subtype())); seed = combine(seed, static_cast<std::size_t>(j.get_binary().subtype()));
for (const auto byte : j.get_binary()) for (const auto byte : j.get_binary())
{ {
seed = combine(seed, std::hash<std::uint8_t> {}(byte)); seed = combine(seed, std::hash<std::uint8_t>{}(byte));
} }
return seed; return seed;
} }
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
return 0; // LCOV_EXCL_LINE return 0; // LCOV_EXCL_LINE
} }
} }
File diff suppressed because it is too large. Load diff
@@ -8,15 +8,15 @@
#pragma once #pragma once
#include <array> // array #include <array> // array
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstring> // strlen #include <cstring> // strlen
#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next #include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
#include <memory> // shared_ptr, make_shared, addressof #include <memory> // shared_ptr, make_shared, addressof
#include <numeric> // accumulate #include <numeric> // accumulate
#include <string> // string, char_traits #include <string> // string, char_traits
#include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer #include <type_traits> // enable_if, is_base_of, is_pointer, is_integral, remove_pointer
#include <utility> // pair, declval #include <utility> // pair, declval
#ifndef JSON_NO_IO #ifndef JSON_NO_IO
#include <cstdio> // FILE * #include <cstdio> // FILE *
@@ -28,11 +28,18 @@
#include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/meta/type_traits.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
/// the supported input formats /// the supported input formats
enum class input_format_t { json, cbor, msgpack, ubjson, bson, bjdata }; enum class input_format_t
{
json,
cbor,
msgpack,
ubjson,
bson,
bjdata
};
//////////////////// ////////////////////
// input adapters // // input adapters //
@@ -50,7 +57,7 @@ class file_input_adapter
JSON_HEDLEY_NON_NULL(2) JSON_HEDLEY_NON_NULL(2)
explicit file_input_adapter(std::FILE* f) noexcept explicit file_input_adapter(std::FILE* f) noexcept
: m_file(f) : m_file(f)
{ {
JSON_ASSERT(m_file != nullptr); JSON_ASSERT(m_file != nullptr);
} }
@@ -97,7 +104,8 @@ class input_stream_adapter
} }
explicit input_stream_adapter(std::istream& i) explicit input_stream_adapter(std::istream& i)
: is(&i), sb(i.rdbuf()) : is(&i)
, sb(i.rdbuf())
{} {}
// delete because of pointer members // delete because of pointer members
@@ -106,7 +114,8 @@ class input_stream_adapter
input_stream_adapter& operator=(input_stream_adapter&&) = delete; input_stream_adapter& operator=(input_stream_adapter&&) = delete;
input_stream_adapter(input_stream_adapter&& rhs) noexcept input_stream_adapter(input_stream_adapter&& rhs) noexcept
: is(rhs.is), sb(rhs.sb) : is(rhs.is)
, sb(rhs.sb)
{ {
rhs.is = nullptr; rhs.is = nullptr;
rhs.sb = nullptr; rhs.sb = nullptr;
@@ -142,7 +151,8 @@ class iterator_input_adapter
using char_type = typename std::iterator_traits<IteratorType>::value_type; using char_type = typename std::iterator_traits<IteratorType>::value_type;
iterator_input_adapter(IteratorType first, IteratorType last) iterator_input_adapter(IteratorType first, IteratorType last)
: current(std::move(first)), end(std::move(last)) : current(std::move(first))
, end(std::move(last))
{} {}
typename char_traits<char_type>::int_type get_character() typename char_traits<char_type>::int_type get_character()
@@ -301,7 +311,8 @@ class wide_string_input_adapter
using char_type = char; using char_type = char;
wide_string_input_adapter(BaseInputAdapter base) wide_string_input_adapter(BaseInputAdapter base)
: base_adapter(base) {} : base_adapter(base)
{}
typename std::char_traits<char>::int_type get_character() noexcept typename std::char_traits<char>::int_type get_character() noexcept
{ {
@@ -387,26 +398,26 @@ typename iterator_input_adapter_factory<IteratorType>::adapter_type input_adapte
// Enables ADL on begin(container) and end(container) // Enables ADL on begin(container) and end(container)
// Encloses the using declarations in namespace for not to leak them to outside scope // Encloses the using declarations in namespace for not to leak them to outside scope
namespace container_input_adapter_factory_impl namespace container_input_adapter_factory_impl {
{
using std::begin; using std::begin;
using std::end; using std::end;
template<typename ContainerType, typename Enable = void> template<typename ContainerType, typename Enable = void>
struct container_input_adapter_factory {}; struct container_input_adapter_factory
{};
template<typename ContainerType> template<typename ContainerType>
struct container_input_adapter_factory< ContainerType, struct container_input_adapter_factory<ContainerType,
void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))>> void_t<decltype(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>()))>>
{
using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));
static adapter_type create(const ContainerType& container)
{ {
return input_adapter(begin(container), end(container)); using adapter_type = decltype(input_adapter(begin(std::declval<ContainerType>()), end(std::declval<ContainerType>())));
}
}; static adapter_type create(const ContainerType& container)
{
return input_adapter(begin(container), end(container));
}
};
} // namespace container_input_adapter_factory_impl } // namespace container_input_adapter_factory_impl
@@ -437,13 +448,13 @@ inline input_stream_adapter input_adapter(std::istream&& stream)
using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const char*>(), std::declval<const char*>())); using contiguous_bytes_input_adapter = decltype(input_adapter(std::declval<const char*>(), std::declval<const char*>()));
// Null-delimited strings, and the like. // Null-delimited strings, and the like.
template < typename CharT, template<typename CharT,
typename std::enable_if < typename std::enable_if<
std::is_pointer<CharT>::value&& std::is_pointer<CharT>::value &&
!std::is_array<CharT>::value&& !std::is_array<CharT>::value &&
std::is_integral<typename std::remove_pointer<CharT>::type>::value&& std::is_integral<typename std::remove_pointer<CharT>::type>::value &&
sizeof(typename std::remove_pointer<CharT>::type) == 1, sizeof(typename std::remove_pointer<CharT>::type) == 1,
int >::type = 0 > int>::type = 0>
contiguous_bytes_input_adapter input_adapter(CharT b) contiguous_bytes_input_adapter input_adapter(CharT b)
{ {
auto length = std::strlen(reinterpret_cast<const char*>(b)); auto length = std::strlen(reinterpret_cast<const char*>(b));
@@ -452,7 +463,7 @@ contiguous_bytes_input_adapter input_adapter(CharT b)
} }
template<typename T, std::size_t N> template<typename T, std::size_t N>
auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
{ {
return input_adapter(array, array + N); return input_adapter(array, array + N);
} }
@@ -463,25 +474,27 @@ auto input_adapter(T (&array)[N]) -> decltype(input_adapter(array, array + N)) /
class span_input_adapter class span_input_adapter
{ {
public: public:
template < typename CharT, template<typename CharT,
typename std::enable_if < typename std::enable_if<
std::is_pointer<CharT>::value&& std::is_pointer<CharT>::value &&
std::is_integral<typename std::remove_pointer<CharT>::type>::value&& std::is_integral<typename std::remove_pointer<CharT>::type>::value &&
sizeof(typename std::remove_pointer<CharT>::type) == 1, sizeof(typename std::remove_pointer<CharT>::type) == 1,
int >::type = 0 > int>::type = 0>
span_input_adapter(CharT b, std::size_t l) span_input_adapter(CharT b, std::size_t l)
: ia(reinterpret_cast<const char*>(b), reinterpret_cast<const char*>(b) + l) {} : ia(reinterpret_cast<const char*>(b), reinterpret_cast<const char*>(b) + l)
{}
template<class IteratorType, template<class IteratorType,
typename std::enable_if< typename std::enable_if<
std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value, std::is_same<typename iterator_traits<IteratorType>::iterator_category, std::random_access_iterator_tag>::value,
int>::type = 0> int>::type = 0>
span_input_adapter(IteratorType first, IteratorType last) span_input_adapter(IteratorType first, IteratorType last)
: ia(input_adapter(first, last)) {} : ia(input_adapter(first, last))
{}
contiguous_bytes_input_adapter&& get() contiguous_bytes_input_adapter&& get()
{ {
return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg) return std::move(ia); // NOLINT(hicpp-move-const-arg,performance-move-const-arg)
} }
private: private:
+23 -22
View File
@@ -9,9 +9,9 @@
#pragma once #pragma once
#include <cstddef> #include <cstddef>
#include <string> // string #include <string> // string
#include <utility> // move #include <utility> // move
#include <vector> // vector #include <vector> // vector
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
@@ -142,8 +142,7 @@ struct json_sax
virtual ~json_sax() = default; virtual ~json_sax() = default;
}; };
namespace detail namespace detail {
{
/*! /*!
@brief SAX implementation to create a JSON value from SAX events @brief SAX implementation to create a JSON value from SAX events
@@ -173,14 +172,15 @@ class json_sax_dom_parser
@param[in] allow_exceptions_ whether parse errors yield exceptions @param[in] allow_exceptions_ whether parse errors yield exceptions
*/ */
explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true) explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)
: root(r), allow_exceptions(allow_exceptions_) : root(r)
, allow_exceptions(allow_exceptions_)
{} {}
// make class move-only // make class move-only
json_sax_dom_parser(const json_sax_dom_parser&) = delete; json_sax_dom_parser(const json_sax_dom_parser&) = delete;
json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) json_sax_dom_parser(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete; json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete;
json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
~json_sax_dom_parser() = default; ~json_sax_dom_parser() = default;
bool null() bool null()
@@ -280,8 +280,7 @@ class json_sax_dom_parser
} }
template<class Exception> template<class Exception>
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const Exception& ex)
const Exception& ex)
{ {
errored = true; errored = true;
static_cast<void>(ex); static_cast<void>(ex);
@@ -306,7 +305,8 @@ class json_sax_dom_parser
*/ */
template<typename Value> template<typename Value>
JSON_HEDLEY_RETURNS_NON_NULL JSON_HEDLEY_RETURNS_NON_NULL
BasicJsonType* handle_value(Value&& v) BasicJsonType*
handle_value(Value&& v)
{ {
if (ref_stack.empty()) if (ref_stack.empty())
{ {
@@ -331,7 +331,7 @@ class json_sax_dom_parser
/// the parsed JSON value /// the parsed JSON value
BasicJsonType& root; BasicJsonType& root;
/// stack to model hierarchy of values /// stack to model hierarchy of values
std::vector<BasicJsonType*> ref_stack {}; std::vector<BasicJsonType*> ref_stack{};
/// helper to hold the reference for the next object element /// helper to hold the reference for the next object element
BasicJsonType* object_element = nullptr; BasicJsonType* object_element = nullptr;
/// whether a syntax error occurred /// whether a syntax error occurred
@@ -355,16 +355,18 @@ class json_sax_dom_callback_parser
json_sax_dom_callback_parser(BasicJsonType& r, json_sax_dom_callback_parser(BasicJsonType& r,
const parser_callback_t cb, const parser_callback_t cb,
const bool allow_exceptions_ = true) const bool allow_exceptions_ = true)
: root(r), callback(cb), allow_exceptions(allow_exceptions_) : root(r)
, callback(cb)
, allow_exceptions(allow_exceptions_)
{ {
keep_stack.push_back(true); keep_stack.push_back(true);
} }
// make class move-only // make class move-only
json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete; json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete;
json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete; json_sax_dom_callback_parser& operator=(const json_sax_dom_callback_parser&) = delete;
json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) json_sax_dom_callback_parser& operator=(json_sax_dom_callback_parser&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
~json_sax_dom_callback_parser() = default; ~json_sax_dom_callback_parser() = default;
bool null() bool null()
@@ -530,8 +532,7 @@ class json_sax_dom_callback_parser
} }
template<class Exception> template<class Exception>
bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const Exception& ex)
const Exception& ex)
{ {
errored = true; errored = true;
static_cast<void>(ex); static_cast<void>(ex);
@@ -590,7 +591,7 @@ class json_sax_dom_callback_parser
if (ref_stack.empty()) if (ref_stack.empty())
{ {
root = std::move(value); root = std::move(value);
return {true, & root}; return {true, &root};
} }
// skip this value if we already decided to skip the parent // skip this value if we already decided to skip the parent
@@ -607,7 +608,7 @@ class json_sax_dom_callback_parser
if (ref_stack.back()->is_array()) if (ref_stack.back()->is_array())
{ {
ref_stack.back()->m_data.m_value.array->emplace_back(std::move(value)); ref_stack.back()->m_data.m_value.array->emplace_back(std::move(value));
return {true, & (ref_stack.back()->m_data.m_value.array->back())}; return {true, &(ref_stack.back()->m_data.m_value.array->back())};
} }
// object // object
@@ -630,11 +631,11 @@ class json_sax_dom_callback_parser
/// the parsed JSON value /// the parsed JSON value
BasicJsonType& root; BasicJsonType& root;
/// stack to model hierarchy of values /// stack to model hierarchy of values
std::vector<BasicJsonType*> ref_stack {}; std::vector<BasicJsonType*> ref_stack{};
/// stack to manage which values to keep /// stack to manage which values to keep
std::vector<bool> keep_stack {}; std::vector<bool> keep_stack{};
/// stack to manage which object keys to keep /// stack to manage which object keys to keep
std::vector<bool> key_keep_stack {}; std::vector<bool> key_keep_stack{};
/// helper to hold the reference for the next object element /// helper to hold the reference for the next object element
BasicJsonType* object_element = nullptr; BasicJsonType* object_element = nullptr;
/// whether a syntax error occurred /// whether a syntax error occurred
+36 -39
View File
@@ -8,15 +8,15 @@
#pragma once #pragma once
#include <array> // array #include <array> // array
#include <clocale> // localeconv #include <clocale> // localeconv
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdio> // snprintf #include <cstdio> // snprintf
#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull #include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
#include <initializer_list> // initializer_list #include <initializer_list> // initializer_list
#include <string> // char_traits, string #include <string> // char_traits, string
#include <utility> // move #include <utility> // move
#include <vector> // vector #include <vector> // vector
#include <nlohmann/detail/input/input_adapters.hpp> #include <nlohmann/detail/input/input_adapters.hpp>
#include <nlohmann/detail/input/position_t.hpp> #include <nlohmann/detail/input/position_t.hpp>
@@ -24,8 +24,7 @@
#include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/meta/type_traits.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
/////////// ///////////
// lexer // // lexer //
@@ -97,7 +96,7 @@ class lexer_base
case token_type::literal_or_value: case token_type::literal_or_value:
return "'[', '{', or a literal"; return "'[', '{', or a literal";
// LCOV_EXCL_START // LCOV_EXCL_START
default: // catch non-enum values default: // catch non-enum values
return "unknown token"; return "unknown token";
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }
@@ -122,16 +121,16 @@ class lexer : public lexer_base<BasicJsonType>
using token_type = typename lexer_base<BasicJsonType>::token_type; using token_type = typename lexer_base<BasicJsonType>::token_type;
explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept explicit lexer(InputAdapterType&& adapter, bool ignore_comments_ = false) noexcept
: ia(std::move(adapter)) : ia(std::move(adapter))
, ignore_comments(ignore_comments_) , ignore_comments(ignore_comments_)
, decimal_point_char(static_cast<char_int_type>(get_decimal_point())) , decimal_point_char(static_cast<char_int_type>(get_decimal_point()))
{} {}
// delete because of pointer members // delete because of pointer members
lexer(const lexer&) = delete; lexer(const lexer&) = delete;
lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) lexer(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
lexer& operator=(lexer&) = delete; lexer& operator=(lexer&) = delete;
lexer& operator=(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor) lexer& operator=(lexer&&) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor)
~lexer() = default; ~lexer() = default;
private: private:
@@ -173,7 +172,7 @@ class lexer : public lexer_base<BasicJsonType>
JSON_ASSERT(current == 'u'); JSON_ASSERT(current == 'u');
int codepoint = 0; int codepoint = 0;
const auto factors = { 12u, 8u, 4u, 0u }; const auto factors = {12u, 8u, 4u, 0u};
for (const auto factor : factors) for (const auto factor : factors)
{ {
get(); get();
@@ -223,7 +222,7 @@ class lexer : public lexer_base<BasicJsonType>
for (auto range = ranges.begin(); range != ranges.end(); ++range) for (auto range = ranges.begin(); range != ranges.end(); ++range)
{ {
get(); get();
if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) // NOLINT(bugprone-inc-dec-in-conditions) if (JSON_HEDLEY_LIKELY(*range <= current && current <= *(++range))) // NOLINT(bugprone-inc-dec-in-conditions)
{ {
add(current); add(current);
} }
@@ -320,7 +319,7 @@ class lexer : public lexer_base<BasicJsonType>
case 'u': case 'u':
{ {
const int codepoint1 = get_codepoint(); const int codepoint1 = get_codepoint();
int codepoint = codepoint1; // start with codepoint1 int codepoint = codepoint1; // start with codepoint1
if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1)) if (JSON_HEDLEY_UNLIKELY(codepoint1 == -1))
{ {
@@ -347,14 +346,14 @@ class lexer : public lexer_base<BasicJsonType>
{ {
// overwrite codepoint // overwrite codepoint
codepoint = static_cast<int>( codepoint = static_cast<int>(
// high surrogate occupies the most significant 22 bits // high surrogate occupies the most significant 22 bits
(static_cast<unsigned int>(codepoint1) << 10u) (static_cast<unsigned int>(codepoint1) << 10u)
// low surrogate occupies the least significant 15 bits // low surrogate occupies the least significant 15 bits
+ static_cast<unsigned int>(codepoint2) + static_cast<unsigned int>(codepoint2)
// there is still the 0xD800, 0xDC00 and 0x10000 noise // there is still the 0xD800, 0xDC00 and 0x10000 noise
// in the result, so we have to subtract with: // in the result, so we have to subtract with:
// (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00 // (0xD800 << 10) + DC00 - 0x10000 = 0x35FDC00
- 0x35FDC00u); - 0x35FDC00u);
} }
else else
{ {
@@ -1006,8 +1005,8 @@ class lexer : public lexer_base<BasicJsonType>
} }
// all other characters are rejected outside scan_number() // all other characters are rejected outside scan_number()
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
} }
scan_number_minus: scan_number_minus:
@@ -1245,7 +1244,7 @@ scan_number_done:
// we are done scanning a number) // we are done scanning a number)
unget(); unget();
char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) char* endptr = nullptr; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
errno = 0; errno = 0;
// try to parse integers first and fall back to floats // try to parse integers first and fall back to floats
@@ -1298,8 +1297,7 @@ scan_number_done:
@param[in] return_type the token type to return on success @param[in] return_type the token type to return on success
*/ */
JSON_HEDLEY_NON_NULL(2) JSON_HEDLEY_NON_NULL(2)
token_type scan_literal(const char_type* literal_text, const std::size_t length, token_type scan_literal(const char_type* literal_text, const std::size_t length, token_type return_type)
token_type return_type)
{ {
JSON_ASSERT(char_traits<char_type>::to_char_type(current) == literal_text[0]); JSON_ASSERT(char_traits<char_type>::to_char_type(current) == literal_text[0]);
for (std::size_t i = 1; i < length; ++i) for (std::size_t i = 1; i < length; ++i)
@@ -1456,7 +1454,7 @@ scan_number_done:
{ {
// escape control characters // escape control characters
std::array<char, 9> cs{{}}; std::array<char, 9> cs{{}};
static_cast<void>((std::snprintf)(cs.data(), cs.size(), "<U+%.4X>", static_cast<unsigned char>(c))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) static_cast<void>((std::snprintf)(cs.data(), cs.size(), "<U+%.4X>", static_cast<unsigned char>(c))); // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
result += cs.data(); result += cs.data();
} }
else else
@@ -1503,8 +1501,7 @@ scan_number_done:
do do
{ {
get(); get();
} } while (current == ' ' || current == '\t' || current == '\n' || current == '\r');
while (current == ' ' || current == '\t' || current == '\n' || current == '\r');
} }
token_type scan() token_type scan()
@@ -1609,13 +1606,13 @@ scan_number_done:
bool next_unget = false; bool next_unget = false;
/// the start position of the current token /// the start position of the current token
position_t position {}; position_t position{};
/// raw input token string (for error messages) /// raw input token string (for error messages)
std::vector<char_type> token_string {}; std::vector<char_type> token_string{};
/// buffer for variable-length tokens (numbers, strings) /// buffer for variable-length tokens (numbers, strings)
string_t token_buffer {}; string_t token_buffer{};
/// a description of occurred lexer errors /// a description of occurred lexer errors
const char* error_message = ""; const char* error_message = "";
+15 -19
View File
@@ -8,12 +8,12 @@
#pragma once #pragma once
#include <cmath> // isfinite #include <cmath> // isfinite
#include <cstdint> // uint8_t #include <cstdint> // uint8_t
#include <functional> // function #include <functional> // function
#include <string> // string #include <string> // string
#include <utility> // move #include <utility> // move
#include <vector> // vector #include <vector> // vector
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/input/input_adapters.hpp> #include <nlohmann/detail/input/input_adapters.hpp>
@@ -25,8 +25,7 @@
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
//////////// ////////////
// parser // // parser //
//////////// ////////////
@@ -72,9 +71,9 @@ class parser
const parser_callback_t<BasicJsonType> cb = nullptr, const parser_callback_t<BasicJsonType> cb = nullptr,
const bool allow_exceptions_ = true, const bool allow_exceptions_ = true,
const bool skip_comments = false) const bool skip_comments = false)
: callback(cb) : callback(cb)
, m_lexer(std::move(adapter), skip_comments) , m_lexer(std::move(adapter), skip_comments)
, allow_exceptions(allow_exceptions_) , allow_exceptions(allow_exceptions_)
{ {
// read first token // read first token
get_token(); get_token();
@@ -102,8 +101,7 @@ class parser
{ {
sdp.parse_error(m_lexer.get_position(), sdp.parse_error(m_lexer.get_position(),
m_lexer.get_token_string(), m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input, "value"), nullptr));
exception_message(token_type::end_of_input, "value"), nullptr));
} }
// in case of an error, return discarded value // in case of an error, return discarded value
@@ -160,7 +158,7 @@ class parser
JSON_HEDLEY_NON_NULL(2) JSON_HEDLEY_NON_NULL(2)
bool sax_parse(SAX* sax, const bool strict = true) bool sax_parse(SAX* sax, const bool strict = true)
{ {
(void)detail::is_sax_static_asserts<SAX, BasicJsonType> {}; (void)detail::is_sax_static_asserts<SAX, BasicJsonType>{};
const bool result = sax_parse_internal(sax); const bool result = sax_parse_internal(sax);
// strict mode: next byte must be EOF // strict mode: next byte must be EOF
@@ -347,8 +345,7 @@ class parser
{ {
return sax->parse_error(m_lexer.get_position(), return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(), m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), parse_error::create(101, m_lexer.get_position(), "attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
"attempting to parse an empty input; check that your input string or stream contains the expected JSON", nullptr));
} }
return sax->parse_error(m_lexer.get_position(), return sax->parse_error(m_lexer.get_position(),
@@ -361,7 +358,7 @@ class parser
case token_type::name_separator: case token_type::name_separator:
case token_type::value_separator: case token_type::value_separator:
case token_type::literal_or_value: case token_type::literal_or_value:
default: // the last token was unexpected default: // the last token was unexpected
{ {
return sax->parse_error(m_lexer.get_position(), return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(), m_lexer.get_token_string(),
@@ -488,8 +485,7 @@ class parser
if (last_token == token_type::parse_error) if (last_token == token_type::parse_error)
{ {
error_msg += concat(m_lexer.get_error_message(), "; last read: '", error_msg += concat(m_lexer.get_error_message(), "; last read: '", m_lexer.get_token_string(), '\'');
m_lexer.get_token_string(), '\'');
} }
else else
{ {
+2 -3
View File
@@ -8,13 +8,12 @@
#pragma once #pragma once
#include <cstddef> // size_t #include <cstddef> // size_t
#include <nlohmann/detail/abi_macros.hpp> #include <nlohmann/detail/abi_macros.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
/// struct to capture the start position of the current token /// struct to capture the start position of the current token
struct position_t struct position_t
@@ -12,8 +12,7 @@
#include <nlohmann/detail/iterators/primitive_iterator.hpp> #include <nlohmann/detail/iterators/primitive_iterator.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
/*! /*!
@brief an iterator value @brief an iterator value
@@ -21,14 +20,15 @@ namespace detail
@note This structure could easily be a union, but MSVC currently does not allow @note This structure could easily be a union, but MSVC currently does not allow
unions members with complex constructors, see https://github.com/nlohmann/json/pull/105. unions members with complex constructors, see https://github.com/nlohmann/json/pull/105.
*/ */
template<typename BasicJsonType> struct internal_iterator template<typename BasicJsonType>
struct internal_iterator
{ {
/// iterator for JSON objects /// iterator for JSON objects
typename BasicJsonType::object_t::iterator object_iterator {}; typename BasicJsonType::object_t::iterator object_iterator{};
/// iterator for JSON arrays /// iterator for JSON arrays
typename BasicJsonType::array_t::iterator array_iterator {}; typename BasicJsonType::array_t::iterator array_iterator{};
/// generic iterator for all other types /// generic iterator for all other types
primitive_iterator_t primitive_iterator {}; primitive_iterator_t primitive_iterator{};
}; };
} // namespace detail } // namespace detail
+33 -29
View File
@@ -8,8 +8,8 @@
#pragma once #pragma once
#include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next #include <iterator> // iterator, random_access_iterator_tag, bidirectional_iterator_tag, advance, next
#include <type_traits> // conditional, is_const, remove_const #include <type_traits> // conditional, is_const, remove_const
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/iterators/internal_iterator.hpp> #include <nlohmann/detail/iterators/internal_iterator.hpp>
@@ -20,12 +20,13 @@
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
// forward declare, to be able to friend it later on // forward declare, to be able to friend it later on
template<typename IteratorType> class iteration_proxy; template<typename IteratorType>
template<typename IteratorType> class iteration_proxy_value; class iteration_proxy;
template<typename IteratorType>
class iteration_proxy_value;
/*! /*!
@brief a template for a bidirectional iterator for the @ref basic_json class @brief a template for a bidirectional iterator for the @ref basic_json class
@@ -44,7 +45,7 @@ This class implements a both iterators (iterator and const_iterator) for the
iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593) iterators in version 3.0.0 (see https://github.com/nlohmann/json/issues/593)
*/ */
template<typename BasicJsonType> template<typename BasicJsonType>
class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions) class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-special-member-functions)
{ {
/// the iterator with BasicJsonType of different const-ness /// the iterator with BasicJsonType of different const-ness
using other_iter_impl = iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>; using other_iter_impl = iter_impl<typename std::conditional<std::is_const<BasicJsonType>::value, typename std::remove_const<BasicJsonType>::type, const BasicJsonType>::type>;
@@ -60,8 +61,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value, static_assert(is_basic_json<typename std::remove_const<BasicJsonType>::type>::value,
"iter_impl only accepts (const) basic_json"); "iter_impl only accepts (const) basic_json");
// superficial check for the LegacyBidirectionalIterator named requirement // superficial check for the LegacyBidirectionalIterator named requirement
static_assert(std::is_base_of<std::bidirectional_iterator_tag, std::bidirectional_iterator_tag>::value static_assert(std::is_base_of<std::bidirectional_iterator_tag, std::bidirectional_iterator_tag>::value && std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<typename array_t::iterator>::iterator_category>::value,
&& std::is_base_of<std::bidirectional_iterator_tag, typename std::iterator_traits<typename array_t::iterator>::iterator_category>::value,
"basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement."); "basic_json iterator assumes array and object type iterators satisfy the LegacyBidirectionalIterator named requirement.");
public: public:
@@ -78,13 +78,13 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
using difference_type = typename BasicJsonType::difference_type; using difference_type = typename BasicJsonType::difference_type;
/// defines a pointer to the type iterated over (value_type) /// defines a pointer to the type iterated over (value_type)
using pointer = typename std::conditional<std::is_const<BasicJsonType>::value, using pointer = typename std::conditional<std::is_const<BasicJsonType>::value,
typename BasicJsonType::const_pointer, typename BasicJsonType::const_pointer,
typename BasicJsonType::pointer>::type; typename BasicJsonType::pointer>::type;
/// defines a reference to the type iterated over (value_type) /// defines a reference to the type iterated over (value_type)
using reference = using reference =
typename std::conditional<std::is_const<BasicJsonType>::value, typename std::conditional<std::is_const<BasicJsonType>::value,
typename BasicJsonType::const_reference, typename BasicJsonType::const_reference,
typename BasicJsonType::reference>::type; typename BasicJsonType::reference>::type;
iter_impl() = default; iter_impl() = default;
~iter_impl() = default; ~iter_impl() = default;
@@ -97,7 +97,8 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
@pre object != nullptr @pre object != nullptr
@post The iterator is initialized; i.e. `m_object != nullptr`. @post The iterator is initialized; i.e. `m_object != nullptr`.
*/ */
explicit iter_impl(pointer object) noexcept : m_object(object) explicit iter_impl(pointer object) noexcept
: m_object(object)
{ {
JSON_ASSERT(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
@@ -148,7 +149,8 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
information refer to: https://github.com/nlohmann/json/issues/1608 information refer to: https://github.com/nlohmann/json/issues/1608
*/ */
iter_impl(const iter_impl<const BasicJsonType>& other) noexcept iter_impl(const iter_impl<const BasicJsonType>& other) noexcept
: m_object(other.m_object), m_it(other.m_it) : m_object(other.m_object)
, m_it(other.m_it)
{} {}
/*! /*!
@@ -173,7 +175,8 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
@note It is not checked whether @a other is initialized. @note It is not checked whether @a other is initialized.
*/ */
iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept iter_impl(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept
: m_object(other.m_object), m_it(other.m_it) : m_object(other.m_object)
, m_it(other.m_it)
{} {}
/*! /*!
@@ -182,19 +185,20 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
@return const/non-const iterator @return const/non-const iterator
@note It is not checked whether @a other is initialized. @note It is not checked whether @a other is initialized.
*/ */
iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept // NOLINT(cert-oop54-cpp) iter_impl& operator=(const iter_impl<typename std::remove_const<BasicJsonType>::type>& other) noexcept // NOLINT(cert-oop54-cpp)
{ {
m_object = other.m_object; m_object = other.m_object;
m_it = other.m_it; m_it = other.m_it;
return *this; return *this;
} }
JSON_PRIVATE_UNLESS_TESTED: JSON_PRIVATE_UNLESS_TESTED :
/*! /*!
@brief set the iterator to the first value @brief set the iterator to the first value
@pre The iterator is initialized; i.e. `m_object != nullptr`. @pre The iterator is initialized; i.e. `m_object != nullptr`.
*/ */
void set_begin() noexcept void
set_begin() noexcept
{ {
JSON_ASSERT(m_object != nullptr); JSON_ASSERT(m_object != nullptr);
@@ -363,7 +367,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
@brief post-increment (it++) @brief post-increment (it++)
@pre The iterator is initialized; i.e. `m_object != nullptr`. @pre The iterator is initialized; i.e. `m_object != nullptr`.
*/ */
iter_impl operator++(int)& // NOLINT(cert-dcl21-cpp) iter_impl operator++(int) & // NOLINT(cert-dcl21-cpp)
{ {
auto result = *this; auto result = *this;
++(*this); ++(*this);
@@ -414,7 +418,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
@brief post-decrement (it--) @brief post-decrement (it--)
@pre The iterator is initialized; i.e. `m_object != nullptr`. @pre The iterator is initialized; i.e. `m_object != nullptr`.
*/ */
iter_impl operator--(int)& // NOLINT(cert-dcl21-cpp) iter_impl operator--(int) & // NOLINT(cert-dcl21-cpp)
{ {
auto result = *this; auto result = *this;
--(*this); --(*this);
@@ -465,7 +469,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
@brief comparison: equal @brief comparison: equal
@pre The iterator is initialized; i.e. `m_object != nullptr`. @pre The iterator is initialized; i.e. `m_object != nullptr`.
*/ */
template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr > template<typename IterImpl, detail::enable_if_t<(std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t> = nullptr>
bool operator==(const IterImpl& other) const bool operator==(const IterImpl& other) const
{ {
// if objects are not the same, the comparison is undefined // if objects are not the same, the comparison is undefined
@@ -501,7 +505,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
@brief comparison: not equal @brief comparison: not equal
@pre The iterator is initialized; i.e. `m_object != nullptr`. @pre The iterator is initialized; i.e. `m_object != nullptr`.
*/ */
template < typename IterImpl, detail::enable_if_t < (std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t > = nullptr > template<typename IterImpl, detail::enable_if_t<(std::is_same<IterImpl, iter_impl>::value || std::is_same<IterImpl, other_iter_impl>::value), std::nullptr_t> = nullptr>
bool operator!=(const IterImpl& other) const bool operator!=(const IterImpl& other) const
{ {
return !operator==(other); return !operator==(other);
@@ -548,7 +552,7 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
*/ */
bool operator<=(const iter_impl& other) const bool operator<=(const iter_impl& other) const
{ {
return !other.operator < (*this); return !other.operator<(*this);
} }
/*! /*!
@@ -740,11 +744,11 @@ class iter_impl // NOLINT(cppcoreguidelines-special-member-functions,hicpp-speci
return operator*(); return operator*();
} }
JSON_PRIVATE_UNLESS_TESTED: JSON_PRIVATE_UNLESS_TESTED :
/// associated JSON instance /// associated JSON instance
pointer m_object = nullptr; pointer m_object = nullptr;
/// the actual iterator of the associated instance /// the actual iterator of the associated instance
internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it {}; internal_iterator<typename std::remove_const<BasicJsonType>::type> m_it{};
}; };
} // namespace detail } // namespace detail
@@ -8,14 +8,14 @@
#pragma once #pragma once
#include <cstddef> // size_t #include <cstddef> // size_t
#include <iterator> // input_iterator_tag #include <iterator> // input_iterator_tag
#include <string> // string, to_string #include <string> // string, to_string
#include <tuple> // tuple_size, get, tuple_element #include <tuple> // tuple_size, get, tuple_element
#include <utility> // move #include <utility> // move
#if JSON_HAS_RANGES #if JSON_HAS_RANGES
#include <ranges> // enable_borrowed_range #include <ranges> // enable_borrowed_range
#endif #endif
#include <nlohmann/detail/abi_macros.hpp> #include <nlohmann/detail/abi_macros.hpp>
@@ -23,25 +23,25 @@
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
template<typename string_type> template<typename string_type>
void int_to_string( string_type& target, std::size_t value ) void int_to_string(string_type& target, std::size_t value)
{ {
// For ADL // For ADL
using std::to_string; using std::to_string;
target = to_string(value); target = to_string(value);
} }
template<typename IteratorType> class iteration_proxy_value template<typename IteratorType>
class iteration_proxy_value
{ {
public: public:
using difference_type = std::ptrdiff_t; using difference_type = std::ptrdiff_t;
using value_type = iteration_proxy_value; using value_type = iteration_proxy_value;
using pointer = value_type *; using pointer = value_type*;
using reference = value_type &; using reference = value_type&;
using iterator_category = std::input_iterator_tag; 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; using string_type = typename std::remove_cv<typename std::remove_reference<decltype(std::declval<IteratorType>().key())>::type>::type;
private: private:
/// the iterator /// the iterator
@@ -57,22 +57,16 @@ template<typename IteratorType> class iteration_proxy_value
public: public:
explicit iteration_proxy_value() = default; explicit iteration_proxy_value() = default;
explicit iteration_proxy_value(IteratorType it, std::size_t array_index_ = 0) 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)
noexcept(std::is_nothrow_move_constructible<IteratorType>::value : anchor(std::move(it))
&& std::is_nothrow_default_constructible<string_type>::value) , array_index(array_index_)
: anchor(std::move(it))
, array_index(array_index_)
{} {}
iteration_proxy_value(iteration_proxy_value const&) = default; iteration_proxy_value(iteration_proxy_value const&) = default;
iteration_proxy_value& operator=(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 // older GCCs are a bit fussy and require explicit noexcept specifiers on defaulted functions
iteration_proxy_value(iteration_proxy_value&&) iteration_proxy_value(iteration_proxy_value&&) noexcept(std::is_nothrow_move_constructible<IteratorType>::value && std::is_nothrow_move_constructible<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)
noexcept(std::is_nothrow_move_constructible<IteratorType>::value iteration_proxy_value& operator=(iteration_proxy_value&&) noexcept(std::is_nothrow_move_assignable<IteratorType>::value && std::is_nothrow_move_assignable<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)
&& std::is_nothrow_move_constructible<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)
iteration_proxy_value& operator=(iteration_proxy_value&&)
noexcept(std::is_nothrow_move_assignable<IteratorType>::value
&& std::is_nothrow_move_assignable<string_type>::value) = default; // NOLINT(hicpp-noexcept-move,performance-noexcept-move-constructor,cppcoreguidelines-noexcept-move-operations)
~iteration_proxy_value() = default; ~iteration_proxy_value() = default;
/// dereference operator (needed for range-based for) /// dereference operator (needed for range-based for)
@@ -90,7 +84,7 @@ template<typename IteratorType> class iteration_proxy_value
return *this; return *this;
} }
iteration_proxy_value operator++(int)& // NOLINT(cert-dcl21-cpp) iteration_proxy_value operator++(int) & // NOLINT(cert-dcl21-cpp)
{ {
auto tmp = iteration_proxy_value(anchor, array_index); auto tmp = iteration_proxy_value(anchor, array_index);
++anchor; ++anchor;
@@ -122,7 +116,7 @@ template<typename IteratorType> class iteration_proxy_value
{ {
if (array_index != array_index_last) if (array_index != array_index_last)
{ {
int_to_string( array_index_str, array_index ); int_to_string(array_index_str, array_index);
array_index_last = array_index; array_index_last = array_index;
} }
return array_index_str; return array_index_str;
@@ -154,7 +148,8 @@ template<typename IteratorType> class iteration_proxy_value
}; };
/// proxy class for the items() function /// proxy class for the items() function
template<typename IteratorType> class iteration_proxy template<typename IteratorType>
class iteration_proxy
{ {
private: private:
/// the container to iterate /// the container to iterate
@@ -165,7 +160,8 @@ template<typename IteratorType> class iteration_proxy
/// construct iteration proxy from a container /// construct iteration proxy from a container
explicit iteration_proxy(typename IteratorType::reference cont) noexcept explicit iteration_proxy(typename IteratorType::reference cont) noexcept
: container(&cont) {} : container(&cont)
{}
iteration_proxy(iteration_proxy const&) = default; iteration_proxy(iteration_proxy const&) = default;
iteration_proxy& operator=(iteration_proxy const&) = default; iteration_proxy& operator=(iteration_proxy const&) = default;
@@ -210,8 +206,7 @@ NLOHMANN_JSON_NAMESPACE_END
// Structured Bindings Support to the iteration_proxy_value class // Structured Bindings Support to the iteration_proxy_value class
// For further reference see https://blog.tartanllama.xyz/structured-bindings/ // For further reference see https://blog.tartanllama.xyz/structured-bindings/
// And see https://github.com/nlohmann/json/pull/1391 // And see https://github.com/nlohmann/json/pull/1391
namespace std namespace std {
{
#if defined(__clang__) #if defined(__clang__)
// Fix: https://github.com/nlohmann/json/issues/1401 // Fix: https://github.com/nlohmann/json/issues/1401
@@ -219,16 +214,16 @@ namespace std
#pragma clang diagnostic ignored "-Wmismatched-tags" #pragma clang diagnostic ignored "-Wmismatched-tags"
#endif #endif
template<typename IteratorType> template<typename IteratorType>
class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> // NOLINT(cert-dcl58-cpp) class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> // NOLINT(cert-dcl58-cpp)
: public std::integral_constant<std::size_t, 2> {}; : public std::integral_constant<std::size_t, 2>
{};
template<std::size_t N, typename IteratorType> template<std::size_t N, typename IteratorType>
class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >> // NOLINT(cert-dcl58-cpp) class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType>> // NOLINT(cert-dcl58-cpp)
{ {
public: public:
using type = decltype( using type = decltype(get<N>(std::declval<
get<N>(std::declval < ::nlohmann::detail::iteration_proxy_value<IteratorType>>()));
::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));
}; };
#if defined(__clang__) #if defined(__clang__)
#pragma clang diagnostic pop #pragma clang diagnostic pop
@@ -237,6 +232,6 @@ class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>
} // namespace std } // namespace std
#if JSON_HAS_RANGES #if JSON_HAS_RANGES
template <typename IteratorType> template<typename IteratorType>
inline constexpr bool ::std::ranges::enable_borrowed_range<::nlohmann::detail::iteration_proxy<IteratorType>> = true; inline constexpr bool ::std::ranges::enable_borrowed_range<::nlohmann::detail::iteration_proxy<IteratorType>> = true;
#endif #endif
@@ -8,24 +8,23 @@
#pragma once #pragma once
#include <iterator> // random_access_iterator_tag #include <iterator> // random_access_iterator_tag
#include <nlohmann/detail/abi_macros.hpp> #include <nlohmann/detail/abi_macros.hpp>
#include <nlohmann/detail/meta/void_t.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp> #include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/meta/void_t.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
template<typename It, typename = void> template<typename It, typename = void>
struct iterator_types {}; struct iterator_types
{};
template<typename It> template<typename It>
struct iterator_types < struct iterator_types<
It, It,
void_t<typename It::difference_type, typename It::value_type, typename It::pointer, void_t<typename It::difference_type, typename It::value_type, typename It::pointer, typename It::reference, typename It::iterator_category>>
typename It::reference, typename It::iterator_category >>
{ {
using difference_type = typename It::difference_type; using difference_type = typename It::difference_type;
using value_type = typename It::value_type; using value_type = typename It::value_type;
@@ -42,8 +41,8 @@ struct iterator_traits
}; };
template<typename T> template<typename T>
struct iterator_traits < T, enable_if_t < !std::is_pointer<T>::value >> struct iterator_traits<T, enable_if_t<!std::is_pointer<T>::value>>
: iterator_types<T> : iterator_types<T>
{ {
}; };
@@ -8,15 +8,14 @@
#pragma once #pragma once
#include <cstddef> // ptrdiff_t #include <cstddef> // ptrdiff_t
#include <iterator> // reverse_iterator #include <iterator> // reverse_iterator
#include <utility> // declval #include <utility> // declval
#include <nlohmann/detail/abi_macros.hpp> #include <nlohmann/detail/abi_macros.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
////////////////////// //////////////////////
// reverse_iterator // // reverse_iterator //
@@ -52,13 +51,16 @@ class json_reverse_iterator : public std::reverse_iterator<Base>
/// create reverse iterator from iterator /// create reverse iterator from iterator
explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
: base_iterator(it) {} : base_iterator(it)
{}
/// create reverse iterator from base class /// create reverse iterator from base class
explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} explicit json_reverse_iterator(const base_iterator& it) noexcept
: base_iterator(it)
{}
/// post-increment (it++) /// post-increment (it++)
json_reverse_iterator operator++(int)& // NOLINT(cert-dcl21-cpp) json_reverse_iterator operator++(int) & // NOLINT(cert-dcl21-cpp)
{ {
return static_cast<json_reverse_iterator>(base_iterator::operator++(1)); return static_cast<json_reverse_iterator>(base_iterator::operator++(1));
} }
@@ -70,7 +72,7 @@ class json_reverse_iterator : public std::reverse_iterator<Base>
} }
/// post-decrement (it--) /// post-decrement (it--)
json_reverse_iterator operator--(int)& // NOLINT(cert-dcl21-cpp) json_reverse_iterator operator--(int) & // NOLINT(cert-dcl21-cpp)
{ {
return static_cast<json_reverse_iterator>(base_iterator::operator--(1)); return static_cast<json_reverse_iterator>(base_iterator::operator--(1));
} }
@@ -122,7 +124,7 @@ class json_reverse_iterator : public std::reverse_iterator<Base>
reference value() const reference value() const
{ {
auto it = --this->base(); auto it = --this->base();
return it.operator * (); return it.operator*();
} }
}; };
@@ -8,14 +8,13 @@
#pragma once #pragma once
#include <cstddef> // ptrdiff_t #include <cstddef> // ptrdiff_t
#include <limits> // numeric_limits #include <limits> // numeric_limits
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
/* /*
@brief an iterator for primitive JSON types @brief an iterator for primitive JSON types
@@ -33,9 +32,9 @@ class primitive_iterator_t
static constexpr difference_type begin_value = 0; static constexpr difference_type begin_value = 0;
static constexpr difference_type end_value = begin_value + 1; static constexpr difference_type end_value = begin_value + 1;
JSON_PRIVATE_UNLESS_TESTED: JSON_PRIVATE_UNLESS_TESTED :
/// iterator as signed integer type /// iterator as signed integer type
difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)(); difference_type m_it = (std::numeric_limits<std::ptrdiff_t>::min)();
public: public:
constexpr difference_type get_value() const noexcept constexpr difference_type get_value() const noexcept
@@ -95,7 +94,7 @@ class primitive_iterator_t
return *this; return *this;
} }
primitive_iterator_t operator++(int)& noexcept // NOLINT(cert-dcl21-cpp) primitive_iterator_t operator++(int) & noexcept // NOLINT(cert-dcl21-cpp)
{ {
auto result = *this; auto result = *this;
++m_it; ++m_it;
@@ -108,7 +107,7 @@ class primitive_iterator_t
return *this; return *this;
} }
primitive_iterator_t operator--(int)& noexcept // NOLINT(cert-dcl21-cpp) primitive_iterator_t operator--(int) & noexcept // NOLINT(cert-dcl21-cpp)
{ {
auto result = *this; auto result = *this;
--m_it; --m_it;
@@ -8,13 +8,12 @@
#pragma once #pragma once
#include <type_traits> // conditional, is_same #include <type_traits> // conditional, is_same
#include <nlohmann/detail/abi_macros.hpp> #include <nlohmann/detail/abi_macros.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
/*! /*!
@brief Default base class of the @ref basic_json class. @brief Default base class of the @ref basic_json class.
@@ -26,14 +25,14 @@ of @ref basic_json do not require complex case distinctions
By default, this class is used because it is empty and thus has no effect By default, this class is used because it is empty and thus has no effect
on the behavior of @ref basic_json. on the behavior of @ref basic_json.
*/ */
struct json_default_base {}; struct json_default_base
{};
template<class T> template<class T>
using json_base_class = typename std::conditional < using json_base_class = typename std::conditional<
std::is_same<T, void>::value, std::is_same<T, void>::value,
json_default_base, json_default_base,
T T>::type;
>::type;
} // namespace detail } // namespace detail
NLOHMANN_JSON_NAMESPACE_END NLOHMANN_JSON_NAMESPACE_END
+37 -46
View File
@@ -8,18 +8,18 @@
#pragma once #pragma once
#include <algorithm> // all_of #include <algorithm> // all_of
#include <cctype> // isdigit #include <cctype> // isdigit
#include <cerrno> // errno, ERANGE #include <cerrno> // errno, ERANGE
#include <cstdlib> // strtoull #include <cstdlib> // strtoull
#ifndef JSON_NO_IO #ifndef JSON_NO_IO
#include <iosfwd> // ostream #include <iosfwd> // ostream
#endif // JSON_NO_IO #endif // JSON_NO_IO
#include <limits> // max #include <limits> // max
#include <numeric> // accumulate #include <numeric> // accumulate
#include <string> // string #include <string> // string
#include <utility> // move #include <utility> // move
#include <vector> // vector #include <vector> // vector
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
@@ -60,17 +60,14 @@ class json_pointer
/// @brief create JSON pointer /// @brief create JSON pointer
/// @sa https://json.nlohmann.me/api/json_pointer/json_pointer/ /// @sa https://json.nlohmann.me/api/json_pointer/json_pointer/
explicit json_pointer(const string_t& s = "") explicit json_pointer(const string_t& s = "")
: reference_tokens(split(s)) : reference_tokens(split(s))
{} {}
/// @brief return a string representation of the JSON pointer /// @brief return a string representation of the JSON pointer
/// @sa https://json.nlohmann.me/api/json_pointer/to_string/ /// @sa https://json.nlohmann.me/api/json_pointer/to_string/
string_t to_string() const string_t to_string() const
{ {
return std::accumulate(reference_tokens.begin(), reference_tokens.end(), return std::accumulate(reference_tokens.begin(), reference_tokens.end(), string_t{}, [](const string_t& a, const string_t& b) {
string_t{},
[](const string_t& a, const string_t& b)
{
return detail::concat(a, '/', detail::escape(b)); return detail::concat(a, '/', detail::escape(b));
}); });
} }
@@ -128,7 +125,7 @@ class json_pointer
/// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer /// @brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer
/// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/ /// @sa https://json.nlohmann.me/api/json_pointer/operator_slash/
friend json_pointer operator/(const json_pointer& lhs, string_t token) // NOLINT(performance-unnecessary-value-param) friend json_pointer operator/(const json_pointer& lhs, string_t token) // NOLINT(performance-unnecessary-value-param)
{ {
return json_pointer(lhs) /= std::move(token); return json_pointer(lhs) /= std::move(token);
} }
@@ -229,11 +226,11 @@ class json_pointer
const char* p = s.c_str(); const char* p = s.c_str();
char* p_end = nullptr; char* p_end = nullptr;
errno = 0; // strtoull doesn't reset errno errno = 0; // strtoull doesn't reset errno
const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int) const unsigned long long res = std::strtoull(p, &p_end, 10); // NOLINT(runtime/int)
if (p == p_end // invalid input or empty string if (p == p_end // invalid input or empty string
|| errno == ERANGE // out of range || errno == ERANGE // out of range
|| JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(p_end - p) != s.size())) // incomplete read || JSON_HEDLEY_UNLIKELY(static_cast<std::size_t>(p_end - p) != s.size())) // incomplete read
{ {
JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr)); JSON_THROW(detail::out_of_range::create(404, detail::concat("unresolved reference token '", s, "'"), nullptr));
} }
@@ -242,14 +239,13 @@ class json_pointer
// https://github.com/nlohmann/json/pull/2203 // https://github.com/nlohmann/json/pull/2203
if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)())) // NOLINT(runtime/int) if (res >= static_cast<unsigned long long>((std::numeric_limits<size_type>::max)())) // NOLINT(runtime/int)
{ {
JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr)); // LCOV_EXCL_LINE JSON_THROW(detail::out_of_range::create(410, detail::concat("array index ", s, " exceeds size_type"), nullptr)); // LCOV_EXCL_LINE
} }
return static_cast<size_type>(res); return static_cast<size_type>(res);
} }
JSON_PRIVATE_UNLESS_TESTED: JSON_PRIVATE_UNLESS_TESTED : json_pointer top() const
json_pointer top() const
{ {
if (JSON_HEDLEY_UNLIKELY(empty())) if (JSON_HEDLEY_UNLIKELY(empty()))
{ {
@@ -360,16 +356,14 @@ class json_pointer
{ {
// check if reference token is a number // check if reference token is a number
const bool nums = const bool nums =
std::all_of(reference_token.begin(), reference_token.end(), std::all_of(reference_token.begin(), reference_token.end(), [](const unsigned char x) {
[](const unsigned char x) return std::isdigit(x);
{ });
return std::isdigit(x);
});
// change value to array for numbers or "-" or to object otherwise // change value to array for numbers or "-" or to object otherwise
*ptr = (nums || reference_token == "-") *ptr = (nums || reference_token == "-")
? detail::value_t::array ? detail::value_t::array
: detail::value_t::object; : detail::value_t::object;
} }
switch (ptr->type()) switch (ptr->type())
@@ -437,9 +431,7 @@ class json_pointer
if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
{ {
// "-" always fails the range check // "-" always fails the range check
JSON_THROW(detail::out_of_range::create(402, detail::concat( JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr));
"array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
") is out of range"), ptr));
} }
// note: at performs range check // note: at performs range check
@@ -544,9 +536,7 @@ class json_pointer
if (JSON_HEDLEY_UNLIKELY(reference_token == "-")) if (JSON_HEDLEY_UNLIKELY(reference_token == "-"))
{ {
// "-" always fails the range check // "-" always fails the range check
JSON_THROW(detail::out_of_range::create(402, detail::concat( JSON_THROW(detail::out_of_range::create(402, detail::concat("array index '-' (", std::to_string(ptr->m_data.m_value.array->size()), ") is out of range"), ptr));
"array index '-' (", std::to_string(ptr->m_data.m_value.array->size()),
") is out of range"), ptr));
} }
// note: at performs range check // note: at performs range check
@@ -685,14 +675,14 @@ class json_pointer
for ( for (
// search for the first slash after the first character // search for the first slash after the first character
std::size_t slash = reference_string.find_first_of('/', 1), std::size_t slash = reference_string.find_first_of('/', 1),
// set the beginning of the first reference token // set the beginning of the first reference token
start = 1; start = 1;
// we can stop if start == 0 (if slash == string_t::npos) // we can stop if start == 0 (if slash == string_t::npos)
start != 0; start != 0;
// set the beginning of the next reference token // set the beginning of the next reference token
// (will eventually be 0 if slash == string_t::npos) // (will eventually be 0 if slash == string_t::npos)
start = (slash == string_t::npos) ? 0 : slash + 1, start = (slash == string_t::npos) ? 0 : slash + 1,
// find next slash // find next slash
slash = reference_string.find_first_of('/', start)) slash = reference_string.find_first_of('/', start))
{ {
// use the text between the beginning of the reference token // use the text between the beginning of the reference token
@@ -701,8 +691,8 @@ class json_pointer
// check reference tokens are properly escaped // check reference tokens are properly escaped
for (std::size_t pos = reference_token.find_first_of('~'); for (std::size_t pos = reference_token.find_first_of('~');
pos != string_t::npos; pos != string_t::npos;
pos = reference_token.find_first_of('~', pos + 1)) pos = reference_token.find_first_of('~', pos + 1))
{ {
JSON_ASSERT(reference_token[pos] == '~'); JSON_ASSERT(reference_token[pos] == '~');
@@ -751,7 +741,8 @@ class json_pointer
for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i) for (std::size_t i = 0; i < value.m_data.m_value.array->size(); ++i)
{ {
flatten(detail::concat(reference_string, '/', std::to_string(i)), flatten(detail::concat(reference_string, '/', std::to_string(i)),
value.m_data.m_value.array->operator[](i), result); value.m_data.m_value.array->operator[](i),
result);
} }
} }
break; break;
@@ -839,7 +830,7 @@ class json_pointer
return result; return result;
} }
json_pointer<string_t> convert()&& json_pointer<string_t> convert() &&
{ {
json_pointer<string_t> result; json_pointer<string_t> result;
result.reference_tokens = std::move(reference_tokens); result.reference_tokens = std::move(reference_tokens);
@@ -866,9 +857,9 @@ class json_pointer
/// @brief 3-way compares two JSON pointers /// @brief 3-way compares two JSON pointers
template<typename RefStringTypeRhs> template<typename RefStringTypeRhs>
std::strong_ordering operator<=>(const json_pointer<RefStringTypeRhs>& rhs) const noexcept // *NOPAD* std::strong_ordering operator<= > (const json_pointer<RefStringTypeRhs>& rhs) const noexcept // *NOPAD*
{ {
return reference_tokens <=> rhs.reference_tokens; // *NOPAD* return reference_tokens <= > rhs.reference_tokens; // *NOPAD*
} }
#else #else
/// @brief compares two JSON pointers for equality /// @brief compares two JSON pointers for equality
+9 -10
View File
@@ -15,8 +15,7 @@
#include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/meta/type_traits.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
template<typename BasicJsonType> template<typename BasicJsonType>
class json_ref class json_ref
@@ -25,22 +24,22 @@ class json_ref
using value_type = BasicJsonType; using value_type = BasicJsonType;
json_ref(value_type&& value) json_ref(value_type&& value)
: owned_value(std::move(value)) : owned_value(std::move(value))
{} {}
json_ref(const value_type& value) json_ref(const value_type& value)
: value_ref(&value) : value_ref(&value)
{} {}
json_ref(std::initializer_list<json_ref> init) json_ref(std::initializer_list<json_ref> init)
: owned_value(init) : owned_value(init)
{} {}
template < template<
class... Args, class... Args,
enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0 > enable_if_t<std::is_constructible<value_type, Args...>::value, int> = 0>
json_ref(Args && ... args) json_ref(Args&&... args)
: owned_value(std::forward<Args>(args)...) : owned_value(std::forward<Args>(args)...)
{} {}
// class should be movable only // class should be movable only
@@ -66,7 +65,7 @@ class json_ref
value_type const* operator->() const value_type const* operator->() const
{ {
return &** this; return &**this;
} }
private: private:
+168 -137
View File
@@ -8,9 +8,9 @@
#pragma once #pragma once
#include <utility> // declval, pair
#include <nlohmann/detail/meta/detected.hpp> #include <nlohmann/detail/meta/detected.hpp>
#include <nlohmann/thirdparty/hedley/hedley.hpp> #include <nlohmann/thirdparty/hedley/hedley.hpp>
#include <utility> // declval, pair
// This file contains all internal macro definitions (except those affecting ABI) // This file contains all internal macro definitions (except those affecting ABI)
// You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them // You MUST include macro_unscope.hpp at the end of json.hpp to undef all of them
@@ -37,7 +37,7 @@
#define JSON_HAS_CPP_20 #define JSON_HAS_CPP_20
#define JSON_HAS_CPP_17 #define JSON_HAS_CPP_17
#define JSON_HAS_CPP_14 #define JSON_HAS_CPP_14
#elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464 #elif (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
#define JSON_HAS_CPP_17 #define JSON_HAS_CPP_17
#define JSON_HAS_CPP_14 #define JSON_HAS_CPP_14
#elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1) #elif (defined(__cplusplus) && __cplusplus >= 201402L) || (defined(_HAS_CXX14) && _HAS_CXX14 == 1)
@@ -114,8 +114,7 @@
#endif #endif
#ifndef JSON_HAS_THREE_WAY_COMPARISON #ifndef JSON_HAS_THREE_WAY_COMPARISON
#if 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
&& defined(__cpp_lib_three_way_comparison) && __cpp_lib_three_way_comparison >= 201907L
#define JSON_HAS_THREE_WAY_COMPARISON 1 #define JSON_HAS_THREE_WAY_COMPARISON 1
#else #else
#define JSON_HAS_THREE_WAY_COMPARISON 0 #define JSON_HAS_THREE_WAY_COMPARISON 0
@@ -164,14 +163,14 @@
#if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION) #if (defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)) && !defined(JSON_NOEXCEPTION)
#define JSON_THROW(exception) throw exception #define JSON_THROW(exception) throw exception
#define JSON_TRY try #define JSON_TRY try
#define JSON_CATCH(exception) catch(exception) #define JSON_CATCH(exception) catch (exception)
#define JSON_INTERNAL_CATCH(exception) catch(exception) #define JSON_INTERNAL_CATCH(exception) catch (exception)
#else #else
#include <cstdlib> #include <cstdlib>
#define JSON_THROW(exception) std::abort() #define JSON_THROW(exception) std::abort()
#define JSON_TRY if(true) #define JSON_TRY if (true)
#define JSON_CATCH(exception) if(false) #define JSON_CATCH(exception) if (false)
#define JSON_INTERNAL_CATCH(exception) if(false) #define JSON_INTERNAL_CATCH(exception) if (false)
#endif #endif
// override exception macros // override exception macros
@@ -196,7 +195,7 @@
// allow overriding assert // allow overriding assert
#if !defined(JSON_ASSERT) #if !defined(JSON_ASSERT)
#include <cassert> // assert #include <cassert> // assert
#define JSON_ASSERT(x) assert(x) #define JSON_ASSERT(x) assert(x)
#endif #endif
@@ -212,119 +211,119 @@
@def NLOHMANN_JSON_SERIALIZE_ENUM @def NLOHMANN_JSON_SERIALIZE_ENUM
@since version 3.4.0 @since version 3.4.0
*/ */
#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ #define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \
template<typename BasicJsonType> \ template<typename BasicJsonType> \
inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \
{ \ { \
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \ static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \ static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
auto it = std::find_if(std::begin(m), std::end(m), \ auto it = std::find_if(std::begin(m), std::end(m), [e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool { \
[e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \ return ej_pair.first == e; \
{ \ }); \
return ej_pair.first == e; \ j = ((it != std::end(m)) ? it : std::begin(m))->second; \
}); \ } \
j = ((it != std::end(m)) ? it : std::begin(m))->second; \ template<typename BasicJsonType> \
} \ inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \
template<typename BasicJsonType> \ { \
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \
{ \ static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \ auto it = std::find_if(std::begin(m), std::end(m), [&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool { \
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \ return ej_pair.second == j; \
auto it = std::find_if(std::begin(m), std::end(m), \ }); \
[&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \ e = ((it != std::end(m)) ? it : std::begin(m))->first; \
{ \
return ej_pair.second == j; \
}); \
e = ((it != std::end(m)) ? it : std::begin(m))->first; \
} }
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They // Ugly macros to avoid uglier copy-paste when specializing basic_json. They
// may be removed in the future once the class is split. // may be removed in the future once the class is split.
#define NLOHMANN_BASIC_JSON_TPL_DECLARATION \ #define NLOHMANN_BASIC_JSON_TPL_DECLARATION \
template<template<typename, typename, typename...> class ObjectType, \ template<template<typename, typename, typename...> class ObjectType, \
template<typename, typename...> class ArrayType, \ template<typename, typename...> \
class StringType, class BooleanType, class NumberIntegerType, \ class ArrayType, \
class NumberUnsignedType, class NumberFloatType, \ class StringType, \
template<typename> class AllocatorType, \ class BooleanType, \
template<typename, typename = void> class JSONSerializer, \ class NumberIntegerType, \
class BinaryType, \ class NumberUnsignedType, \
class NumberFloatType, \
template<typename> \
class AllocatorType, \
template<typename, typename = void> \
class JSONSerializer, \
class BinaryType, \
class CustomBaseClass> class CustomBaseClass>
#define NLOHMANN_BASIC_JSON_TPL \ #define NLOHMANN_BASIC_JSON_TPL \
basic_json<ObjectType, ArrayType, StringType, BooleanType, \ basic_json<ObjectType, ArrayType, StringType, BooleanType, NumberIntegerType, NumberUnsignedType, NumberFloatType, AllocatorType, JSONSerializer, BinaryType, CustomBaseClass>
NumberIntegerType, NumberUnsignedType, NumberFloatType, \
AllocatorType, JSONSerializer, BinaryType, CustomBaseClass>
// Macros to simplify conversion from/to types // Macros to simplify conversion from/to types
#define NLOHMANN_JSON_EXPAND( x ) x #define NLOHMANN_JSON_EXPAND(x) x
#define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME,...) NAME #define NLOHMANN_JSON_GET_MACRO(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, NAME, ...) NAME
#define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \ #define NLOHMANN_JSON_PASTE(...) NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_GET_MACRO(__VA_ARGS__, \
NLOHMANN_JSON_PASTE64, \ NLOHMANN_JSON_PASTE64, \
NLOHMANN_JSON_PASTE63, \ NLOHMANN_JSON_PASTE63, \
NLOHMANN_JSON_PASTE62, \ NLOHMANN_JSON_PASTE62, \
NLOHMANN_JSON_PASTE61, \ NLOHMANN_JSON_PASTE61, \
NLOHMANN_JSON_PASTE60, \ NLOHMANN_JSON_PASTE60, \
NLOHMANN_JSON_PASTE59, \ NLOHMANN_JSON_PASTE59, \
NLOHMANN_JSON_PASTE58, \ NLOHMANN_JSON_PASTE58, \
NLOHMANN_JSON_PASTE57, \ NLOHMANN_JSON_PASTE57, \
NLOHMANN_JSON_PASTE56, \ NLOHMANN_JSON_PASTE56, \
NLOHMANN_JSON_PASTE55, \ NLOHMANN_JSON_PASTE55, \
NLOHMANN_JSON_PASTE54, \ NLOHMANN_JSON_PASTE54, \
NLOHMANN_JSON_PASTE53, \ NLOHMANN_JSON_PASTE53, \
NLOHMANN_JSON_PASTE52, \ NLOHMANN_JSON_PASTE52, \
NLOHMANN_JSON_PASTE51, \ NLOHMANN_JSON_PASTE51, \
NLOHMANN_JSON_PASTE50, \ NLOHMANN_JSON_PASTE50, \
NLOHMANN_JSON_PASTE49, \ NLOHMANN_JSON_PASTE49, \
NLOHMANN_JSON_PASTE48, \ NLOHMANN_JSON_PASTE48, \
NLOHMANN_JSON_PASTE47, \ NLOHMANN_JSON_PASTE47, \
NLOHMANN_JSON_PASTE46, \ NLOHMANN_JSON_PASTE46, \
NLOHMANN_JSON_PASTE45, \ NLOHMANN_JSON_PASTE45, \
NLOHMANN_JSON_PASTE44, \ NLOHMANN_JSON_PASTE44, \
NLOHMANN_JSON_PASTE43, \ NLOHMANN_JSON_PASTE43, \
NLOHMANN_JSON_PASTE42, \ NLOHMANN_JSON_PASTE42, \
NLOHMANN_JSON_PASTE41, \ NLOHMANN_JSON_PASTE41, \
NLOHMANN_JSON_PASTE40, \ NLOHMANN_JSON_PASTE40, \
NLOHMANN_JSON_PASTE39, \ NLOHMANN_JSON_PASTE39, \
NLOHMANN_JSON_PASTE38, \ NLOHMANN_JSON_PASTE38, \
NLOHMANN_JSON_PASTE37, \ NLOHMANN_JSON_PASTE37, \
NLOHMANN_JSON_PASTE36, \ NLOHMANN_JSON_PASTE36, \
NLOHMANN_JSON_PASTE35, \ NLOHMANN_JSON_PASTE35, \
NLOHMANN_JSON_PASTE34, \ NLOHMANN_JSON_PASTE34, \
NLOHMANN_JSON_PASTE33, \ NLOHMANN_JSON_PASTE33, \
NLOHMANN_JSON_PASTE32, \ NLOHMANN_JSON_PASTE32, \
NLOHMANN_JSON_PASTE31, \ NLOHMANN_JSON_PASTE31, \
NLOHMANN_JSON_PASTE30, \ NLOHMANN_JSON_PASTE30, \
NLOHMANN_JSON_PASTE29, \ NLOHMANN_JSON_PASTE29, \
NLOHMANN_JSON_PASTE28, \ NLOHMANN_JSON_PASTE28, \
NLOHMANN_JSON_PASTE27, \ NLOHMANN_JSON_PASTE27, \
NLOHMANN_JSON_PASTE26, \ NLOHMANN_JSON_PASTE26, \
NLOHMANN_JSON_PASTE25, \ NLOHMANN_JSON_PASTE25, \
NLOHMANN_JSON_PASTE24, \ NLOHMANN_JSON_PASTE24, \
NLOHMANN_JSON_PASTE23, \ NLOHMANN_JSON_PASTE23, \
NLOHMANN_JSON_PASTE22, \ NLOHMANN_JSON_PASTE22, \
NLOHMANN_JSON_PASTE21, \ NLOHMANN_JSON_PASTE21, \
NLOHMANN_JSON_PASTE20, \ NLOHMANN_JSON_PASTE20, \
NLOHMANN_JSON_PASTE19, \ NLOHMANN_JSON_PASTE19, \
NLOHMANN_JSON_PASTE18, \ NLOHMANN_JSON_PASTE18, \
NLOHMANN_JSON_PASTE17, \ NLOHMANN_JSON_PASTE17, \
NLOHMANN_JSON_PASTE16, \ NLOHMANN_JSON_PASTE16, \
NLOHMANN_JSON_PASTE15, \ NLOHMANN_JSON_PASTE15, \
NLOHMANN_JSON_PASTE14, \ NLOHMANN_JSON_PASTE14, \
NLOHMANN_JSON_PASTE13, \ NLOHMANN_JSON_PASTE13, \
NLOHMANN_JSON_PASTE12, \ NLOHMANN_JSON_PASTE12, \
NLOHMANN_JSON_PASTE11, \ NLOHMANN_JSON_PASTE11, \
NLOHMANN_JSON_PASTE10, \ NLOHMANN_JSON_PASTE10, \
NLOHMANN_JSON_PASTE9, \ NLOHMANN_JSON_PASTE9, \
NLOHMANN_JSON_PASTE8, \ NLOHMANN_JSON_PASTE8, \
NLOHMANN_JSON_PASTE7, \ NLOHMANN_JSON_PASTE7, \
NLOHMANN_JSON_PASTE6, \ NLOHMANN_JSON_PASTE6, \
NLOHMANN_JSON_PASTE5, \ NLOHMANN_JSON_PASTE5, \
NLOHMANN_JSON_PASTE4, \ NLOHMANN_JSON_PASTE4, \
NLOHMANN_JSON_PASTE3, \ NLOHMANN_JSON_PASTE3, \
NLOHMANN_JSON_PASTE2, \ NLOHMANN_JSON_PASTE2, \
NLOHMANN_JSON_PASTE1)(__VA_ARGS__)) NLOHMANN_JSON_PASTE1)(__VA_ARGS__))
#define NLOHMANN_JSON_PASTE2(func, v1) func(v1) #define NLOHMANN_JSON_PASTE2(func, v1) func(v1)
#define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2) #define NLOHMANN_JSON_PASTE3(func, v1, v2) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE2(func, v2)
#define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3) #define NLOHMANN_JSON_PASTE4(func, v1, v2, v3) NLOHMANN_JSON_PASTE2(func, v1) NLOHMANN_JSON_PASTE3(func, v2, v3)
@@ -398,32 +397,64 @@
@def NLOHMANN_DEFINE_TYPE_INTRUSIVE @def NLOHMANN_DEFINE_TYPE_INTRUSIVE
@since version 3.9.0 @since version 3.9.0
*/ */
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \ #define NLOHMANN_DEFINE_TYPE_INTRUSIVE(Type, ...) \
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) \
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } { \
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) \
} \
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) \
{ \
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) \
}
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \ #define NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(Type, ...) \
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) \
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } { \
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) \
} \
friend void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) \
{ \
const Type nlohmann_json_default_obj{}; \
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) \
}
#define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ #define NLOHMANN_DEFINE_TYPE_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } friend void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) \
{ \
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) \
}
/*! /*!
@brief macro @brief macro
@def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE @def NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE
@since version 3.9.0 @since version 3.9.0
*/ */
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \ #define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(Type, ...) \
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) \
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) } { \
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) \
} \
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) \
{ \
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM, __VA_ARGS__)) \
}
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \ #define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_ONLY_SERIALIZE(Type, ...) \
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) \
{ \
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) \
}
#define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \ #define NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(Type, ...) \
inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) { NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) } \ inline void to_json(nlohmann::json& nlohmann_json_j, const Type& nlohmann_json_t) \
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) { const Type nlohmann_json_default_obj{}; NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) } { \
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_TO, __VA_ARGS__)) \
} \
inline void from_json(const nlohmann::json& nlohmann_json_j, Type& nlohmann_json_t) \
{ \
const Type nlohmann_json_default_obj{}; \
NLOHMANN_JSON_EXPAND(NLOHMANN_JSON_PASTE(NLOHMANN_JSON_FROM_WITH_DEFAULT, __VA_ARGS__)) \
}
// inspired from https://stackoverflow.com/a/26745591 // inspired from https://stackoverflow.com/a/26745591
// allows to call any std function as if (e.g. with begin): // allows to call any std function as if (e.g. with begin):
@@ -434,30 +465,30 @@
#define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \ #define NLOHMANN_CAN_CALL_STD_FUNC_IMPL(std_name) \
namespace detail { \ namespace detail { \
using std::std_name; \ using std::std_name; \
\ \
template<typename... T> \ template<typename... T> \
using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \ using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \
} \ } \
\ \
namespace detail2 { \ namespace detail2 { \
struct std_name##_tag \ struct std_name##_tag \
{ \ { \
}; \ }; \
\ \
template<typename... T> \ template<typename... T> \
std_name##_tag std_name(T&&...); \ std_name##_tag std_name(T&&...); \
\ \
template<typename... T> \ template<typename... T> \
using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \ using result_of_##std_name = decltype(std_name(std::declval<T>()...)); \
\ \
template<typename... T> \ template<typename... T> \
struct would_call_std_##std_name \ struct would_call_std_##std_name \
{ \ { \
static constexpr auto const value = ::nlohmann::detail:: \ static constexpr auto const value = ::nlohmann::detail:: \
is_detected_exact<std_name##_tag, result_of_##std_name, T...>::value; \ is_detected_exact<std_name##_tag, result_of_##std_name, T...>::value; \
}; \ }; \
} /* namespace detail2 */ \ } /* namespace detail2 */ \
\ \
template<typename... T> \ template<typename... T> \
struct would_call_std_##std_name : detail2::would_call_std_##std_name<T...> \ struct would_call_std_##std_name : detail2::would_call_std_##std_name<T...> \
{ \ { \
+30 -28
View File
@@ -9,16 +9,15 @@
#pragma once #pragma once
#include <array> // array #include <array> // array
#include <cstddef> // size_t #include <cstddef> // size_t
#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type #include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
#include <utility> // index_sequence, make_index_sequence, index_sequence_for #include <utility> // index_sequence, make_index_sequence, index_sequence_for
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
template<typename T> template<typename T>
using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type; using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
@@ -28,8 +27,8 @@ using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::typ
// the following utilities are natively available in C++14 // the following utilities are natively available in C++14
using std::enable_if_t; using std::enable_if_t;
using std::index_sequence; using std::index_sequence;
using std::make_index_sequence;
using std::index_sequence_for; using std::index_sequence_for;
using std::make_index_sequence;
#else #else
@@ -61,7 +60,7 @@ using enable_if_t = typename std::enable_if<B, T>::type;
// // will be deduced to `0, 1, 2, 3, 4`. // // will be deduced to `0, 1, 2, 3, 4`.
// user_function(make_integer_sequence<int, 5>()); // user_function(make_integer_sequence<int, 5>());
// } // }
template <typename T, T... Ints> template<typename T, T... Ints>
struct integer_sequence struct integer_sequence
{ {
using value_type = T; using value_type = T;
@@ -76,38 +75,37 @@ struct integer_sequence
// A helper template for an `integer_sequence` of `size_t`, // A helper template for an `integer_sequence` of `size_t`,
// `absl::index_sequence` is designed to be a drop-in replacement for C++14's // `absl::index_sequence` is designed to be a drop-in replacement for C++14's
// `std::index_sequence`. // `std::index_sequence`.
template <size_t... Ints> template<size_t... Ints>
using index_sequence = integer_sequence<size_t, Ints...>; using index_sequence = integer_sequence<size_t, Ints...>;
namespace utility_internal namespace utility_internal {
{
template <typename Seq, size_t SeqSize, size_t Rem> template<typename Seq, size_t SeqSize, size_t Rem>
struct Extend; struct Extend;
// Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency. // Note that SeqSize == sizeof...(Ints). It's passed explicitly for efficiency.
template <typename T, T... Ints, size_t SeqSize> template<typename T, T... Ints, size_t SeqSize>
struct Extend<integer_sequence<T, Ints...>, SeqSize, 0> struct Extend<integer_sequence<T, Ints...>, SeqSize, 0>
{ {
using type = integer_sequence < T, Ints..., (Ints + SeqSize)... >; using type = integer_sequence<T, Ints..., (Ints + SeqSize)...>;
}; };
template <typename T, T... Ints, size_t SeqSize> template<typename T, T... Ints, size_t SeqSize>
struct Extend<integer_sequence<T, Ints...>, SeqSize, 1> struct Extend<integer_sequence<T, Ints...>, SeqSize, 1>
{ {
using type = integer_sequence < T, Ints..., (Ints + SeqSize)..., 2 * SeqSize >; using type = integer_sequence<T, Ints..., (Ints + SeqSize)..., 2 * SeqSize>;
}; };
// Recursion helper for 'make_integer_sequence<T, N>'. // Recursion helper for 'make_integer_sequence<T, N>'.
// 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'. // 'Gen<T, N>::type' is an alias for 'integer_sequence<T, 0, 1, ... N-1>'.
template <typename T, size_t N> template<typename T, size_t N>
struct Gen struct Gen
{ {
using type = using type =
typename Extend < typename Gen < T, N / 2 >::type, N / 2, N % 2 >::type; typename Extend<typename Gen<T, N / 2>::type, N / 2, N % 2>::type;
}; };
template <typename T> template<typename T>
struct Gen<T, 0> struct Gen<T, 0>
{ {
using type = integer_sequence<T>; using type = integer_sequence<T>;
@@ -122,7 +120,7 @@ struct Gen<T, 0>
// This template alias is equivalent to // This template alias is equivalent to
// `integer_sequence<int, 0, 1, ..., N-1>`, and is designed to be a drop-in // `integer_sequence<int, 0, 1, ..., N-1>`, and is designed to be a drop-in
// replacement for C++14's `std::make_integer_sequence`. // replacement for C++14's `std::make_integer_sequence`.
template <typename T, T N> template<typename T, T N>
using make_integer_sequence = typename utility_internal::Gen<T, N>::type; using make_integer_sequence = typename utility_internal::Gen<T, N>::type;
// make_index_sequence // make_index_sequence
@@ -130,7 +128,7 @@ using make_integer_sequence = typename utility_internal::Gen<T, N>::type;
// This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`, // This template alias is equivalent to `index_sequence<0, 1, ..., N-1>`,
// and is designed to be a drop-in replacement for C++14's // and is designed to be a drop-in replacement for C++14's
// `std::make_index_sequence`. // `std::make_index_sequence`.
template <size_t N> template<size_t N>
using make_index_sequence = make_integer_sequence<size_t, N>; using make_index_sequence = make_integer_sequence<size_t, N>;
// index_sequence_for // index_sequence_for
@@ -138,7 +136,7 @@ using make_index_sequence = make_integer_sequence<size_t, N>;
// Converts a typename pack into an index sequence of the same length, and // Converts a typename pack into an index sequence of the same length, and
// is designed to be a drop-in replacement for C++14's // is designed to be a drop-in replacement for C++14's
// `std::index_sequence_for()` // `std::index_sequence_for()`
template <typename... Ts> template<typename... Ts>
using index_sequence_for = make_index_sequence<sizeof...(Ts)>; using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
//// END OF CODE FROM GOOGLE ABSEIL //// END OF CODE FROM GOOGLE ABSEIL
@@ -146,8 +144,12 @@ using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
#endif #endif
// dispatch utility (taken from ranges-v3) // dispatch utility (taken from ranges-v3)
template<unsigned N> struct priority_tag : priority_tag < N - 1 > {}; template<unsigned N>
template<> struct priority_tag<0> {}; struct priority_tag : priority_tag<N - 1>
{};
template<>
struct priority_tag<0>
{};
// taken from ranges-v3 // taken from ranges-v3
template<typename T> template<typename T>
@@ -157,14 +159,14 @@ struct static_const
}; };
#ifndef JSON_HAS_CPP_17 #ifndef JSON_HAS_CPP_17
template<typename T> template<typename T>
constexpr T static_const<T>::value; constexpr T static_const<T>::value;
#endif #endif
template<typename T, typename... Args> template<typename T, typename... Args>
inline constexpr std::array<T, sizeof...(Args)> make_array(Args&& ... args) inline constexpr std::array<T, sizeof...(Args)> make_array(Args&&... args)
{ {
return std::array<T, sizeof...(Args)> {{static_cast<T>(std::forward<Args>(args))...}}; return std::array<T, sizeof...(Args)>{{static_cast<T>(std::forward<Args>(args))...}};
} }
} // namespace detail } // namespace detail
+5 -4
View File
@@ -13,8 +13,7 @@
#include <nlohmann/detail/meta/void_t.hpp> #include <nlohmann/detail/meta/void_t.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
// https://en.cppreference.com/w/cpp/experimental/is_detected // https://en.cppreference.com/w/cpp/experimental/is_detected
struct nonesuch struct nonesuch
@@ -29,7 +28,8 @@ struct nonesuch
template<class Default, template<class Default,
class AlwaysVoid, class AlwaysVoid,
template<class...> class Op, template<class...>
class Op,
class... Args> class... Args>
struct detector struct detector
{ {
@@ -48,7 +48,8 @@ template<template<class...> class Op, class... Args>
using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t; using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;
template<template<class...> class Op, class... Args> template<template<class...> class Op, class... Args>
struct is_detected_lazy : is_detected<Op, Args...> { }; struct is_detected_lazy : is_detected<Op, Args...>
{};
template<template<class...> class Op, class... Args> template<template<class...> class Op, class... Args>
using detected_t = typename detector<nonesuch, void, Op, Args...>::type; using detected_t = typename detector<nonesuch, void, Op, Args...>::type;
@@ -11,11 +11,12 @@
#include <nlohmann/detail/abi_macros.hpp> #include <nlohmann/detail/abi_macros.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
// dispatching helper struct // dispatching helper struct
template <class T> struct identity_tag {}; template<class T>
struct identity_tag
{};
} // namespace detail } // namespace detail
NLOHMANN_JSON_NAMESPACE_END NLOHMANN_JSON_NAMESPACE_END
+12 -14
View File
@@ -8,17 +8,16 @@
#pragma once #pragma once
#include <cstdint> // size_t #include <cstdint> // size_t
#include <utility> // declval #include <string> // string
#include <string> // string #include <utility> // declval
#include <nlohmann/detail/abi_macros.hpp> #include <nlohmann/detail/abi_macros.hpp>
#include <nlohmann/detail/meta/detected.hpp> #include <nlohmann/detail/meta/detected.hpp>
#include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/meta/type_traits.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
template<typename T> template<typename T>
using null_function_t = decltype(std::declval<T&>().null()); using null_function_t = decltype(std::declval<T&>().null());
@@ -37,7 +36,8 @@ using number_unsigned_function_t =
template<typename T, typename Float, typename String> template<typename T, typename Float, typename String>
using number_float_function_t = decltype(std::declval<T&>().number_float( using number_float_function_t = decltype(std::declval<T&>().number_float(
std::declval<Float>(), std::declval<const String&>())); std::declval<Float>(),
std::declval<const String&>()));
template<typename T, typename String> template<typename T, typename String>
using string_function_t = using string_function_t =
@@ -67,8 +67,9 @@ using end_array_function_t = decltype(std::declval<T&>().end_array());
template<typename T, typename Exception> template<typename T, typename Exception>
using parse_error_function_t = decltype(std::declval<T&>().parse_error( using parse_error_function_t = decltype(std::declval<T&>().parse_error(
std::declval<std::size_t>(), std::declval<const std::string&>(), std::declval<std::size_t>(),
std::declval<const Exception&>())); std::declval<const std::string&>(),
std::declval<const Exception&>()));
template<typename SAX, typename BasicJsonType> template<typename SAX, typename BasicJsonType>
struct is_sax struct is_sax
@@ -123,15 +124,12 @@ struct is_sax_static_asserts
static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value, static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
"Missing/invalid function: bool boolean(bool)"); "Missing/invalid function: bool boolean(bool)");
static_assert( static_assert(
is_detected_exact<bool, number_integer_function_t, SAX, is_detected_exact<bool, number_integer_function_t, SAX, number_integer_t>::value,
number_integer_t>::value,
"Missing/invalid function: bool number_integer(number_integer_t)"); "Missing/invalid function: bool number_integer(number_integer_t)");
static_assert( static_assert(
is_detected_exact<bool, number_unsigned_function_t, SAX, is_detected_exact<bool, number_unsigned_function_t, SAX, number_unsigned_t>::value,
number_unsigned_t>::value,
"Missing/invalid function: bool number_unsigned(number_unsigned_t)"); "Missing/invalid function: bool number_unsigned(number_unsigned_t)");
static_assert(is_detected_exact<bool, number_float_function_t, SAX, static_assert(is_detected_exact<bool, number_float_function_t, SAX, number_float_t, string_t>::value,
number_float_t, string_t>::value,
"Missing/invalid function: bool number_float(number_float_t, const string_t&)"); "Missing/invalid function: bool number_float(number_float_t, const string_t&)");
static_assert( static_assert(
is_detected_exact<bool, string_function_t, SAX, string_t>::value, is_detected_exact<bool, string_function_t, SAX, string_t>::value,
+4 -6
View File
@@ -11,18 +11,16 @@
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
#if JSON_HAS_EXPERIMENTAL_FILESYSTEM #if JSON_HAS_EXPERIMENTAL_FILESYSTEM
#include <experimental/filesystem> #include <experimental/filesystem>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
namespace std_fs = std::experimental::filesystem; namespace std_fs = std::experimental::filesystem;
} // namespace detail } // namespace detail
NLOHMANN_JSON_NAMESPACE_END NLOHMANN_JSON_NAMESPACE_END
#elif JSON_HAS_FILESYSTEM #elif JSON_HAS_FILESYSTEM
#include <filesystem> #include <filesystem>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
namespace std_fs = std::filesystem; namespace std_fs = std::filesystem;
} // namespace detail } // namespace detail
NLOHMANN_JSON_NAMESPACE_END NLOHMANN_JSON_NAMESPACE_END
+250 -210
View File
@@ -8,11 +8,11 @@
#pragma once #pragma once
#include <limits> // numeric_limits #include <limits> // numeric_limits
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type #include <string> // char_traits
#include <utility> // declval #include <tuple> // tuple
#include <tuple> // tuple #include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
#include <string> // char_traits #include <utility> // declval
#include <nlohmann/detail/iterators/iterator_traits.hpp> #include <nlohmann/detail/iterators/iterator_traits.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
@@ -31,8 +31,7 @@ implementations of some @ref basic_json methods, and meta-programming helpers.
@since version 2.1.0 @since version 2.1.0
*/ */
namespace detail namespace detail {
{
///////////// /////////////
// helpers // // helpers //
@@ -47,19 +46,20 @@ namespace detail
// In this case, T has to be properly CV-qualified to constraint the function arguments // In this case, T has to be properly CV-qualified to constraint the function arguments
// (e.g. to_json(BasicJsonType&, const T&)) // (e.g. to_json(BasicJsonType&, const T&))
template<typename> struct is_basic_json : std::false_type {}; template<typename>
struct is_basic_json : std::false_type
{};
NLOHMANN_BASIC_JSON_TPL_DECLARATION NLOHMANN_BASIC_JSON_TPL_DECLARATION
struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {}; struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type
{};
// used by exceptions create() member functions // used by exceptions create() member functions
// true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t // true_type for pointer to possibly cv-qualified basic_json or std::nullptr_t
// false_type otherwise // false_type otherwise
template<typename BasicJsonContext> template<typename BasicJsonContext>
struct is_basic_json_context : struct is_basic_json_context : std::integral_constant<bool,
std::integral_constant < bool, is_basic_json<typename std::remove_cv<typename std::remove_pointer<BasicJsonContext>::type>::type>::value || std::is_same<BasicJsonContext, std::nullptr_t>::value>
is_basic_json<typename std::remove_cv<typename std::remove_pointer<BasicJsonContext>::type>::type>::value
|| std::is_same<BasicJsonContext, std::nullptr_t>::value >
{}; {};
////////////////////// //////////////////////
@@ -70,10 +70,12 @@ template<typename>
class json_ref; class json_ref;
template<typename> template<typename>
struct is_json_ref : std::false_type {}; struct is_json_ref : std::false_type
{};
template<typename T> template<typename T>
struct is_json_ref<json_ref<T>> : std::true_type {}; struct is_json_ref<json_ref<T>> : std::true_type
{};
////////////////////////// //////////////////////////
// aliases for detected // // aliases for detected //
@@ -111,63 +113,64 @@ using get_template_function = decltype(std::declval<T>().template get<U>());
// trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists // trait checking if JSONSerializer<T>::from_json(json const&, udt&) exists
template<typename BasicJsonType, typename T, typename = void> template<typename BasicJsonType, typename T, typename = void>
struct has_from_json : std::false_type {}; struct has_from_json : std::false_type
{};
// trait checking if j.get<T> is valid // trait checking if j.get<T> is valid
// use this trait instead of std::is_constructible or std::is_convertible, // use this trait instead of std::is_constructible or std::is_convertible,
// both rely on, or make use of implicit conversions, and thus fail when T // both rely on, or make use of implicit conversions, and thus fail when T
// has several constructors/operator= (see https://github.com/nlohmann/json/issues/958) // has several constructors/operator= (see https://github.com/nlohmann/json/issues/958)
template <typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct is_getable struct is_getable
{ {
static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value; static constexpr bool value = is_detected<get_template_function, const BasicJsonType&, T>::value;
}; };
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct has_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >> struct has_from_json<BasicJsonType, T, enable_if_t<!is_basic_json<T>::value>>
{ {
using serializer = typename BasicJsonType::template json_serializer<T, void>; using serializer = typename BasicJsonType::template json_serializer<T, void>;
static constexpr bool value = static constexpr bool value =
is_detected_exact<void, from_json_function, serializer, is_detected_exact<void, from_json_function, serializer, const BasicJsonType&, T&>::value;
const BasicJsonType&, T&>::value;
}; };
// This trait checks if JSONSerializer<T>::from_json(json const&) exists // This trait checks if JSONSerializer<T>::from_json(json const&) exists
// this overload is used for non-default-constructible user-defined-types // this overload is used for non-default-constructible user-defined-types
template<typename BasicJsonType, typename T, typename = void> template<typename BasicJsonType, typename T, typename = void>
struct has_non_default_from_json : std::false_type {}; struct has_non_default_from_json : std::false_type
{};
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct has_non_default_from_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >> struct has_non_default_from_json<BasicJsonType, T, enable_if_t<!is_basic_json<T>::value>>
{ {
using serializer = typename BasicJsonType::template json_serializer<T, void>; using serializer = typename BasicJsonType::template json_serializer<T, void>;
static constexpr bool value = static constexpr bool value =
is_detected_exact<T, from_json_function, serializer, is_detected_exact<T, from_json_function, serializer, const BasicJsonType&>::value;
const BasicJsonType&>::value;
}; };
// This trait checks if BasicJsonType::json_serializer<T>::to_json exists // This trait checks if BasicJsonType::json_serializer<T>::to_json exists
// Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion. // Do not evaluate the trait when T is a basic_json type, to avoid template instantiation infinite recursion.
template<typename BasicJsonType, typename T, typename = void> template<typename BasicJsonType, typename T, typename = void>
struct has_to_json : std::false_type {}; struct has_to_json : std::false_type
{};
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct has_to_json < BasicJsonType, T, enable_if_t < !is_basic_json<T>::value >> struct has_to_json<BasicJsonType, T, enable_if_t<!is_basic_json<T>::value>>
{ {
using serializer = typename BasicJsonType::template json_serializer<T, void>; using serializer = typename BasicJsonType::template json_serializer<T, void>;
static constexpr bool value = static constexpr bool value =
is_detected_exact<void, to_json_function, serializer, BasicJsonType&, is_detected_exact<void, to_json_function, serializer, BasicJsonType&, T>::value;
T>::value;
}; };
template<typename T> template<typename T>
using detect_key_compare = typename T::key_compare; using detect_key_compare = typename T::key_compare;
template<typename T> template<typename T>
struct has_key_compare : std::integral_constant<bool, is_detected<detect_key_compare, T>::value> {}; struct has_key_compare : std::integral_constant<bool, is_detected<detect_key_compare, T>::value>
{};
// obtains the actual object key comparator // obtains the actual object key comparator
template<typename BasicJsonType> template<typename BasicJsonType>
@@ -175,8 +178,9 @@ struct actual_object_comparator
{ {
using object_t = typename BasicJsonType::object_t; using object_t = typename BasicJsonType::object_t;
using object_comparator_t = typename BasicJsonType::default_object_comparator_t; using object_comparator_t = typename BasicJsonType::default_object_comparator_t;
using type = typename std::conditional < has_key_compare<object_t>::value, using type = typename std::conditional<has_key_compare<object_t>::value,
typename object_t::key_compare, object_comparator_t>::type; typename object_t::key_compare,
object_comparator_t>::type;
}; };
template<typename BasicJsonType> template<typename BasicJsonType>
@@ -244,54 +248,72 @@ struct char_traits<signed char> : std::char_traits<char>
/////////////////// ///////////////////
// https://en.cppreference.com/w/cpp/types/conjunction // https://en.cppreference.com/w/cpp/types/conjunction
template<class...> struct conjunction : std::true_type { }; template<class...>
template<class B> struct conjunction<B> : B { }; struct conjunction : std::true_type
{};
template<class B>
struct conjunction<B> : B
{};
template<class B, class... Bn> template<class B, class... Bn>
struct conjunction<B, Bn...> struct conjunction<B, Bn...>
: std::conditional<static_cast<bool>(B::value), conjunction<Bn...>, B>::type {}; : std::conditional<static_cast<bool>(B::value), conjunction<Bn...>, B>::type
{};
// https://en.cppreference.com/w/cpp/types/negation // https://en.cppreference.com/w/cpp/types/negation
template<class B> struct negation : std::integral_constant < bool, !B::value > { }; 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 // 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). // 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. // This causes compile errors in e.g. clang 3.5 or gcc 4.9.
template <typename T> template<typename T>
struct is_default_constructible : std::is_default_constructible<T> {}; struct is_default_constructible : std::is_default_constructible<T>
{};
template <typename T1, typename T2> template<typename T1, typename T2>
struct is_default_constructible<std::pair<T1, T2>> struct is_default_constructible<std::pair<T1, T2>>
: conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {}; : conjunction<is_default_constructible<T1>, is_default_constructible<T2>>
{};
template <typename T1, typename T2> template<typename T1, typename T2>
struct is_default_constructible<const std::pair<T1, T2>> struct is_default_constructible<const std::pair<T1, T2>>
: conjunction<is_default_constructible<T1>, is_default_constructible<T2>> {}; : conjunction<is_default_constructible<T1>, is_default_constructible<T2>>
{};
template <typename... Ts> template<typename... Ts>
struct is_default_constructible<std::tuple<Ts...>> struct is_default_constructible<std::tuple<Ts...>>
: conjunction<is_default_constructible<Ts>...> {}; : conjunction<is_default_constructible<Ts>...>
{};
template <typename... Ts> template<typename... Ts>
struct is_default_constructible<const std::tuple<Ts...>> struct is_default_constructible<const std::tuple<Ts...>>
: conjunction<is_default_constructible<Ts>...> {}; : conjunction<is_default_constructible<Ts>...>
{};
template <typename T, typename... Args> template<typename T, typename... Args>
struct is_constructible : std::is_constructible<T, Args...> {}; struct is_constructible : std::is_constructible<T, Args...>
{};
template <typename T1, typename T2> template<typename T1, typename T2>
struct is_constructible<std::pair<T1, T2>> : is_default_constructible<std::pair<T1, T2>> {}; struct is_constructible<std::pair<T1, T2>> : is_default_constructible<std::pair<T1, T2>>
{};
template <typename T1, typename T2> template<typename T1, typename T2>
struct is_constructible<const std::pair<T1, T2>> : is_default_constructible<const std::pair<T1, T2>> {}; struct is_constructible<const std::pair<T1, T2>> : is_default_constructible<const std::pair<T1, T2>>
{};
template <typename... Ts> template<typename... Ts>
struct is_constructible<std::tuple<Ts...>> : is_default_constructible<std::tuple<Ts...>> {}; struct is_constructible<std::tuple<Ts...>> : is_default_constructible<std::tuple<Ts...>>
{};
template <typename... Ts> template<typename... Ts>
struct is_constructible<const std::tuple<Ts...>> : is_default_constructible<const std::tuple<Ts...>> {}; struct is_constructible<const std::tuple<Ts...>> : is_default_constructible<const std::tuple<Ts...>>
{};
template<typename T, typename = void> template<typename T, typename = void>
struct is_iterator_traits : std::false_type {}; struct is_iterator_traits : std::false_type
{};
template<typename T> template<typename T>
struct is_iterator_traits<iterator_traits<T>> struct is_iterator_traits<iterator_traits<T>>
@@ -338,44 +360,49 @@ using range_value_t = value_type_t<iterator_traits<iterator_t<T>>>;
// and is written by Xiang Fan who agreed to using it in this library. // and is written by Xiang Fan who agreed to using it in this library.
template<typename T, typename = void> template<typename T, typename = void>
struct is_complete_type : std::false_type {}; struct is_complete_type : std::false_type
{};
template<typename T> template<typename T>
struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type {}; struct is_complete_type<T, decltype(void(sizeof(T)))> : std::true_type
{};
template<typename BasicJsonType, typename CompatibleObjectType, template<typename BasicJsonType, typename CompatibleObjectType, typename = void>
typename = void> struct is_compatible_object_type_impl : std::false_type
struct is_compatible_object_type_impl : std::false_type {}; {};
template<typename BasicJsonType, typename CompatibleObjectType> template<typename BasicJsonType, typename CompatibleObjectType>
struct is_compatible_object_type_impl < struct is_compatible_object_type_impl<
BasicJsonType, CompatibleObjectType, BasicJsonType,
enable_if_t < is_detected<mapped_type_t, CompatibleObjectType>::value&& CompatibleObjectType,
is_detected<key_type_t, CompatibleObjectType>::value >> enable_if_t<is_detected<mapped_type_t, CompatibleObjectType>::value &&
is_detected<key_type_t, CompatibleObjectType>::value>>
{ {
using object_t = typename BasicJsonType::object_t; using object_t = typename BasicJsonType::object_t;
// macOS's is_constructible does not play well with nonesuch... // macOS's is_constructible does not play well with nonesuch...
static constexpr bool value = static constexpr bool value =
is_constructible<typename object_t::key_type, is_constructible<typename object_t::key_type,
typename CompatibleObjectType::key_type>::value && typename CompatibleObjectType::key_type>::value &&
is_constructible<typename object_t::mapped_type, is_constructible<typename object_t::mapped_type,
typename CompatibleObjectType::mapped_type>::value; typename CompatibleObjectType::mapped_type>::value;
}; };
template<typename BasicJsonType, typename CompatibleObjectType> template<typename BasicJsonType, typename CompatibleObjectType>
struct is_compatible_object_type struct is_compatible_object_type
: is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType> {}; : is_compatible_object_type_impl<BasicJsonType, CompatibleObjectType>
{};
template<typename BasicJsonType, typename ConstructibleObjectType, template<typename BasicJsonType, typename ConstructibleObjectType, typename = void>
typename = void> struct is_constructible_object_type_impl : std::false_type
struct is_constructible_object_type_impl : std::false_type {}; {};
template<typename BasicJsonType, typename ConstructibleObjectType> template<typename BasicJsonType, typename ConstructibleObjectType>
struct is_constructible_object_type_impl < struct is_constructible_object_type_impl<
BasicJsonType, ConstructibleObjectType, BasicJsonType,
enable_if_t < is_detected<mapped_type_t, ConstructibleObjectType>::value&& ConstructibleObjectType,
is_detected<key_type_t, ConstructibleObjectType>::value >> enable_if_t<is_detected<mapped_type_t, ConstructibleObjectType>::value &&
is_detected<key_type_t, ConstructibleObjectType>::value>>
{ {
using object_t = typename BasicJsonType::object_t; using object_t = typename BasicJsonType::object_t;
@@ -384,21 +411,22 @@ struct is_constructible_object_type_impl <
(std::is_move_assignable<ConstructibleObjectType>::value || (std::is_move_assignable<ConstructibleObjectType>::value ||
std::is_copy_assignable<ConstructibleObjectType>::value) && std::is_copy_assignable<ConstructibleObjectType>::value) &&
(is_constructible<typename ConstructibleObjectType::key_type, (is_constructible<typename ConstructibleObjectType::key_type,
typename object_t::key_type>::value && typename object_t::key_type>::value &&
std::is_same < std::is_same<
typename object_t::mapped_type, typename object_t::mapped_type,
typename ConstructibleObjectType::mapped_type >::value)) || typename ConstructibleObjectType::mapped_type>::value)) ||
(has_from_json<BasicJsonType, (has_from_json<BasicJsonType,
typename ConstructibleObjectType::mapped_type>::value || typename ConstructibleObjectType::mapped_type>::value ||
has_non_default_from_json < has_non_default_from_json<
BasicJsonType, BasicJsonType,
typename ConstructibleObjectType::mapped_type >::value); typename ConstructibleObjectType::mapped_type>::value);
}; };
template<typename BasicJsonType, typename ConstructibleObjectType> template<typename BasicJsonType, typename ConstructibleObjectType>
struct is_constructible_object_type struct is_constructible_object_type
: is_constructible_object_type_impl<BasicJsonType, : is_constructible_object_type_impl<BasicJsonType,
ConstructibleObjectType> {}; ConstructibleObjectType>
{};
template<typename BasicJsonType, typename CompatibleStringType> template<typename BasicJsonType, typename CompatibleStringType>
struct is_compatible_string_type struct is_compatible_string_type
@@ -418,88 +446,98 @@ struct is_constructible_string_type
#endif #endif
static constexpr auto value = static constexpr auto value =
conjunction < conjunction<
is_constructible<laundered_type, typename BasicJsonType::string_t>, is_constructible<laundered_type, typename BasicJsonType::string_t>,
is_detected_exact<typename BasicJsonType::string_t::value_type, is_detected_exact<typename BasicJsonType::string_t::value_type,
value_type_t, laundered_type >>::value; value_type_t,
laundered_type>>::value;
}; };
template<typename BasicJsonType, typename CompatibleArrayType, typename = void> template<typename BasicJsonType, typename CompatibleArrayType, typename = void>
struct is_compatible_array_type_impl : std::false_type {}; struct is_compatible_array_type_impl : std::false_type
{};
template<typename BasicJsonType, typename CompatibleArrayType> template<typename BasicJsonType, typename CompatibleArrayType>
struct is_compatible_array_type_impl < struct is_compatible_array_type_impl<
BasicJsonType, CompatibleArrayType, BasicJsonType,
enable_if_t < CompatibleArrayType,
is_detected<iterator_t, CompatibleArrayType>::value&& enable_if_t<
is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value&& is_detected<iterator_t, CompatibleArrayType>::value &&
// special case for types like std::filesystem::path whose iterator's value_type are themselves is_iterator_traits<iterator_traits<detected_t<iterator_t, CompatibleArrayType>>>::value &&
// c.f. https://github.com/nlohmann/json/pull/3073 // special case for types like std::filesystem::path whose iterator's value_type are themselves
!std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value >> // c.f. https://github.com/nlohmann/json/pull/3073
!std::is_same<CompatibleArrayType, detected_t<range_value_t, CompatibleArrayType>>::value>>
{ {
static constexpr bool value = static constexpr bool value =
is_constructible<BasicJsonType, is_constructible<BasicJsonType,
range_value_t<CompatibleArrayType>>::value; range_value_t<CompatibleArrayType>>::value;
}; };
template<typename BasicJsonType, typename CompatibleArrayType> template<typename BasicJsonType, typename CompatibleArrayType>
struct is_compatible_array_type struct is_compatible_array_type
: is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType> {}; : is_compatible_array_type_impl<BasicJsonType, CompatibleArrayType>
{};
template<typename BasicJsonType, typename ConstructibleArrayType, typename = void> template<typename BasicJsonType, typename ConstructibleArrayType, typename = void>
struct is_constructible_array_type_impl : std::false_type {}; struct is_constructible_array_type_impl : std::false_type
{};
template<typename BasicJsonType, typename ConstructibleArrayType> template<typename BasicJsonType, typename ConstructibleArrayType>
struct is_constructible_array_type_impl < struct is_constructible_array_type_impl<
BasicJsonType, ConstructibleArrayType, BasicJsonType,
ConstructibleArrayType,
enable_if_t<std::is_same<ConstructibleArrayType, enable_if_t<std::is_same<ConstructibleArrayType,
typename BasicJsonType::value_type>::value >> typename BasicJsonType::value_type>::value>>
: std::true_type {}; : std::true_type
{};
template<typename BasicJsonType, typename ConstructibleArrayType> template<typename BasicJsonType, typename ConstructibleArrayType>
struct is_constructible_array_type_impl < struct is_constructible_array_type_impl<
BasicJsonType, ConstructibleArrayType, BasicJsonType,
enable_if_t < !std::is_same<ConstructibleArrayType, ConstructibleArrayType,
typename BasicJsonType::value_type>::value&& enable_if_t<!std::is_same<ConstructibleArrayType,
!is_compatible_string_type<BasicJsonType, ConstructibleArrayType>::value&& typename BasicJsonType::value_type>::value &&
is_default_constructible<ConstructibleArrayType>::value&& !is_compatible_string_type<BasicJsonType, ConstructibleArrayType>::value &&
(std::is_move_assignable<ConstructibleArrayType>::value || is_default_constructible<ConstructibleArrayType>::value &&
std::is_copy_assignable<ConstructibleArrayType>::value)&& (std::is_move_assignable<ConstructibleArrayType>::value ||
is_detected<iterator_t, ConstructibleArrayType>::value&& std::is_copy_assignable<ConstructibleArrayType>::value) &&
is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value&& is_detected<iterator_t, ConstructibleArrayType>::value &&
is_detected<range_value_t, ConstructibleArrayType>::value&& is_iterator_traits<iterator_traits<detected_t<iterator_t, ConstructibleArrayType>>>::value &&
// special case for types like std::filesystem::path whose iterator's value_type are themselves is_detected<range_value_t, ConstructibleArrayType>::value &&
// c.f. https://github.com/nlohmann/json/pull/3073 // special case for types like std::filesystem::path whose iterator's value_type are themselves
!std::is_same<ConstructibleArrayType, detected_t<range_value_t, ConstructibleArrayType>>::value&& // c.f. https://github.com/nlohmann/json/pull/3073
is_complete_type < !std::is_same<ConstructibleArrayType, detected_t<range_value_t, ConstructibleArrayType>>::value &&
detected_t<range_value_t, ConstructibleArrayType >>::value >> is_complete_type<
detected_t<range_value_t, ConstructibleArrayType>>::value>>
{ {
using value_type = range_value_t<ConstructibleArrayType>; using value_type = range_value_t<ConstructibleArrayType>;
static constexpr bool value = static constexpr bool value =
std::is_same<value_type, std::is_same<value_type,
typename BasicJsonType::array_t::value_type>::value || typename BasicJsonType::array_t::value_type>::value ||
has_from_json<BasicJsonType, has_from_json<BasicJsonType,
value_type>::value || value_type>::value ||
has_non_default_from_json < has_non_default_from_json<
BasicJsonType, BasicJsonType,
value_type >::value; value_type>::value;
}; };
template<typename BasicJsonType, typename ConstructibleArrayType> template<typename BasicJsonType, typename ConstructibleArrayType>
struct is_constructible_array_type struct is_constructible_array_type
: is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType> {}; : is_constructible_array_type_impl<BasicJsonType, ConstructibleArrayType>
{};
template<typename RealIntegerType, typename CompatibleNumberIntegerType, template<typename RealIntegerType, typename CompatibleNumberIntegerType, typename = void>
typename = void> struct is_compatible_integer_type_impl : std::false_type
struct is_compatible_integer_type_impl : std::false_type {}; {};
template<typename RealIntegerType, typename CompatibleNumberIntegerType> template<typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type_impl < struct is_compatible_integer_type_impl<
RealIntegerType, CompatibleNumberIntegerType, RealIntegerType,
enable_if_t < std::is_integral<RealIntegerType>::value&& CompatibleNumberIntegerType,
std::is_integral<CompatibleNumberIntegerType>::value&& enable_if_t<std::is_integral<RealIntegerType>::value &&
!std::is_same<bool, CompatibleNumberIntegerType>::value >> std::is_integral<CompatibleNumberIntegerType>::value &&
!std::is_same<bool, CompatibleNumberIntegerType>::value>>
{ {
// is there an assert somewhere on overflows? // is there an assert somewhere on overflows?
using RealLimits = std::numeric_limits<RealIntegerType>; using RealLimits = std::numeric_limits<RealIntegerType>;
@@ -507,23 +545,26 @@ struct is_compatible_integer_type_impl <
static constexpr auto value = static constexpr auto value =
is_constructible<RealIntegerType, is_constructible<RealIntegerType,
CompatibleNumberIntegerType>::value && CompatibleNumberIntegerType>::value &&
CompatibleLimits::is_integer && CompatibleLimits::is_integer &&
RealLimits::is_signed == CompatibleLimits::is_signed; RealLimits::is_signed == CompatibleLimits::is_signed;
}; };
template<typename RealIntegerType, typename CompatibleNumberIntegerType> template<typename RealIntegerType, typename CompatibleNumberIntegerType>
struct is_compatible_integer_type struct is_compatible_integer_type
: is_compatible_integer_type_impl<RealIntegerType, : is_compatible_integer_type_impl<RealIntegerType,
CompatibleNumberIntegerType> {}; CompatibleNumberIntegerType>
{};
template<typename BasicJsonType, typename CompatibleType, typename = void> template<typename BasicJsonType, typename CompatibleType, typename = void>
struct is_compatible_type_impl: std::false_type {}; struct is_compatible_type_impl : std::false_type
{};
template<typename BasicJsonType, typename CompatibleType> template<typename BasicJsonType, typename CompatibleType>
struct is_compatible_type_impl < struct is_compatible_type_impl<
BasicJsonType, CompatibleType, BasicJsonType,
enable_if_t<is_complete_type<CompatibleType>::value >> CompatibleType,
enable_if_t<is_complete_type<CompatibleType>::value>>
{ {
static constexpr bool value = static constexpr bool value =
has_to_json<BasicJsonType, CompatibleType>::value; has_to_json<BasicJsonType, CompatibleType>::value;
@@ -531,60 +572,60 @@ struct is_compatible_type_impl <
template<typename BasicJsonType, typename CompatibleType> template<typename BasicJsonType, typename CompatibleType>
struct is_compatible_type struct is_compatible_type
: is_compatible_type_impl<BasicJsonType, CompatibleType> {}; : is_compatible_type_impl<BasicJsonType, CompatibleType>
{};
template<typename T1, typename T2> template<typename T1, typename T2>
struct is_constructible_tuple : std::false_type {}; struct is_constructible_tuple : std::false_type
{};
template<typename T1, typename... Args> template<typename T1, typename... Args>
struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...> {}; struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<is_constructible<T1, Args>...>
{};
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct is_json_iterator_of : std::false_type {}; struct is_json_iterator_of : std::false_type
{};
template<typename BasicJsonType> template<typename BasicJsonType>
struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::iterator> : std::true_type {}; struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::iterator> : std::true_type
{};
template<typename BasicJsonType> template<typename BasicJsonType>
struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::const_iterator> : std::true_type struct is_json_iterator_of<BasicJsonType, typename BasicJsonType::const_iterator> : std::true_type
{}; {};
// checks if a given type T is a template specialization of Primary // checks if a given type T is a template specialization of Primary
template<template <typename...> class Primary, typename T> template<template<typename...> class Primary, typename T>
struct is_specialization_of : std::false_type {}; struct is_specialization_of : std::false_type
{};
template<template <typename...> class Primary, typename... Args> template<template<typename...> class Primary, typename... Args>
struct is_specialization_of<Primary, Primary<Args...>> : std::true_type {}; struct is_specialization_of<Primary, Primary<Args...>> : std::true_type
{};
template<typename T> template<typename T>
using is_json_pointer = is_specialization_of<::nlohmann::json_pointer, uncvref_t<T>>; using is_json_pointer = is_specialization_of<::nlohmann::json_pointer, uncvref_t<T>>;
// checks if A and B are comparable using Compare functor // checks if A and B are comparable using Compare functor
template<typename Compare, typename A, typename B, typename = void> template<typename Compare, typename A, typename B, typename = void>
struct is_comparable : std::false_type {}; struct is_comparable : std::false_type
{};
template<typename Compare, typename A, typename B> template<typename Compare, typename A, typename B>
struct is_comparable<Compare, A, B, void_t< struct is_comparable<Compare, A, B, void_t<decltype(std::declval<Compare>()(std::declval<A>(), std::declval<B>())), decltype(std::declval<Compare>()(std::declval<B>(), std::declval<A>()))>> : std::true_type
decltype(std::declval<Compare>()(std::declval<A>(), std::declval<B>())), {};
decltype(std::declval<Compare>()(std::declval<B>(), std::declval<A>()))
>> : std::true_type {};
template<typename T> template<typename T>
using detect_is_transparent = typename T::is_transparent; using detect_is_transparent = typename T::is_transparent;
// type trait to check if KeyType can be used as object key (without a BasicJsonType) // type trait to check if KeyType can be used as object key (without a BasicJsonType)
// see is_usable_as_basic_json_key_type below // see is_usable_as_basic_json_key_type below
template<typename Comparator, typename ObjectKeyType, typename KeyTypeCVRef, bool RequireTransparentComparator = true, template<typename Comparator, typename ObjectKeyType, typename KeyTypeCVRef, bool RequireTransparentComparator = true, bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>> using is_usable_as_key_type = typename std::conditional<
using is_usable_as_key_type = typename std::conditional < is_comparable<Comparator, ObjectKeyType, KeyTypeCVRef>::value && !(ExcludeObjectKeyType && std::is_same<KeyType, ObjectKeyType>::value) && (!RequireTransparentComparator || is_detected<detect_is_transparent, Comparator>::value) && !is_json_pointer<KeyType>::value,
is_comparable<Comparator, ObjectKeyType, KeyTypeCVRef>::value std::true_type,
&& !(ExcludeObjectKeyType && std::is_same<KeyType, std::false_type>::type;
ObjectKeyType>::value)
&& (!RequireTransparentComparator
|| is_detected <detect_is_transparent, Comparator>::value)
&& !is_json_pointer<KeyType>::value,
std::true_type,
std::false_type >::type;
// type trait to check if KeyType can be used as object key // type trait to check if KeyType can be used as object key
// true if: // true if:
@@ -592,48 +633,55 @@ using is_usable_as_key_type = typename std::conditional <
// - if ExcludeObjectKeyType is true, KeyType is not BasicJsonType::object_t::key_type // - if ExcludeObjectKeyType is true, KeyType is not BasicJsonType::object_t::key_type
// - the comparator is transparent or RequireTransparentComparator is false // - the comparator is transparent or RequireTransparentComparator is false
// - KeyType is not a JSON iterator or json_pointer // - KeyType is not a JSON iterator or json_pointer
template<typename BasicJsonType, typename KeyTypeCVRef, bool RequireTransparentComparator = true, template<typename BasicJsonType, typename KeyTypeCVRef, bool RequireTransparentComparator = true, bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>>
bool ExcludeObjectKeyType = RequireTransparentComparator, typename KeyType = uncvref_t<KeyTypeCVRef>> using is_usable_as_basic_json_key_type = typename std::conditional<
using is_usable_as_basic_json_key_type = typename std::conditional < is_usable_as_key_type<typename BasicJsonType::object_comparator_t,
is_usable_as_key_type<typename BasicJsonType::object_comparator_t, typename BasicJsonType::object_t::key_type,
typename BasicJsonType::object_t::key_type, KeyTypeCVRef, KeyTypeCVRef,
RequireTransparentComparator, ExcludeObjectKeyType>::value RequireTransparentComparator,
&& !is_json_iterator_of<BasicJsonType, KeyType>::value, ExcludeObjectKeyType>::value &&
std::true_type, !is_json_iterator_of<BasicJsonType, KeyType>::value,
std::false_type >::type; std::true_type,
std::false_type>::type;
template<typename ObjectType, typename KeyType> template<typename ObjectType, typename KeyType>
using detect_erase_with_key_type = decltype(std::declval<ObjectType&>().erase(std::declval<KeyType>())); using detect_erase_with_key_type = decltype(std::declval<ObjectType&>().erase(std::declval<KeyType>()));
// type trait to check if object_t has an erase() member functions accepting KeyType // type trait to check if object_t has an erase() member functions accepting KeyType
template<typename BasicJsonType, typename KeyType> template<typename BasicJsonType, typename KeyType>
using has_erase_with_key_type = typename std::conditional < using has_erase_with_key_type = typename std::conditional<
is_detected < is_detected<
detect_erase_with_key_type, detect_erase_with_key_type,
typename BasicJsonType::object_t, KeyType >::value, typename BasicJsonType::object_t,
std::true_type, KeyType>::value,
std::false_type >::type; std::true_type,
std::false_type>::type;
// a naive helper to check if a type is an ordered_map (exploits the fact that // a naive helper to check if a type is an ordered_map (exploits the fact that
// ordered_map inherits capacity() from std::vector) // ordered_map inherits capacity() from std::vector)
template <typename T> template<typename T>
struct is_ordered_map struct is_ordered_map
{ {
using one = char; using one = char;
struct two struct two
{ {
char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) char x[2]; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
}; };
template <typename C> static one test( decltype(&C::capacity) ) ; template<typename C>
template <typename C> static two test(...); static one test(decltype(&C::capacity));
template<typename C>
static two test(...);
enum { value = sizeof(test<T>(nullptr)) == sizeof(char) }; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg) enum
{
value = sizeof(test<T>(nullptr)) == sizeof(char)
}; // NOLINT(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
}; };
// to avoid useless casts (see https://github.com/nlohmann/json/issues/2893#issuecomment-889152324) // 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 > template<typename T, typename U, enable_if_t<!std::is_same<T, U>::value, int> = 0>
T conditional_static_cast(U value) T conditional_static_cast(U value)
{ {
return static_cast<T>(value); return static_cast<T>(value);
@@ -656,17 +704,14 @@ using all_unsigned = conjunction<std::is_unsigned<Types>...>;
// there's a disjunction trait in another PR; replace when merged // there's a disjunction trait in another PR; replace when merged
template<typename... Types> template<typename... Types>
using same_sign = std::integral_constant < bool, using same_sign = std::integral_constant<bool,
all_signed<Types...>::value || all_unsigned<Types...>::value >; all_signed<Types...>::value || all_unsigned<Types...>::value>;
template<typename OfType, typename T> template<typename OfType, typename T>
using never_out_of_range = std::integral_constant < bool, using never_out_of_range = std::integral_constant<bool,
(std::is_signed<OfType>::value && (sizeof(T) < sizeof(OfType))) (std::is_signed<OfType>::value && (sizeof(T) < sizeof(OfType))) || (same_sign<OfType, T>::value && sizeof(OfType) == sizeof(T))>;
|| (same_sign<OfType, T>::value && sizeof(OfType) == sizeof(T)) >;
template<typename OfType, typename T, template<typename OfType, typename T, bool OfTypeSigned = std::is_signed<OfType>::value, bool TSigned = std::is_signed<T>::value>
bool OfTypeSigned = std::is_signed<OfType>::value,
bool TSigned = std::is_signed<T>::value>
struct value_in_range_of_impl2; struct value_in_range_of_impl2;
template<typename OfType, typename T> template<typename OfType, typename T>
@@ -705,14 +750,11 @@ struct value_in_range_of_impl2<OfType, T, true, true>
static constexpr bool test(T val) static constexpr bool test(T val)
{ {
using CommonType = typename std::common_type<OfType, T>::type; using CommonType = typename std::common_type<OfType, T>::type;
return static_cast<CommonType>(val) >= static_cast<CommonType>((std::numeric_limits<OfType>::min)()) return static_cast<CommonType>(val) >= static_cast<CommonType>((std::numeric_limits<OfType>::min)()) && static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
&& static_cast<CommonType>(val) <= static_cast<CommonType>((std::numeric_limits<OfType>::max)());
} }
}; };
template<typename OfType, typename T, template<typename OfType, typename T, bool NeverOutOfRange = never_out_of_range<OfType, T>::value, typename = detail::enable_if_t<all_integral<OfType, T>::value>>
bool NeverOutOfRange = never_out_of_range<OfType, T>::value,
typename = detail::enable_if_t<all_integral<OfType, T>::value>>
struct value_in_range_of_impl1; struct value_in_range_of_impl1;
template<typename OfType, typename T> template<typename OfType, typename T>
@@ -746,8 +788,7 @@ using bool_constant = std::integral_constant<bool, Value>;
// is_c_string // is_c_string
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
namespace impl namespace impl {
{
template<typename T> template<typename T>
inline constexpr bool is_c_string() inline constexpr bool is_c_string()
@@ -756,16 +797,15 @@ inline constexpr bool is_c_string()
using TUnCVExt = typename std::remove_cv<TUnExt>::type; using TUnCVExt = typename std::remove_cv<TUnExt>::type;
using TUnPtr = typename std::remove_pointer<T>::type; using TUnPtr = typename std::remove_pointer<T>::type;
using TUnCVPtr = typename std::remove_cv<TUnPtr>::type; using TUnCVPtr = typename std::remove_cv<TUnPtr>::type;
return return (std::is_array<T>::value && std::is_same<TUnCVExt, char>::value) || (std::is_pointer<T>::value && std::is_same<TUnCVPtr, char>::value);
(std::is_array<T>::value && std::is_same<TUnCVExt, char>::value)
|| (std::is_pointer<T>::value && std::is_same<TUnCVPtr, char>::value);
} }
} // namespace impl } // namespace impl
// checks whether T is a [cv] char */[cv] char[] C string // checks whether T is a [cv] char */[cv] char[] C string
template<typename T> template<typename T>
struct is_c_string : bool_constant<impl::is_c_string<T>()> {}; struct is_c_string : bool_constant<impl::is_c_string<T>()>
{};
template<typename T> template<typename T>
using is_c_string_uncvref = is_c_string<uncvref_t<T>>; using is_c_string_uncvref = is_c_string<uncvref_t<T>>;
@@ -774,8 +814,7 @@ using is_c_string_uncvref = is_c_string<uncvref_t<T>>;
// is_transparent // is_transparent
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
namespace impl namespace impl {
{
template<typename T> template<typename T>
inline constexpr bool is_transparent() inline constexpr bool is_transparent()
@@ -787,7 +826,8 @@ inline constexpr bool is_transparent()
// checks whether T has a member named is_transparent // checks whether T has a member named is_transparent
template<typename T> template<typename T>
struct is_transparent : bool_constant<impl::is_transparent<T>()> {}; struct is_transparent : bool_constant<impl::is_transparent<T>()>
{};
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
+5 -4
View File
@@ -11,14 +11,15 @@
#include <nlohmann/detail/abi_macros.hpp> #include <nlohmann/detail/abi_macros.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
template<typename ...Ts> struct make_void template<typename... Ts>
struct make_void
{ {
using type = void; using type = void;
}; };
template<typename ...Ts> using void_t = typename make_void<Ts...>::type; template<typename... Ts>
using void_t = typename make_void<Ts...>::type;
} // namespace detail } // namespace detail
NLOHMANN_JSON_NAMESPACE_END NLOHMANN_JSON_NAMESPACE_END
@@ -8,16 +8,16 @@
#pragma once #pragma once
#include <algorithm> // reverse #include <algorithm> // reverse
#include <array> // array #include <array> // array
#include <map> // map #include <cmath> // isnan, isinf
#include <cmath> // isnan, isinf #include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t
#include <cstdint> // uint8_t, uint16_t, uint32_t, uint64_t #include <cstring> // memcpy
#include <cstring> // memcpy #include <limits> // numeric_limits
#include <limits> // numeric_limits #include <map> // map
#include <string> // string #include <string> // string
#include <utility> // move #include <utility> // move
#include <vector> // vector #include <vector> // vector
#include <nlohmann/detail/input/binary_reader.hpp> #include <nlohmann/detail/input/binary_reader.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
@@ -25,8 +25,7 @@
#include <nlohmann/detail/string_concat.hpp> #include <nlohmann/detail/string_concat.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
/////////////////// ///////////////////
// binary writer // // binary writer //
@@ -48,7 +47,8 @@ class binary_writer
@param[in] adapter output adapter to write to @param[in] adapter output adapter to write to
*/ */
explicit binary_writer(output_adapter_t<CharType> adapter) : oa(std::move(adapter)) explicit binary_writer(output_adapter_t<CharType> adapter)
: oa(std::move(adapter))
{ {
JSON_ASSERT(oa); JSON_ASSERT(oa);
} }
@@ -99,8 +99,8 @@ class binary_writer
case value_t::boolean: case value_t::boolean:
{ {
oa->write_character(j.m_data.m_value.boolean oa->write_character(j.m_data.m_value.boolean
? to_char_type(0xF5) ? to_char_type(0xF5)
: to_char_type(0xF4)); : to_char_type(0xF4));
break; break;
} }
@@ -414,17 +414,17 @@ class binary_writer
{ {
switch (j.type()) switch (j.type())
{ {
case value_t::null: // nil case value_t::null: // nil
{ {
oa->write_character(to_char_type(0xC0)); oa->write_character(to_char_type(0xC0));
break; break;
} }
case value_t::boolean: // true and false case value_t::boolean: // true and false
{ {
oa->write_character(j.m_data.m_value.boolean oa->write_character(j.m_data.m_value.boolean
? to_char_type(0xC3) ? to_char_type(0xC3)
: to_char_type(0xC2)); : to_char_type(0xC2));
break; break;
} }
@@ -626,30 +626,29 @@ class binary_writer
switch (N) switch (N)
{ {
case 1: case 1:
output_type = 0xD4; // fixext 1 output_type = 0xD4; // fixext 1
break; break;
case 2: case 2:
output_type = 0xD5; // fixext 2 output_type = 0xD5; // fixext 2
break; break;
case 4: case 4:
output_type = 0xD6; // fixext 4 output_type = 0xD6; // fixext 4
break; break;
case 8: case 8:
output_type = 0xD7; // fixext 8 output_type = 0xD7; // fixext 8
break; break;
case 16: case 16:
output_type = 0xD8; // fixext 16 output_type = 0xD8; // fixext 16
break; break;
default: default:
output_type = 0xC7; // ext 8 output_type = 0xC7; // ext 8
fixed = false; fixed = false;
break; break;
} }
} }
else else
{ {
output_type = 0xC4; // bin 8 output_type = 0xC4; // bin 8
fixed = false; fixed = false;
} }
@@ -662,8 +661,8 @@ class binary_writer
else if (N <= (std::numeric_limits<std::uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
const std::uint8_t output_type = use_ext const std::uint8_t output_type = use_ext
? 0xC8 // ext 16 ? 0xC8 // ext 16
: 0xC5; // bin 16 : 0xC5; // bin 16
oa->write_character(to_char_type(output_type)); oa->write_character(to_char_type(output_type));
write_number(static_cast<std::uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
@@ -671,8 +670,8 @@ class binary_writer
else if (N <= (std::numeric_limits<std::uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
const std::uint8_t output_type = use_ext const std::uint8_t output_type = use_ext
? 0xC9 // ext 32 ? 0xC9 // ext 32
: 0xC6; // bin 32 : 0xC6; // bin 32
oa->write_character(to_char_type(output_type)); oa->write_character(to_char_type(output_type));
write_number(static_cast<std::uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
@@ -736,9 +735,7 @@ class binary_writer
@param[in] add_prefix whether prefixes need to be used for this value @param[in] add_prefix whether prefixes need to be used for this value
@param[in] use_bjdata whether write in BJData format, default is false @param[in] use_bjdata whether write in BJData format, default is false
*/ */
void write_ubjson(const BasicJsonType& j, const bool use_count, void write_ubjson(const BasicJsonType& j, const bool use_count, const bool use_type, const bool add_prefix = true, const bool use_bjdata = false)
const bool use_type, const bool add_prefix = true,
const bool use_bjdata = false)
{ {
switch (j.type()) switch (j.type())
{ {
@@ -756,8 +753,8 @@ class binary_writer
if (add_prefix) if (add_prefix)
{ {
oa->write_character(j.m_data.m_value.boolean oa->write_character(j.m_data.m_value.boolean
? to_char_type('T') ? to_char_type('T')
: to_char_type('F')); : to_char_type('F'));
} }
break; break;
} }
@@ -805,13 +802,11 @@ class binary_writer
{ {
JSON_ASSERT(use_count); JSON_ASSERT(use_count);
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
const bool same_prefix = std::all_of(j.begin() + 1, j.end(), const bool same_prefix = std::all_of(j.begin() + 1, j.end(), [this, first_prefix, use_bjdata](const BasicJsonType& v) {
[this, first_prefix, use_bjdata](const BasicJsonType & v)
{
return ubjson_prefix(v, use_bjdata) == first_prefix; return ubjson_prefix(v, use_bjdata) == first_prefix;
}); });
std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type
if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end())) if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end()))
{ {
@@ -903,13 +898,11 @@ class binary_writer
{ {
JSON_ASSERT(use_count); JSON_ASSERT(use_count);
const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata); const CharType first_prefix = ubjson_prefix(j.front(), use_bjdata);
const bool same_prefix = std::all_of(j.begin(), j.end(), const bool same_prefix = std::all_of(j.begin(), j.end(), [this, first_prefix, use_bjdata](const BasicJsonType& v) {
[this, first_prefix, use_bjdata](const BasicJsonType & v)
{
return ubjson_prefix(v, use_bjdata) == first_prefix; return ubjson_prefix(v, use_bjdata) == first_prefix;
}); });
std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type std::vector<CharType> bjdx = {'[', '{', 'S', 'H', 'T', 'F', 'N', 'Z'}; // excluded markers in bjdata optimized type
if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end())) if (same_prefix && !(use_bjdata && std::find(bjdx.begin(), bjdx.end(), first_prefix) != bjdx.end()))
{ {
@@ -966,7 +959,7 @@ class binary_writer
static_cast<void>(j); static_cast<void>(j);
} }
return /*id*/ 1ul + name.size() + /*zero-terminator*/1u; return /*id*/ 1ul + name.size() + /*zero-terminator*/ 1u;
} }
/*! /*!
@@ -975,7 +968,7 @@ class binary_writer
void write_bson_entry_header(const string_t& name, void write_bson_entry_header(const string_t& name,
const std::uint8_t element_type) const std::uint8_t element_type)
{ {
oa->write_character(to_char_type(element_type)); // boolean oa->write_character(to_char_type(element_type)); // boolean
oa->write_characters( oa->write_characters(
reinterpret_cast<const CharType*>(name.c_str()), reinterpret_cast<const CharType*>(name.c_str()),
name.size() + 1u); name.size() + 1u);
@@ -1037,8 +1030,8 @@ class binary_writer
static std::size_t calc_bson_integer_size(const std::int64_t value) static std::size_t calc_bson_integer_size(const std::int64_t value)
{ {
return (std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)() return (std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)()
? sizeof(std::int32_t) ? sizeof(std::int32_t)
: sizeof(std::int64_t); : sizeof(std::int64_t);
} }
/*! /*!
@@ -1049,12 +1042,12 @@ class binary_writer
{ {
if ((std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)()) if ((std::numeric_limits<std::int32_t>::min)() <= value && value <= (std::numeric_limits<std::int32_t>::max)())
{ {
write_bson_entry_header(name, 0x10); // int32 write_bson_entry_header(name, 0x10); // int32
write_number<std::int32_t>(static_cast<std::int32_t>(value), true); write_number<std::int32_t>(static_cast<std::int32_t>(value), true);
} }
else else
{ {
write_bson_entry_header(name, 0x12); // int64 write_bson_entry_header(name, 0x12); // int64
write_number<std::int64_t>(static_cast<std::int64_t>(value), true); write_number<std::int64_t>(static_cast<std::int64_t>(value), true);
} }
} }
@@ -1065,8 +1058,8 @@ class binary_writer
static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept static constexpr std::size_t calc_bson_unsigned_size(const std::uint64_t value) noexcept
{ {
return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)())) return (value <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
? sizeof(std::int32_t) ? sizeof(std::int32_t)
: sizeof(std::int64_t); : sizeof(std::int64_t);
} }
/*! /*!
@@ -1097,7 +1090,7 @@ class binary_writer
void write_bson_object_entry(const string_t& name, void write_bson_object_entry(const string_t& name,
const typename BasicJsonType::object_t& value) const typename BasicJsonType::object_t& value)
{ {
write_bson_entry_header(name, 0x03); // object write_bson_entry_header(name, 0x03); // object
write_bson_object(value); write_bson_object(value);
} }
@@ -1108,8 +1101,7 @@ class binary_writer
{ {
std::size_t array_index = 0ul; std::size_t array_index = 0ul;
const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), static_cast<std::size_t>(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el) const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), static_cast<std::size_t>(0), [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type& el) {
{
return result + calc_bson_element_size(std::to_string(array_index++), el); return result + calc_bson_element_size(std::to_string(array_index++), el);
}); });
@@ -1130,7 +1122,7 @@ class binary_writer
void write_bson_array(const string_t& name, void write_bson_array(const string_t& name,
const typename BasicJsonType::array_t& value) const typename BasicJsonType::array_t& value)
{ {
write_bson_entry_header(name, 0x04); // array write_bson_entry_header(name, 0x04); // array
write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_array_size(value)), true); write_number<std::int32_t>(static_cast<std::int32_t>(calc_bson_array_size(value)), true);
std::size_t array_index = 0ul; std::size_t array_index = 0ul;
@@ -1162,7 +1154,7 @@ class binary_writer
@return The calculated size for the BSON document entry for @a j with the given @a name. @return The calculated size for the BSON document entry for @a j with the given @a name.
*/ */
static std::size_t calc_bson_element_size(const string_t& name, static std::size_t calc_bson_element_size(const string_t& name,
const BasicJsonType& j) const BasicJsonType& j)
{ {
const auto header_size = calc_bson_entry_header_size(name, j); const auto header_size = calc_bson_entry_header_size(name, j);
switch (j.type()) switch (j.type())
@@ -1197,7 +1189,7 @@ class binary_writer
// LCOV_EXCL_START // LCOV_EXCL_START
case value_t::discarded: case value_t::discarded:
default: default:
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)
return 0ul; return 0ul;
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }
@@ -1244,7 +1236,7 @@ class binary_writer
// LCOV_EXCL_START // LCOV_EXCL_START
case value_t::discarded: case value_t::discarded:
default: default:
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert)
return; return;
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
} }
@@ -1258,9 +1250,7 @@ class binary_writer
*/ */
static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value) static std::size_t calc_bson_object_size(const typename BasicJsonType::object_t& value)
{ {
const std::size_t document_size = std::accumulate(value.begin(), value.end(), static_cast<std::size_t>(0), const std::size_t document_size = std::accumulate(value.begin(), value.end(), static_cast<std::size_t>(0), [](size_t result, const typename BasicJsonType::object_t::value_type& el) {
[](size_t result, const typename BasicJsonType::object_t::value_type & el)
{
return result += calc_bson_element_size(el.first, el.second); return result += calc_bson_element_size(el.first, el.second);
}); });
@@ -1316,8 +1306,7 @@ class binary_writer
//////////// ////////////
// UBJSON: write number (floating point) // UBJSON: write number (floating point)
template<typename NumberType, typename std::enable_if< template<typename NumberType, typename std::enable_if<std::is_floating_point<NumberType>::value, int>::type = 0>
std::is_floating_point<NumberType>::value, int>::type = 0>
void write_number_with_ubjson_prefix(const NumberType n, void write_number_with_ubjson_prefix(const NumberType n,
const bool add_prefix, const bool add_prefix,
const bool use_bjdata) const bool use_bjdata)
@@ -1330,8 +1319,7 @@ class binary_writer
} }
// UBJSON: write number (unsigned integer) // UBJSON: write number (unsigned integer)
template<typename NumberType, typename std::enable_if< template<typename NumberType, typename std::enable_if<std::is_unsigned<NumberType>::value, int>::type = 0>
std::is_unsigned<NumberType>::value, int>::type = 0>
void write_number_with_ubjson_prefix(const NumberType n, void write_number_with_ubjson_prefix(const NumberType n,
const bool add_prefix, const bool add_prefix,
const bool use_bjdata) const bool use_bjdata)
@@ -1417,9 +1405,7 @@ class binary_writer
} }
// UBJSON: write number (signed integer) // UBJSON: write number (signed integer)
template < typename NumberType, typename std::enable_if < template<typename NumberType, typename std::enable_if<std::is_signed<NumberType>::value && !std::is_floating_point<NumberType>::value, int>::type = 0>
std::is_signed<NumberType>::value&&
!std::is_floating_point<NumberType>::value, int >::type = 0 >
void write_number_with_ubjson_prefix(const NumberType n, void write_number_with_ubjson_prefix(const NumberType n,
const bool add_prefix, const bool add_prefix,
const bool use_bjdata) const bool use_bjdata)
@@ -1542,7 +1528,7 @@ class binary_writer
return 'L'; return 'L';
} }
// anything else is treated as high-precision number // anything else is treated as high-precision number
return 'H'; // LCOV_EXCL_LINE return 'H'; // LCOV_EXCL_LINE
} }
case value_t::number_unsigned: case value_t::number_unsigned:
@@ -1580,7 +1566,7 @@ class binary_writer
return 'M'; return 'M';
} }
// anything else is treated as high-precision number // anything else is treated as high-precision number
return 'H'; // LCOV_EXCL_LINE return 'H'; // LCOV_EXCL_LINE
} }
case value_t::number_float: case value_t::number_float:
@@ -1589,7 +1575,7 @@ class binary_writer
case value_t::string: case value_t::string:
return 'S'; return 'S';
case value_t::array: // fallthrough case value_t::array: // fallthrough
case value_t::binary: case value_t::binary:
return '['; return '[';
@@ -1617,9 +1603,7 @@ class binary_writer
*/ */
bool write_bjdata_ndarray(const typename BasicJsonType::object_t& value, const bool use_count, const bool use_type) bool write_bjdata_ndarray(const typename BasicJsonType::object_t& value, const bool use_count, const bool use_type)
{ {
std::map<string_t, CharType> bjdtype = {{"uint8", 'U'}, {"int8", 'i'}, {"uint16", 'u'}, {"int16", 'I'}, std::map<string_t, CharType> bjdtype = {{"uint8", 'U'}, {"int8", 'i'}, {"uint16", 'u'}, {"int16", 'I'}, {"uint32", 'm'}, {"int32", 'l'}, {"uint64", 'M'}, {"int64", 'L'}, {"single", 'd'}, {"double", 'D'}, {"char", 'C'}};
{"uint32", 'm'}, {"int32", 'l'}, {"uint64", 'M'}, {"int64", 'L'}, {"single", 'd'}, {"double", 'D'}, {"char", 'C'}
};
string_t key = "_ArrayType_"; string_t key = "_ArrayType_";
auto it = bjdtype.find(static_cast<string_t>(value.at(key))); auto it = bjdtype.find(static_cast<string_t>(value.at(key)));
@@ -1648,7 +1632,7 @@ class binary_writer
oa->write_character('#'); oa->write_character('#');
key = "_ArraySize_"; key = "_ArraySize_";
write_ubjson(value.at(key), use_count, use_type, true, true); write_ubjson(value.at(key), use_count, use_type, true, true);
key = "_ArrayData_"; key = "_ArrayData_";
if (dtype == 'U' || dtype == 'C') if (dtype == 'U' || dtype == 'C')
@@ -1761,27 +1745,27 @@ class binary_writer
void write_compact_float(const number_float_t n, detail::input_format_t format) void write_compact_float(const number_float_t n, detail::input_format_t format)
{ {
#ifdef __GNUC__ #ifdef __GNUC__
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wfloat-equal" #pragma GCC diagnostic ignored "-Wfloat-equal"
#endif #endif
if (static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) && if (static_cast<double>(n) >= static_cast<double>(std::numeric_limits<float>::lowest()) &&
static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) && static_cast<double>(n) <= static_cast<double>((std::numeric_limits<float>::max)()) &&
static_cast<double>(static_cast<float>(n)) == static_cast<double>(n)) static_cast<double>(static_cast<float>(n)) == static_cast<double>(n))
{ {
oa->write_character(format == detail::input_format_t::cbor oa->write_character(format == detail::input_format_t::cbor
? get_cbor_float_prefix(static_cast<float>(n)) ? get_cbor_float_prefix(static_cast<float>(n))
: get_msgpack_float_prefix(static_cast<float>(n))); : get_msgpack_float_prefix(static_cast<float>(n)));
write_number(static_cast<float>(n)); write_number(static_cast<float>(n));
} }
else else
{ {
oa->write_character(format == detail::input_format_t::cbor oa->write_character(format == detail::input_format_t::cbor
? get_cbor_float_prefix(n) ? get_cbor_float_prefix(n)
: get_msgpack_float_prefix(n)); : get_msgpack_float_prefix(n));
write_number(n); write_number(n);
} }
#ifdef __GNUC__ #ifdef __GNUC__
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
} }
@@ -1790,15 +1774,15 @@ class binary_writer
// between uint8_t and CharType. In case CharType is not unsigned, // between uint8_t and CharType. In case CharType is not unsigned,
// such a conversion is required to allow values greater than 128. // such a conversion is required to allow values greater than 128.
// See <https://github.com/nlohmann/json/issues/1286> for a discussion. // See <https://github.com/nlohmann/json/issues/1286> for a discussion.
template < typename C = CharType, template<typename C = CharType,
enable_if_t < std::is_signed<C>::value && std::is_signed<char>::value > * = nullptr > enable_if_t<std::is_signed<C>::value && std::is_signed<char>::value>* = nullptr>
static constexpr CharType to_char_type(std::uint8_t x) noexcept static constexpr CharType to_char_type(std::uint8_t x) noexcept
{ {
return *reinterpret_cast<char*>(&x); return *reinterpret_cast<char*>(&x);
} }
template < typename C = CharType, template<typename C = CharType,
enable_if_t < std::is_signed<C>::value && std::is_unsigned<char>::value > * = nullptr > enable_if_t<std::is_signed<C>::value && std::is_unsigned<char>::value>* = nullptr>
static CharType to_char_type(std::uint8_t x) noexcept static CharType to_char_type(std::uint8_t x) noexcept
{ {
static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t"); static_assert(sizeof(std::uint8_t) == sizeof(CharType), "size of CharType must be equal to std::uint8_t");
@@ -1815,12 +1799,7 @@ class binary_writer
return x; return x;
} }
template < typename InputCharType, typename C = CharType, template<typename InputCharType, typename C = CharType, enable_if_t<std::is_signed<C>::value && std::is_signed<char>::value && std::is_same<char, typename std::remove_cv<InputCharType>::type>::value>* = nullptr>
enable_if_t <
std::is_signed<C>::value &&
std::is_signed<char>::value &&
std::is_same<char, typename std::remove_cv<InputCharType>::type>::value
> * = nullptr >
static constexpr CharType to_char_type(InputCharType x) noexcept static constexpr CharType to_char_type(InputCharType x) noexcept
{ {
return x; return x;
@@ -8,26 +8,26 @@
#pragma once #pragma once
#include <algorithm> // copy #include <algorithm> // copy
#include <cstddef> // size_t #include <cstddef> // size_t
#include <iterator> // back_inserter #include <iterator> // back_inserter
#include <memory> // shared_ptr, make_shared #include <memory> // shared_ptr, make_shared
#include <string> // basic_string #include <string> // basic_string
#include <vector> // vector #include <vector> // vector
#ifndef JSON_NO_IO #ifndef JSON_NO_IO
#include <ios> // streamsize #include <ios> // streamsize
#include <ostream> // basic_ostream #include <ostream> // basic_ostream
#endif // JSON_NO_IO #endif // JSON_NO_IO
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
/// abstract output adapter interface /// abstract output adapter interface
template<typename CharType> struct output_adapter_protocol template<typename CharType>
struct output_adapter_protocol
{ {
virtual void write_character(CharType c) = 0; virtual void write_character(CharType c) = 0;
virtual void write_characters(const CharType* s, std::size_t length) = 0; virtual void write_characters(const CharType* s, std::size_t length) = 0;
@@ -50,7 +50,7 @@ class output_vector_adapter : public output_adapter_protocol<CharType>
{ {
public: public:
explicit output_vector_adapter(std::vector<CharType, AllocatorType>& vec) noexcept explicit output_vector_adapter(std::vector<CharType, AllocatorType>& vec) noexcept
: v(vec) : v(vec)
{} {}
void write_character(CharType c) override void write_character(CharType c) override
@@ -75,7 +75,7 @@ class output_stream_adapter : public output_adapter_protocol<CharType>
{ {
public: public:
explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept
: stream(s) : stream(s)
{} {}
void write_character(CharType c) override void write_character(CharType c) override
@@ -100,7 +100,7 @@ class output_string_adapter : public output_adapter_protocol<CharType>
{ {
public: public:
explicit output_string_adapter(StringType& s) noexcept explicit output_string_adapter(StringType& s) noexcept
: str(s) : str(s)
{} {}
void write_character(CharType c) override void write_character(CharType c) override
@@ -124,15 +124,18 @@ class output_adapter
public: public:
template<typename AllocatorType = std::allocator<CharType>> template<typename AllocatorType = std::allocator<CharType>>
output_adapter(std::vector<CharType, AllocatorType>& vec) output_adapter(std::vector<CharType, AllocatorType>& vec)
: oa(std::make_shared<output_vector_adapter<CharType, AllocatorType>>(vec)) {} : oa(std::make_shared<output_vector_adapter<CharType, AllocatorType>>(vec))
{}
#ifndef JSON_NO_IO #ifndef JSON_NO_IO
output_adapter(std::basic_ostream<CharType>& s) output_adapter(std::basic_ostream<CharType>& s)
: oa(std::make_shared<output_stream_adapter<CharType>>(s)) {} : oa(std::make_shared<output_stream_adapter<CharType>>(s))
{}
#endif // JSON_NO_IO #endif // JSON_NO_IO
output_adapter(StringType& s) output_adapter(StringType& s)
: oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {} : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s))
{}
operator output_adapter_t<CharType>() operator output_adapter_t<CharType>()
{ {
+569 -104
View File
@@ -9,18 +9,18 @@
#pragma once #pragma once
#include <algorithm> // reverse, remove, fill, find, none_of #include <algorithm> // reverse, remove, fill, find, none_of
#include <array> // array #include <array> // array
#include <clocale> // localeconv, lconv #include <clocale> // localeconv, lconv
#include <cmath> // labs, isfinite, isnan, signbit #include <cmath> // labs, isfinite, isnan, signbit
#include <cstddef> // size_t, ptrdiff_t #include <cstddef> // size_t, ptrdiff_t
#include <cstdint> // uint8_t #include <cstdint> // uint8_t
#include <cstdio> // snprintf #include <cstdio> // snprintf
#include <limits> // numeric_limits #include <iomanip> // setfill, setw
#include <string> // string, char_traits #include <limits> // numeric_limits
#include <iomanip> // setfill, setw #include <string> // string, char_traits
#include <type_traits> // is_same #include <type_traits> // is_same
#include <utility> // move #include <utility> // move
#include <nlohmann/detail/conversions/to_chars.hpp> #include <nlohmann/detail/conversions/to_chars.hpp>
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
@@ -32,8 +32,7 @@
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
/////////////////// ///////////////////
// serialization // // serialization //
@@ -42,9 +41,9 @@ namespace detail
/// how to treat decoding errors /// how to treat decoding errors
enum class error_handler_t enum class error_handler_t
{ {
strict, ///< throw a type_error exception in case of invalid UTF-8 strict, ///< throw a type_error exception in case of invalid UTF-8
replace, ///< replace invalid UTF-8 sequences with U+FFFD replace, ///< replace invalid UTF-8 sequences with U+FFFD
ignore ///< ignore invalid UTF-8 sequences ignore ///< ignore invalid UTF-8 sequences
}; };
template<typename BasicJsonType> template<typename BasicJsonType>
@@ -64,15 +63,14 @@ class serializer
@param[in] ichar indentation character to use @param[in] ichar indentation character to use
@param[in] error_handler_ how to react on decoding errors @param[in] error_handler_ how to react on decoding errors
*/ */
serializer(output_adapter_t<char> s, const char ichar, serializer(output_adapter_t<char> s, const char ichar, error_handler_t error_handler_ = error_handler_t::strict)
error_handler_t error_handler_ = error_handler_t::strict) : o(std::move(s))
: o(std::move(s)) , loc(std::localeconv())
, loc(std::localeconv()) , thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(*(loc->thousands_sep)))
, thousands_sep(loc->thousands_sep == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->thousands_sep))) , decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(*(loc->decimal_point)))
, decimal_point(loc->decimal_point == nullptr ? '\0' : std::char_traits<char>::to_char_type(* (loc->decimal_point))) , indent_char(ichar)
, indent_char(ichar) , indent_string(512, indent_char)
, indent_string(512, indent_char) , error_handler(error_handler_)
, error_handler(error_handler_)
{} {}
// delete because of pointer members // delete because of pointer members
@@ -206,7 +204,8 @@ class serializer
// first n-1 elements // first n-1 elements
for (auto i = val.m_data.m_value.array->cbegin(); for (auto i = val.m_data.m_value.array->cbegin();
i != val.m_data.m_value.array->cend() - 1; ++i) i != val.m_data.m_value.array->cend() - 1;
++i)
{ {
o->write_characters(indent_string.c_str(), new_indent); o->write_characters(indent_string.c_str(), new_indent);
dump(*i, true, ensure_ascii, indent_step, new_indent); dump(*i, true, ensure_ascii, indent_step, new_indent);
@@ -228,7 +227,8 @@ class serializer
// first n-1 elements // first n-1 elements
for (auto i = val.m_data.m_value.array->cbegin(); for (auto i = val.m_data.m_value.array->cbegin();
i != val.m_data.m_value.array->cend() - 1; ++i) i != val.m_data.m_value.array->cend() - 1;
++i)
{ {
dump(*i, false, ensure_ascii, indent_step, current_indent); dump(*i, false, ensure_ascii, indent_step, current_indent);
o->write_character(','); o->write_character(',');
@@ -272,7 +272,8 @@ class serializer
if (!val.m_data.m_value.binary->empty()) if (!val.m_data.m_value.binary->empty())
{ {
for (auto i = val.m_data.m_value.binary->cbegin(); for (auto i = val.m_data.m_value.binary->cbegin();
i != val.m_data.m_value.binary->cend() - 1; ++i) i != val.m_data.m_value.binary->cend() - 1;
++i)
{ {
dump_integer(*i); dump_integer(*i);
o->write_characters(", ", 2); o->write_characters(", ", 2);
@@ -303,7 +304,8 @@ class serializer
if (!val.m_data.m_value.binary->empty()) if (!val.m_data.m_value.binary->empty())
{ {
for (auto i = val.m_data.m_value.binary->cbegin(); for (auto i = val.m_data.m_value.binary->cbegin();
i != val.m_data.m_value.binary->cend() - 1; ++i) i != val.m_data.m_value.binary->cend() - 1;
++i)
{ {
dump_integer(*i); dump_integer(*i);
o->write_character(','); o->write_character(',');
@@ -368,13 +370,13 @@ class serializer
return; return;
} }
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
} }
} }
JSON_PRIVATE_UNLESS_TESTED: JSON_PRIVATE_UNLESS_TESTED :
/*! /*!
@brief dump escaped string @brief dump escaped string
Escape a string by replacing certain special characters by a sequence of an Escape a string by replacing certain special characters by a sequence of an
@@ -388,7 +390,8 @@ class serializer
@complexity Linear in the length of string @a s. @complexity Linear in the length of string @a s.
*/ */
void dump_escaped(const string_t& s, const bool ensure_ascii) void
dump_escaped(const string_t& s, const bool ensure_ascii)
{ {
std::uint32_t codepoint{}; std::uint32_t codepoint{};
std::uint8_t state = UTF8_ACCEPT; std::uint8_t state = UTF8_ACCEPT;
@@ -408,49 +411,49 @@ class serializer
{ {
switch (codepoint) switch (codepoint)
{ {
case 0x08: // backspace case 0x08: // backspace
{ {
string_buffer[bytes++] = '\\'; string_buffer[bytes++] = '\\';
string_buffer[bytes++] = 'b'; string_buffer[bytes++] = 'b';
break; break;
} }
case 0x09: // horizontal tab case 0x09: // horizontal tab
{ {
string_buffer[bytes++] = '\\'; string_buffer[bytes++] = '\\';
string_buffer[bytes++] = 't'; string_buffer[bytes++] = 't';
break; break;
} }
case 0x0A: // newline case 0x0A: // newline
{ {
string_buffer[bytes++] = '\\'; string_buffer[bytes++] = '\\';
string_buffer[bytes++] = 'n'; string_buffer[bytes++] = 'n';
break; break;
} }
case 0x0C: // formfeed case 0x0C: // formfeed
{ {
string_buffer[bytes++] = '\\'; string_buffer[bytes++] = '\\';
string_buffer[bytes++] = 'f'; string_buffer[bytes++] = 'f';
break; break;
} }
case 0x0D: // carriage return case 0x0D: // carriage return
{ {
string_buffer[bytes++] = '\\'; string_buffer[bytes++] = '\\';
string_buffer[bytes++] = 'r'; string_buffer[bytes++] = 'r';
break; break;
} }
case 0x22: // quotation mark case 0x22: // quotation mark
{ {
string_buffer[bytes++] = '\\'; string_buffer[bytes++] = '\\';
string_buffer[bytes++] = '\"'; string_buffer[bytes++] = '\"';
break; break;
} }
case 0x5C: // reverse solidus case 0x5C: // reverse solidus
{ {
string_buffer[bytes++] = '\\'; string_buffer[bytes++] = '\\';
string_buffer[bytes++] = '\\'; string_buffer[bytes++] = '\\';
@@ -466,16 +469,13 @@ class serializer
if (codepoint <= 0xFFFF) if (codepoint <= 0xFFFF)
{ {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x", static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x", static_cast<std::uint16_t>(codepoint)));
static_cast<std::uint16_t>(codepoint)));
bytes += 6; bytes += 6;
} }
else else
{ {
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg) // NOLINTNEXTLINE(cppcoreguidelines-pro-type-vararg,hicpp-vararg)
static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", static_cast<void>((std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)), static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu))));
static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),
static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu))));
bytes += 12; bytes += 12;
} }
} }
@@ -567,8 +567,8 @@ class serializer
break; break;
} }
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
} }
break; break;
} }
@@ -628,8 +628,8 @@ class serializer
break; break;
} }
default: // LCOV_EXCL_LINE default: // LCOV_EXCL_LINE
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
} }
} }
} }
@@ -684,13 +684,13 @@ class serializer
} }
// templates to avoid warnings about useless casts // templates to avoid warnings about useless casts
template <typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0> template<typename NumberType, enable_if_t<std::is_signed<NumberType>::value, int> = 0>
bool is_negative_number(NumberType x) bool is_negative_number(NumberType x)
{ {
return x < 0; return x < 0;
} }
template < typename NumberType, enable_if_t <std::is_unsigned<NumberType>::value, int > = 0 > template<typename NumberType, enable_if_t<std::is_unsigned<NumberType>::value, int> = 0>
bool is_negative_number(NumberType /*unused*/) bool is_negative_number(NumberType /*unused*/)
{ {
return false; return false;
@@ -705,29 +705,112 @@ class serializer
@param[in] x integer number (signed or unsigned) to dump @param[in] x integer number (signed or unsigned) to dump
@tparam NumberType either @a number_integer_t or @a number_unsigned_t @tparam NumberType either @a number_integer_t or @a number_unsigned_t
*/ */
template < typename NumberType, detail::enable_if_t < template<typename NumberType, detail::enable_if_t<std::is_integral<NumberType>::value || std::is_same<NumberType, number_unsigned_t>::value || std::is_same<NumberType, number_integer_t>::value || std::is_same<NumberType, binary_char_t>::value, int> = 0>
std::is_integral<NumberType>::value ||
std::is_same<NumberType, number_unsigned_t>::value ||
std::is_same<NumberType, number_integer_t>::value ||
std::is_same<NumberType, binary_char_t>::value,
int > = 0 >
void dump_integer(NumberType x) void dump_integer(NumberType x)
{ {
static constexpr std::array<std::array<char, 2>, 100> digits_to_99 static constexpr std::array<std::array<char, 2>, 100> digits_to_99{
{
{ {
{{'0', '0'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}}, {{'0', '0'}},
{{'1', '0'}}, {{'1', '1'}}, {{'1', '2'}}, {{'1', '3'}}, {{'1', '4'}}, {{'1', '5'}}, {{'1', '6'}}, {{'1', '7'}}, {{'1', '8'}}, {{'1', '9'}}, {{'0', '1'}},
{{'2', '0'}}, {{'2', '1'}}, {{'2', '2'}}, {{'2', '3'}}, {{'2', '4'}}, {{'2', '5'}}, {{'2', '6'}}, {{'2', '7'}}, {{'2', '8'}}, {{'2', '9'}}, {{'0', '2'}},
{{'3', '0'}}, {{'3', '1'}}, {{'3', '2'}}, {{'3', '3'}}, {{'3', '4'}}, {{'3', '5'}}, {{'3', '6'}}, {{'3', '7'}}, {{'3', '8'}}, {{'3', '9'}}, {{'0', '3'}},
{{'4', '0'}}, {{'4', '1'}}, {{'4', '2'}}, {{'4', '3'}}, {{'4', '4'}}, {{'4', '5'}}, {{'4', '6'}}, {{'4', '7'}}, {{'4', '8'}}, {{'4', '9'}}, {{'0', '4'}},
{{'5', '0'}}, {{'5', '1'}}, {{'5', '2'}}, {{'5', '3'}}, {{'5', '4'}}, {{'5', '5'}}, {{'5', '6'}}, {{'5', '7'}}, {{'5', '8'}}, {{'5', '9'}}, {{'0', '5'}},
{{'6', '0'}}, {{'6', '1'}}, {{'6', '2'}}, {{'6', '3'}}, {{'6', '4'}}, {{'6', '5'}}, {{'6', '6'}}, {{'6', '7'}}, {{'6', '8'}}, {{'6', '9'}}, {{'0', '6'}},
{{'7', '0'}}, {{'7', '1'}}, {{'7', '2'}}, {{'7', '3'}}, {{'7', '4'}}, {{'7', '5'}}, {{'7', '6'}}, {{'7', '7'}}, {{'7', '8'}}, {{'7', '9'}}, {{'0', '7'}},
{{'8', '0'}}, {{'8', '1'}}, {{'8', '2'}}, {{'8', '3'}}, {{'8', '4'}}, {{'8', '5'}}, {{'8', '6'}}, {{'8', '7'}}, {{'8', '8'}}, {{'8', '9'}}, {{'0', '8'}},
{{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}}, {{'0', '9'}},
} {{'1', '0'}},
}; {{'1', '1'}},
{{'1', '2'}},
{{'1', '3'}},
{{'1', '4'}},
{{'1', '5'}},
{{'1', '6'}},
{{'1', '7'}},
{{'1', '8'}},
{{'1', '9'}},
{{'2', '0'}},
{{'2', '1'}},
{{'2', '2'}},
{{'2', '3'}},
{{'2', '4'}},
{{'2', '5'}},
{{'2', '6'}},
{{'2', '7'}},
{{'2', '8'}},
{{'2', '9'}},
{{'3', '0'}},
{{'3', '1'}},
{{'3', '2'}},
{{'3', '3'}},
{{'3', '4'}},
{{'3', '5'}},
{{'3', '6'}},
{{'3', '7'}},
{{'3', '8'}},
{{'3', '9'}},
{{'4', '0'}},
{{'4', '1'}},
{{'4', '2'}},
{{'4', '3'}},
{{'4', '4'}},
{{'4', '5'}},
{{'4', '6'}},
{{'4', '7'}},
{{'4', '8'}},
{{'4', '9'}},
{{'5', '0'}},
{{'5', '1'}},
{{'5', '2'}},
{{'5', '3'}},
{{'5', '4'}},
{{'5', '5'}},
{{'5', '6'}},
{{'5', '7'}},
{{'5', '8'}},
{{'5', '9'}},
{{'6', '0'}},
{{'6', '1'}},
{{'6', '2'}},
{{'6', '3'}},
{{'6', '4'}},
{{'6', '5'}},
{{'6', '6'}},
{{'6', '7'}},
{{'6', '8'}},
{{'6', '9'}},
{{'7', '0'}},
{{'7', '1'}},
{{'7', '2'}},
{{'7', '3'}},
{{'7', '4'}},
{{'7', '5'}},
{{'7', '6'}},
{{'7', '7'}},
{{'7', '8'}},
{{'7', '9'}},
{{'8', '0'}},
{{'8', '1'}},
{{'8', '2'}},
{{'8', '3'}},
{{'8', '4'}},
{{'8', '5'}},
{{'8', '6'}},
{{'8', '7'}},
{{'8', '8'}},
{{'8', '9'}},
{{'9', '0'}},
{{'9', '1'}},
{{'9', '2'}},
{{'9', '3'}},
{{'9', '4'}},
{{'9', '5'}},
{{'9', '6'}},
{{'9', '7'}},
{{'9', '8'}},
{{'9', '9'}},
}};
// special case for "0" // special case for "0"
if (x == 0) if (x == 0)
@@ -737,7 +820,7 @@ class serializer
} }
// use a pointer to fill the buffer // use a pointer to fill the buffer
auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg) auto buffer_ptr = number_buffer.begin(); // NOLINT(llvm-qualified-auto,readability-qualified-auto,cppcoreguidelines-pro-type-vararg,hicpp-vararg)
number_unsigned_t abs_value; number_unsigned_t abs_value;
@@ -810,9 +893,8 @@ class serializer
// guaranteed to round-trip, using strtof and strtod, resp. // guaranteed to round-trip, using strtof and strtod, resp.
// //
// NB: The test below works if <long double> == <double>. // NB: The test below works if <long double> == <double>.
static constexpr bool is_ieee_single_or_double static constexpr bool is_ieee_single_or_double = (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128) ||
= (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 24 && std::numeric_limits<number_float_t>::max_exponent == 128) || (std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024);
(std::numeric_limits<number_float_t>::is_iec559 && std::numeric_limits<number_float_t>::digits == 53 && std::numeric_limits<number_float_t>::max_exponent == 1024);
dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>()); dump_float(x, std::integral_constant<bool, is_ieee_single_or_double>());
} }
@@ -864,11 +946,9 @@ class serializer
// determine if we need to append ".0" // determine if we need to append ".0"
const bool value_is_int_like = const bool value_is_int_like =
std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, std::none_of(number_buffer.begin(), number_buffer.begin() + len + 1, [](char c) {
[](char c) return c == '.' || c == 'e';
{ });
return c == '.' || c == 'e';
});
if (value_is_int_like) if (value_is_int_like)
{ {
@@ -900,31 +980,416 @@ class serializer
static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept static std::uint8_t decode(std::uint8_t& state, std::uint32_t& codep, const std::uint8_t byte) noexcept
{ {
static const std::array<std::uint8_t, 400> utf8d = static const std::array<std::uint8_t, 400> utf8d =
{
{ {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1F {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3F 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5F 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7F 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9F 0,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // A0..BF 0,
8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // C0..DF 0,
0xA, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // E0..EF 0,
0xB, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // F0..FF 0,
0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 0,
1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 0,
1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 0,
1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // s7..s8 0,
} 0,
}; 0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0, // 00..1F
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0, // 20..3F
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0, // 40..5F
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0, // 60..7F
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9,
9, // 80..9F
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7,
7, // A0..BF
8,
8,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2, // C0..DF
0xA,
0x3,
0x3,
0x3,
0x3,
0x3,
0x3,
0x3,
0x3,
0x3,
0x3,
0x3,
0x3,
0x4,
0x3,
0x3, // E0..EF
0xB,
0x6,
0x6,
0x6,
0x5,
0x8,
0x8,
0x8,
0x8,
0x8,
0x8,
0x8,
0x8,
0x8,
0x8,
0x8, // F0..FF
0x0,
0x1,
0x2,
0x3,
0x5,
0x8,
0x7,
0x1,
0x1,
0x1,
0x4,
0x6,
0x1,
0x1,
0x1,
0x1, // s0..s0
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
0,
1,
0,
1,
1,
1,
1,
1,
1, // s1..s2
1,
2,
1,
1,
1,
1,
1,
2,
1,
2,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
2,
1,
1,
1,
1,
1,
1,
1,
1, // s3..s4
1,
2,
1,
1,
1,
1,
1,
1,
1,
2,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
3,
1,
3,
1,
1,
1,
1,
1,
1, // s5..s6
1,
3,
1,
1,
1,
1,
1,
3,
1,
3,
1,
1,
1,
1,
1,
1,
1,
3,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1 // s7..s8
}};
JSON_ASSERT(byte < utf8d.size()); JSON_ASSERT(byte < utf8d.size());
const std::uint8_t type = utf8d[byte]; const std::uint8_t type = utf8d[byte];
codep = (state != UTF8_ACCEPT) codep = (state != UTF8_ACCEPT)
? (byte & 0x3fu) | (codep << 6u) ? (byte & 0x3fu) | (codep << 6u)
: (0xFFu >> type) & (byte); : (0xFFu >> type) & (byte);
const std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type); const std::size_t index = 256u + static_cast<size_t>(state) * 16u + static_cast<size_t>(type);
JSON_ASSERT(index < utf8d.size()); JSON_ASSERT(index < utf8d.size());
@@ -939,8 +1404,8 @@ class serializer
*/ */
number_unsigned_t remove_sign(number_unsigned_t x) number_unsigned_t remove_sign(number_unsigned_t x)
{ {
JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE JSON_ASSERT(false); // NOLINT(cert-dcl03-c,hicpp-static-assert,misc-static-assert) LCOV_EXCL_LINE
return x; // LCOV_EXCL_LINE return x; // LCOV_EXCL_LINE
} }
/* /*
@@ -954,7 +1419,7 @@ class serializer
*/ */
inline number_unsigned_t remove_sign(number_integer_t x) noexcept inline number_unsigned_t remove_sign(number_integer_t x) noexcept
{ {
JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)()); // NOLINT(misc-redundant-expression) JSON_ASSERT(x < 0 && x < (std::numeric_limits<number_integer_t>::max)()); // NOLINT(misc-redundant-expression)
return static_cast<number_unsigned_t>(-(x + 1)) + 1; return static_cast<number_unsigned_t>(-(x + 1)) + 1;
} }
+26 -46
View File
@@ -8,16 +8,15 @@
#pragma once #pragma once
#include <cstring> // strlen #include <cstring> // strlen
#include <string> // string #include <string> // string
#include <utility> // forward #include <utility> // forward
#include <nlohmann/detail/meta/cpp_future.hpp> #include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/meta/detected.hpp> #include <nlohmann/detail/meta/detected.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
inline std::size_t concat_length() inline std::size_t concat_length()
{ {
@@ -25,26 +24,26 @@ inline std::size_t concat_length()
} }
template<typename... Args> template<typename... Args>
inline std::size_t concat_length(const char* cstr, const Args& ... rest); inline std::size_t concat_length(const char* cstr, const Args&... rest);
template<typename StringType, typename... Args> template<typename StringType, typename... Args>
inline std::size_t concat_length(const StringType& str, const Args& ... rest); inline std::size_t concat_length(const StringType& str, const Args&... rest);
template<typename... Args> template<typename... Args>
inline std::size_t concat_length(const char /*c*/, const Args& ... rest) inline std::size_t concat_length(const char /*c*/, const Args&... rest)
{ {
return 1 + concat_length(rest...); return 1 + concat_length(rest...);
} }
template<typename... Args> template<typename... Args>
inline std::size_t concat_length(const char* cstr, const Args& ... rest) inline std::size_t concat_length(const char* cstr, const Args&... rest)
{ {
// cppcheck-suppress ignoredReturnValue // cppcheck-suppress ignoredReturnValue
return ::strlen(cstr) + concat_length(rest...); return ::strlen(cstr) + concat_length(rest...);
} }
template<typename StringType, typename... Args> template<typename StringType, typename... Args>
inline std::size_t concat_length(const StringType& str, const Args& ... rest) inline std::size_t concat_length(const StringType& str, const Args&... rest)
{ {
return str.size() + concat_length(rest...); return str.size() + concat_length(rest...);
} }
@@ -54,13 +53,13 @@ inline void concat_into(OutStringType& /*out*/)
{} {}
template<typename StringType, typename Arg> template<typename StringType, typename Arg>
using string_can_append = decltype(std::declval<StringType&>().append(std::declval < Arg && > ())); using string_can_append = decltype(std::declval<StringType&>().append(std::declval<Arg&&>()));
template<typename StringType, typename Arg> template<typename StringType, typename Arg>
using detect_string_can_append = is_detected<string_can_append, StringType, Arg>; using detect_string_can_append = is_detected<string_can_append, StringType, Arg>;
template<typename StringType, typename Arg> template<typename StringType, typename Arg>
using string_can_append_op = decltype(std::declval<StringType&>() += std::declval < Arg && > ()); using string_can_append_op = decltype(std::declval<StringType&>() += std::declval<Arg&&>());
template<typename StringType, typename Arg> template<typename StringType, typename Arg>
using detect_string_can_append_op = is_detected<string_can_append_op, StringType, Arg>; using detect_string_can_append_op = is_detected<string_can_append_op, StringType, Arg>;
@@ -77,64 +76,45 @@ using string_can_append_data = decltype(std::declval<StringType&>().append(std::
template<typename StringType, typename Arg> template<typename StringType, typename Arg>
using detect_string_can_append_data = is_detected<string_can_append_data, StringType, Arg>; using detect_string_can_append_data = is_detected<string_can_append_data, StringType, Arg>;
template < typename OutStringType, typename Arg, typename... Args, template<typename OutStringType, typename Arg, typename... Args, enable_if_t<!detect_string_can_append<OutStringType, Arg>::value && detect_string_can_append_op<OutStringType, Arg>::value, int> = 0>
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value inline void concat_into(OutStringType& out, Arg&& arg, Args&&... rest);
&& detect_string_can_append_op<OutStringType, Arg>::value, int > = 0 >
inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest);
template < typename OutStringType, typename Arg, typename... Args, template<typename OutStringType, typename Arg, typename... Args, enable_if_t<!detect_string_can_append<OutStringType, Arg>::value && !detect_string_can_append_op<OutStringType, Arg>::value && detect_string_can_append_iter<OutStringType, Arg>::value, int> = 0>
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value inline void concat_into(OutStringType& out, const Arg& arg, Args&&... rest);
&& !detect_string_can_append_op<OutStringType, Arg>::value
&& detect_string_can_append_iter<OutStringType, Arg>::value, int > = 0 >
inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);
template < typename OutStringType, typename Arg, typename... Args, template<typename OutStringType, typename Arg, typename... Args, enable_if_t<!detect_string_can_append<OutStringType, Arg>::value && !detect_string_can_append_op<OutStringType, Arg>::value && !detect_string_can_append_iter<OutStringType, Arg>::value && detect_string_can_append_data<OutStringType, Arg>::value, int> = 0>
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value inline void concat_into(OutStringType& out, const Arg& arg, Args&&... rest);
&& !detect_string_can_append_op<OutStringType, Arg>::value
&& !detect_string_can_append_iter<OutStringType, Arg>::value
&& detect_string_can_append_data<OutStringType, Arg>::value, int > = 0 >
inline void concat_into(OutStringType& out, const Arg& arg, Args && ... rest);
template<typename OutStringType, typename Arg, typename... Args, template<typename OutStringType, typename Arg, typename... Args, enable_if_t<detect_string_can_append<OutStringType, Arg>::value, int> = 0>
enable_if_t<detect_string_can_append<OutStringType, Arg>::value, int> = 0> inline void concat_into(OutStringType& out, Arg&& arg, Args&&... rest)
inline void concat_into(OutStringType& out, Arg && arg, Args && ... rest)
{ {
out.append(std::forward<Arg>(arg)); out.append(std::forward<Arg>(arg));
concat_into(out, std::forward<Args>(rest)...); concat_into(out, std::forward<Args>(rest)...);
} }
template < typename OutStringType, typename Arg, typename... Args, template<typename OutStringType, typename Arg, typename... Args, enable_if_t<!detect_string_can_append<OutStringType, Arg>::value && detect_string_can_append_op<OutStringType, Arg>::value, int>>
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value inline void concat_into(OutStringType& out, Arg&& arg, Args&&... rest)
&& detect_string_can_append_op<OutStringType, Arg>::value, int > >
inline void concat_into(OutStringType& out, Arg&& arg, Args&& ... rest)
{ {
out += std::forward<Arg>(arg); out += std::forward<Arg>(arg);
concat_into(out, std::forward<Args>(rest)...); concat_into(out, std::forward<Args>(rest)...);
} }
template < typename OutStringType, typename Arg, typename... Args, template<typename OutStringType, typename Arg, typename... Args, enable_if_t<!detect_string_can_append<OutStringType, Arg>::value && !detect_string_can_append_op<OutStringType, Arg>::value && detect_string_can_append_iter<OutStringType, Arg>::value, int>>
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value inline void concat_into(OutStringType& out, const Arg& arg, Args&&... rest)
&& !detect_string_can_append_op<OutStringType, Arg>::value
&& detect_string_can_append_iter<OutStringType, Arg>::value, int > >
inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)
{ {
out.append(arg.begin(), arg.end()); out.append(arg.begin(), arg.end());
concat_into(out, std::forward<Args>(rest)...); concat_into(out, std::forward<Args>(rest)...);
} }
template < typename OutStringType, typename Arg, typename... Args, template<typename OutStringType, typename Arg, typename... Args, enable_if_t<!detect_string_can_append<OutStringType, Arg>::value && !detect_string_can_append_op<OutStringType, Arg>::value && !detect_string_can_append_iter<OutStringType, Arg>::value && detect_string_can_append_data<OutStringType, Arg>::value, int>>
enable_if_t < !detect_string_can_append<OutStringType, Arg>::value inline void concat_into(OutStringType& out, const Arg& arg, Args&&... rest)
&& !detect_string_can_append_op<OutStringType, Arg>::value
&& !detect_string_can_append_iter<OutStringType, Arg>::value
&& detect_string_can_append_data<OutStringType, Arg>::value, int > >
inline void concat_into(OutStringType& out, const Arg& arg, Args&& ... rest)
{ {
out.append(arg.data(), arg.size()); out.append(arg.data(), arg.size());
concat_into(out, std::forward<Args>(rest)...); concat_into(out, std::forward<Args>(rest)...);
} }
template<typename OutStringType = std::string, typename... Args> template<typename OutStringType = std::string, typename... Args>
inline OutStringType concat(Args && ... args) inline OutStringType concat(Args&&... args)
{ {
OutStringType str; OutStringType str;
str.reserve(concat_length(args...)); str.reserve(concat_length(args...));
+6 -8
View File
@@ -11,8 +11,7 @@
#include <nlohmann/detail/abi_macros.hpp> #include <nlohmann/detail/abi_macros.hpp>
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
/*! /*!
@brief replace all occurrences of a substring by another string @brief replace all occurrences of a substring by another string
@@ -28,14 +27,13 @@ enforced with an assertion.**
@since version 2.0.0 @since version 2.0.0
*/ */
template<typename StringType> template<typename StringType>
inline void replace_substring(StringType& s, const StringType& f, inline void replace_substring(StringType& s, const StringType& f, const StringType& t)
const StringType& t)
{ {
JSON_ASSERT(!f.empty()); JSON_ASSERT(!f.empty());
for (auto pos = s.find(f); // find first occurrence of f for (auto pos = s.find(f); // find first occurrence of f
pos != StringType::npos; // make sure f was found pos != StringType::npos; // make sure f was found
s.replace(pos, f.size(), t), // replace with t, and s.replace(pos, f.size(), t), // replace with t, and
pos = s.find(f, pos + t.size())) // find next occurrence of f pos = s.find(f, pos + t.size())) // find next occurrence of f
{} {}
} }
+20 -16
View File
@@ -8,19 +8,18 @@
#pragma once #pragma once
#include <array> // array #include <array> // array
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdint> // uint8_t #include <cstdint> // uint8_t
#include <string> // string #include <string> // string
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
#if JSON_HAS_THREE_WAY_COMPARISON #if JSON_HAS_THREE_WAY_COMPARISON
#include <compare> // partial_ordering #include <compare> // partial_ordering
#endif #endif
NLOHMANN_JSON_NAMESPACE_BEGIN NLOHMANN_JSON_NAMESPACE_BEGIN
namespace detail namespace detail {
{
/////////////////////////// ///////////////////////////
// JSON type enumeration // // JSON type enumeration //
@@ -78,24 +77,29 @@ Returns an ordering that is similar to Python:
@since version 1.0.0 @since version 1.0.0
*/ */
#if JSON_HAS_THREE_WAY_COMPARISON #if JSON_HAS_THREE_WAY_COMPARISON
inline std::partial_ordering operator<=>(const value_t lhs, const value_t rhs) noexcept // *NOPAD* inline std::partial_ordering operator<= > (const value_t lhs, const value_t rhs) noexcept // *NOPAD*
#else #else
inline bool operator<(const value_t lhs, const value_t rhs) noexcept inline bool operator<(const value_t lhs, const value_t rhs) noexcept
#endif #endif
{ {
static constexpr std::array<std::uint8_t, 9> order = {{ static constexpr std::array<std::uint8_t, 9> order = {{
0 /* null */, 3 /* object */, 4 /* array */, 5 /* string */, 0 /* null */,
1 /* boolean */, 2 /* integer */, 2 /* unsigned */, 2 /* float */, 3 /* object */,
6 /* binary */ 4 /* array */,
} 5 /* string */,
}; 1 /* boolean */,
2 /* integer */,
2 /* unsigned */,
2 /* float */,
6 /* binary */
}};
const auto l_index = static_cast<std::size_t>(lhs); const auto l_index = static_cast<std::size_t>(lhs);
const auto r_index = static_cast<std::size_t>(rhs); const auto r_index = static_cast<std::size_t>(rhs);
#if JSON_HAS_THREE_WAY_COMPARISON #if JSON_HAS_THREE_WAY_COMPARISON
if (l_index < order.size() && r_index < order.size()) if (l_index < order.size() && r_index < order.size())
{ {
return order[l_index] <=> order[r_index]; // *NOPAD* return order[l_index] <= > order[r_index]; // *NOPAD*
} }
return std::partial_ordering::unordered; return std::partial_ordering::unordered;
#else #else
@@ -110,7 +114,7 @@ Returns an ordering that is similar to Python:
#if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__) #if JSON_HAS_THREE_WAY_COMPARISON && defined(__GNUC__)
inline bool operator<(const value_t lhs, const value_t rhs) noexcept inline bool operator<(const value_t lhs, const value_t rhs) noexcept
{ {
return std::is_lt(lhs <=> rhs); // *NOPAD* return std::is_lt(lhs <= > rhs); // *NOPAD*
} }
#endif #endif
+512 -614
View File
File diff suppressed because it is too large. Load diff
+10 -9
View File
@@ -9,11 +9,11 @@
#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ #ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
#define INCLUDE_NLOHMANN_JSON_FWD_HPP_ #define INCLUDE_NLOHMANN_JSON_FWD_HPP_
#include <cstdint> // int64_t, uint64_t #include <cstdint> // int64_t, uint64_t
#include <map> // map #include <map> // map
#include <memory> // allocator #include <memory> // allocator
#include <string> // string #include <string> // string
#include <vector> // vector #include <vector> // vector
#include <nlohmann/detail/abi_macros.hpp> #include <nlohmann/detail/abi_macros.hpp>
@@ -37,16 +37,17 @@ struct adl_serializer;
/// a class to store JSON values /// a class to store JSON values
/// @sa https://json.nlohmann.me/api/basic_json/ /// @sa https://json.nlohmann.me/api/basic_json/
template<template<typename U, typename V, typename... Args> class ObjectType = template<template<typename U, typename V, typename... Args> class ObjectType =
std::map, std::map,
template<typename U, typename... Args> class ArrayType = std::vector, template<typename U, typename... Args> class ArrayType = std::vector,
class StringType = std::string, class BooleanType = bool, class StringType = std::string,
class BooleanType = bool,
class NumberIntegerType = std::int64_t, class NumberIntegerType = std::int64_t,
class NumberUnsignedType = std::uint64_t, class NumberUnsignedType = std::uint64_t,
class NumberFloatType = double, class NumberFloatType = double,
template<typename U> class AllocatorType = std::allocator, template<typename U> class AllocatorType = std::allocator,
template<typename T, typename SFINAE = void> class JSONSerializer = template<typename T, typename SFINAE = void> class JSONSerializer =
adl_serializer, adl_serializer,
class BinaryType = std::vector<std::uint8_t>, // cppcheck-suppress syntaxError class BinaryType = std::vector<std::uint8_t>, // cppcheck-suppress syntaxError
class CustomBaseClass = void> class CustomBaseClass = void>
class basic_json; class basic_json;
+46 -49
View File
@@ -8,14 +8,14 @@
#pragma once #pragma once
#include <functional> // equal_to, less #include <functional> // equal_to, less
#include <initializer_list> // initializer_list #include <initializer_list> // initializer_list
#include <iterator> // input_iterator_tag, iterator_traits #include <iterator> // input_iterator_tag, iterator_traits
#include <memory> // allocator #include <memory> // allocator
#include <stdexcept> // for out_of_range #include <stdexcept> // for out_of_range
#include <type_traits> // enable_if, is_convertible #include <type_traits> // enable_if, is_convertible
#include <utility> // pair #include <utility> // pair
#include <vector> // vector #include <vector> // vector
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/meta/type_traits.hpp>
@@ -24,9 +24,8 @@ NLOHMANN_JSON_NAMESPACE_BEGIN
/// ordered_map: a minimal map-like container that preserves insertion order /// ordered_map: a minimal map-like container that preserves insertion order
/// for use within nlohmann::basic_json<ordered_map> /// for use within nlohmann::basic_json<ordered_map>
template <class Key, class T, class IgnoredLess = std::less<Key>, template<class Key, class T, class IgnoredLess = std::less<Key>, class Allocator = std::allocator<std::pair<const Key, T>>>
class Allocator = std::allocator<std::pair<const Key, T>>> struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>
struct ordered_map : std::vector<std::pair<const Key, T>, Allocator>
{ {
using key_type = Key; using key_type = Key;
using mapped_type = T; using mapped_type = T;
@@ -43,13 +42,19 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
// Explicit constructors instead of `using Container::Container` // Explicit constructors instead of `using Container::Container`
// otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4) // otherwise older compilers choke on it (GCC <= 5.5, xcode <= 9.4)
ordered_map() noexcept(noexcept(Container())) : Container{} {} ordered_map() noexcept(noexcept(Container()))
explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc))) : Container{alloc} {} : Container{}
template <class It> {}
explicit ordered_map(const Allocator& alloc) noexcept(noexcept(Container(alloc)))
: Container{alloc}
{}
template<class It>
ordered_map(It first, It last, const Allocator& alloc = Allocator()) ordered_map(It first, It last, const Allocator& alloc = Allocator())
: Container{first, last, alloc} {} : Container{first, last, alloc}
ordered_map(std::initializer_list<value_type> init, const Allocator& alloc = Allocator() ) {}
: Container{init, alloc} {} ordered_map(std::initializer_list<value_type> init, const Allocator& alloc = Allocator())
: Container{init, alloc}
{}
std::pair<iterator, bool> emplace(const key_type& key, T&& t) std::pair<iterator, bool> emplace(const key_type& key, T&& t)
{ {
@@ -64,9 +69,8 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
return {std::prev(this->end()), true}; return {std::prev(this->end()), true};
} }
template<class KeyType, detail::enable_if_t< template<class KeyType, detail::enable_if_t<detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> std::pair<iterator, bool> emplace(KeyType&& key, T&& t)
std::pair<iterator, bool> emplace(KeyType && key, T && t)
{ {
for (auto it = this->begin(); it != this->end(); ++it) for (auto it = this->begin(); it != this->end(); ++it)
{ {
@@ -84,9 +88,8 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
return emplace(key, T{}).first->second; return emplace(key, T{}).first->second;
} }
template<class KeyType, detail::enable_if_t< template<class KeyType, detail::enable_if_t<detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> T& operator[](KeyType&& key)
T & operator[](KeyType && key)
{ {
return emplace(std::forward<KeyType>(key), T{}).first->second; return emplace(std::forward<KeyType>(key), T{}).first->second;
} }
@@ -96,9 +99,8 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
return at(key); return at(key);
} }
template<class KeyType, detail::enable_if_t< template<class KeyType, detail::enable_if_t<detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> const T& operator[](KeyType&& key) const
const T & operator[](KeyType && key) const
{ {
return at(std::forward<KeyType>(key)); return at(std::forward<KeyType>(key));
} }
@@ -116,9 +118,8 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
JSON_THROW(std::out_of_range("key not found")); JSON_THROW(std::out_of_range("key not found"));
} }
template<class KeyType, detail::enable_if_t< template<class KeyType, detail::enable_if_t<detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> T& at(KeyType&& key) // NOLINT(cppcoreguidelines-missing-std-forward)
T & at(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
{ {
for (auto it = this->begin(); it != this->end(); ++it) for (auto it = this->begin(); it != this->end(); ++it)
{ {
@@ -144,9 +145,8 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
JSON_THROW(std::out_of_range("key not found")); JSON_THROW(std::out_of_range("key not found"));
} }
template<class KeyType, detail::enable_if_t< template<class KeyType, detail::enable_if_t<detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> const T& at(KeyType&& key) const // NOLINT(cppcoreguidelines-missing-std-forward)
const T & at(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
{ {
for (auto it = this->begin(); it != this->end(); ++it) for (auto it = this->begin(); it != this->end(); ++it)
{ {
@@ -168,7 +168,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
// Since we cannot move const Keys, re-construct them in place // Since we cannot move const Keys, re-construct them in place
for (auto next = it; ++next != this->end(); ++it) for (auto next = it; ++next != this->end(); ++it)
{ {
it->~value_type(); // Destroy but keep allocation it->~value_type(); // Destroy but keep allocation
new (&*it) value_type{std::move(*next)}; new (&*it) value_type{std::move(*next)};
} }
Container::pop_back(); Container::pop_back();
@@ -178,9 +178,8 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
return 0; return 0;
} }
template<class KeyType, detail::enable_if_t< template<class KeyType, detail::enable_if_t<detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> size_type erase(KeyType&& key) // NOLINT(cppcoreguidelines-missing-std-forward)
size_type erase(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
{ {
for (auto it = this->begin(); it != this->end(); ++it) for (auto it = this->begin(); it != this->end(); ++it)
{ {
@@ -189,7 +188,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
// Since we cannot move const Keys, re-construct them in place // Since we cannot move const Keys, re-construct them in place
for (auto next = it; ++next != this->end(); ++it) for (auto next = it; ++next != this->end(); ++it)
{ {
it->~value_type(); // Destroy but keep allocation it->~value_type(); // Destroy but keep allocation
new (&*it) value_type{std::move(*next)}; new (&*it) value_type{std::move(*next)};
} }
Container::pop_back(); Container::pop_back();
@@ -236,8 +235,8 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it) for (auto it = first; std::next(it, elements_affected) != Container::end(); ++it)
{ {
it->~value_type(); // destroy but keep allocation it->~value_type(); // destroy but keep allocation
new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it new (&*it) value_type{std::move(*std::next(it, elements_affected))}; // "move" next element to it
} }
// [ a, b, c, d, h, i, j, h, i, j ] // [ a, b, c, d, h, i, j, h, i, j ]
@@ -269,9 +268,8 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
return 0; return 0;
} }
template<class KeyType, detail::enable_if_t< template<class KeyType, detail::enable_if_t<detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> size_type count(KeyType&& key) const // NOLINT(cppcoreguidelines-missing-std-forward)
size_type count(KeyType && key) const // NOLINT(cppcoreguidelines-missing-std-forward)
{ {
for (auto it = this->begin(); it != this->end(); ++it) for (auto it = this->begin(); it != this->end(); ++it)
{ {
@@ -295,9 +293,8 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
return Container::end(); return Container::end();
} }
template<class KeyType, detail::enable_if_t< template<class KeyType, detail::enable_if_t<detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0>
detail::is_usable_as_key_type<key_compare, key_type, KeyType>::value, int> = 0> iterator find(KeyType&& key) // NOLINT(cppcoreguidelines-missing-std-forward)
iterator find(KeyType && key) // NOLINT(cppcoreguidelines-missing-std-forward)
{ {
for (auto it = this->begin(); it != this->end(); ++it) for (auto it = this->begin(); it != this->end(); ++it)
{ {
@@ -321,12 +318,12 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
return Container::end(); return Container::end();
} }
std::pair<iterator, bool> insert( value_type&& value ) std::pair<iterator, bool> insert(value_type&& value)
{ {
return emplace(value.first, std::move(value.second)); return emplace(value.first, std::move(value.second));
} }
std::pair<iterator, bool> insert( const value_type& value ) std::pair<iterator, bool> insert(const value_type& value)
{ {
for (auto it = this->begin(); it != this->end(); ++it) for (auto it = this->begin(); it != this->end(); ++it)
{ {
@@ -341,7 +338,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
template<typename InputIt> template<typename InputIt>
using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category, using require_input_iter = typename std::enable_if<std::is_convertible<typename std::iterator_traits<InputIt>::iterator_category,
std::input_iterator_tag>::value>::type; std::input_iterator_tag>::value>::type;
template<typename InputIt, typename = require_input_iter<InputIt>> template<typename InputIt, typename = require_input_iter<InputIt>>
void insert(InputIt first, InputIt last) void insert(InputIt first, InputIt last)
@@ -352,7 +349,7 @@ template <class Key, class T, class IgnoredLess = std::less<Key>,
} }
} }
private: private:
JSON_NO_UNIQUE_ADDRESS key_compare m_compare = key_compare(); JSON_NO_UNIQUE_ADDRESS key_compare m_compare = key_compare();
}; };
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+33 -37
View File
@@ -9,11 +9,11 @@
#ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_ #ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
#define INCLUDE_NLOHMANN_JSON_FWD_HPP_ #define INCLUDE_NLOHMANN_JSON_FWD_HPP_
#include <cstdint> // int64_t, uint64_t #include <cstdint> // int64_t, uint64_t
#include <map> // map #include <map> // map
#include <memory> // allocator #include <memory> // allocator
#include <string> // string #include <string> // string
#include <vector> // vector #include <vector> // vector
// #include <nlohmann/detail/abi_macros.hpp> // #include <nlohmann/detail/abi_macros.hpp>
// __ _____ _____ _____ // __ _____ _____ _____
@@ -24,8 +24,6 @@
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
// This file contains all macro definitions affecting or depending on the ABI // This file contains all macro definitions affecting or depending on the ABI
#ifndef JSON_SKIP_LIBRARY_VERSION_CHECK #ifndef JSON_SKIP_LIBRARY_VERSION_CHECK
@@ -65,59 +63,56 @@
#endif #endif
// Construct the namespace ABI tags component // Construct the namespace ABI tags component
#define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi ## a ## b #define NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) json_abi##a##b
#define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \ #define NLOHMANN_JSON_ABI_TAGS_CONCAT(a, b) \
NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b) NLOHMANN_JSON_ABI_TAGS_CONCAT_EX(a, b)
#define NLOHMANN_JSON_ABI_TAGS \ #define NLOHMANN_JSON_ABI_TAGS \
NLOHMANN_JSON_ABI_TAGS_CONCAT( \ NLOHMANN_JSON_ABI_TAGS_CONCAT( \
NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \ NLOHMANN_JSON_ABI_TAG_DIAGNOSTICS, \
NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON) NLOHMANN_JSON_ABI_TAG_LEGACY_DISCARDED_VALUE_COMPARISON)
// Construct the namespace version component // Construct the namespace version component
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \ #define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) \
_v ## major ## _ ## minor ## _ ## patch _v##major##_##minor##_##patch
#define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \ #define NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(major, minor, patch) \
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch) NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT_EX(major, minor, patch)
#if NLOHMANN_JSON_NAMESPACE_NO_VERSION #if NLOHMANN_JSON_NAMESPACE_NO_VERSION
#define NLOHMANN_JSON_NAMESPACE_VERSION #define NLOHMANN_JSON_NAMESPACE_VERSION
#else #else
#define NLOHMANN_JSON_NAMESPACE_VERSION \ #define NLOHMANN_JSON_NAMESPACE_VERSION \
NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \ NLOHMANN_JSON_NAMESPACE_VERSION_CONCAT(NLOHMANN_JSON_VERSION_MAJOR, \
NLOHMANN_JSON_VERSION_MINOR, \ NLOHMANN_JSON_VERSION_MINOR, \
NLOHMANN_JSON_VERSION_PATCH) NLOHMANN_JSON_VERSION_PATCH)
#endif #endif
// Combine namespace components // Combine namespace components
#define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a ## b #define NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) a##b
#define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \ #define NLOHMANN_JSON_NAMESPACE_CONCAT(a, b) \
NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b) NLOHMANN_JSON_NAMESPACE_CONCAT_EX(a, b)
#ifndef NLOHMANN_JSON_NAMESPACE #ifndef NLOHMANN_JSON_NAMESPACE
#define NLOHMANN_JSON_NAMESPACE \ #define NLOHMANN_JSON_NAMESPACE \
nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \ nlohmann::NLOHMANN_JSON_NAMESPACE_CONCAT( \
NLOHMANN_JSON_ABI_TAGS, \ NLOHMANN_JSON_ABI_TAGS, \
NLOHMANN_JSON_NAMESPACE_VERSION) NLOHMANN_JSON_NAMESPACE_VERSION)
#endif #endif
#ifndef NLOHMANN_JSON_NAMESPACE_BEGIN #ifndef NLOHMANN_JSON_NAMESPACE_BEGIN
#define NLOHMANN_JSON_NAMESPACE_BEGIN \ #define NLOHMANN_JSON_NAMESPACE_BEGIN \
namespace nlohmann \ namespace nlohmann { \
{ \ inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \
inline namespace NLOHMANN_JSON_NAMESPACE_CONCAT( \ NLOHMANN_JSON_ABI_TAGS, \
NLOHMANN_JSON_ABI_TAGS, \ NLOHMANN_JSON_NAMESPACE_VERSION) {
NLOHMANN_JSON_NAMESPACE_VERSION) \
{
#endif #endif
#ifndef NLOHMANN_JSON_NAMESPACE_END #ifndef NLOHMANN_JSON_NAMESPACE_END
#define NLOHMANN_JSON_NAMESPACE_END \ #define NLOHMANN_JSON_NAMESPACE_END \
} /* namespace (inline namespace) NOLINT(readability/namespace) */ \ } /* namespace (inline namespace) NOLINT(readability/namespace) */ \
} // namespace nlohmann } // namespace nlohmann
#endif #endif
/*! /*!
@brief namespace for Niels Lohmann @brief namespace for Niels Lohmann
@see https://github.com/nlohmann @see https://github.com/nlohmann
@@ -138,16 +133,17 @@ struct adl_serializer;
/// a class to store JSON values /// a class to store JSON values
/// @sa https://json.nlohmann.me/api/basic_json/ /// @sa https://json.nlohmann.me/api/basic_json/
template<template<typename U, typename V, typename... Args> class ObjectType = template<template<typename U, typename V, typename... Args> class ObjectType =
std::map, std::map,
template<typename U, typename... Args> class ArrayType = std::vector, template<typename U, typename... Args> class ArrayType = std::vector,
class StringType = std::string, class BooleanType = bool, class StringType = std::string,
class BooleanType = bool,
class NumberIntegerType = std::int64_t, class NumberIntegerType = std::int64_t,
class NumberUnsignedType = std::uint64_t, class NumberUnsignedType = std::uint64_t,
class NumberFloatType = double, class NumberFloatType = double,
template<typename U> class AllocatorType = std::allocator, template<typename U> class AllocatorType = std::allocator,
template<typename T, typename SFINAE = void> class JSONSerializer = template<typename T, typename SFINAE = void> class JSONSerializer =
adl_serializer, adl_serializer,
class BinaryType = std::vector<std::uint8_t>, // cppcheck-suppress syntaxError class BinaryType = std::vector<std::uint8_t>, // cppcheck-suppress syntaxError
class CustomBaseClass = void> class CustomBaseClass = void>
class basic_json; class basic_json;
+1 -1
View File
@@ -18,7 +18,7 @@
#define STRINGIZE(x) STRINGIZE_EX(x) #define STRINGIZE(x) STRINGIZE_EX(x)
template<typename T> template<typename T>
std::string namespace_name(std::string ns, T* /*unused*/ = nullptr) // NOLINT(performance-unnecessary-value-param) std::string namespace_name(std::string ns, T* /*unused*/ = nullptr) // NOLINT(performance-unnecessary-value-param)
{ {
#if DOCTEST_MSVC && !DOCTEST_CLANG #if DOCTEST_MSVC && !DOCTEST_CLANG
ns = __FUNCSIG__; ns = __FUNCSIG__;
+1 -1
View File
@@ -11,7 +11,7 @@
#include "config.hpp" #include "config.hpp"
// define custom namespace // define custom namespace
#define NLOHMANN_JSON_NAMESPACE nlohmann // this line may be omitted #define NLOHMANN_JSON_NAMESPACE nlohmann // this line may be omitted
#define NLOHMANN_JSON_NAMESPACE_BEGIN namespace nlohmann { #define NLOHMANN_JSON_NAMESPACE_BEGIN namespace nlohmann {
#define NLOHMANN_JSON_NAMESPACE_END } #define NLOHMANN_JSON_NAMESPACE_END }
#include <nlohmann/json_fwd.hpp> #include <nlohmann/json_fwd.hpp>
+4 -4
View File
@@ -20,13 +20,13 @@ TEST_CASE("default namespace")
{ {
std::string expected = "nlohmann::json_abi"; std::string expected = "nlohmann::json_abi";
#if JSON_DIAGNOSTICS #if JSON_DIAGNOSTICS
expected += "_diag"; expected += "_diag";
#endif #endif
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
expected += "_ldvcmp"; expected += "_ldvcmp";
#endif #endif
expected += "_v" STRINGIZE(NLOHMANN_JSON_VERSION_MAJOR); expected += "_v" STRINGIZE(NLOHMANN_JSON_VERSION_MAJOR);
expected += "_" STRINGIZE(NLOHMANN_JSON_VERSION_MINOR); expected += "_" STRINGIZE(NLOHMANN_JSON_VERSION_MINOR);
+4 -4
View File
@@ -21,13 +21,13 @@ TEST_CASE("default namespace without version component")
{ {
std::string expected = "nlohmann::json_abi"; std::string expected = "nlohmann::json_abi";
#if JSON_DIAGNOSTICS #if JSON_DIAGNOSTICS
expected += "_diag"; expected += "_diag";
#endif #endif
#if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON #if JSON_USE_LEGACY_DISCARDED_VALUE_COMPARISON
expected += "_ldvcmp"; expected += "_ldvcmp";
#endif #endif
expected += "::basic_json"; expected += "::basic_json";
+39 -39
View File
@@ -7,11 +7,11 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include <benchmark/benchmark.h> #include <benchmark/benchmark.h>
#include <nlohmann/json.hpp>
#include <fstream> #include <fstream>
#include <nlohmann/json.hpp>
#include <numeric> #include <numeric>
#include <vector>
#include <test_data.hpp> #include <test_data.hpp>
#include <vector>
using json = nlohmann::json; using json = nlohmann::json;
@@ -39,13 +39,13 @@ static void ParseFile(benchmark::State& state, const char* filename)
std::ifstream file(filename, std::ios::binary | std::ios::ate); std::ifstream file(filename, std::ios::binary | std::ios::ate);
state.SetBytesProcessed(state.iterations() * file.tellg()); state.SetBytesProcessed(state.iterations() * file.tellg());
} }
BENCHMARK_CAPTURE(ParseFile, jeopardy, TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json"); BENCHMARK_CAPTURE(ParseFile, jeopardy, TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json");
BENCHMARK_CAPTURE(ParseFile, canada, TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json"); BENCHMARK_CAPTURE(ParseFile, canada, TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json");
BENCHMARK_CAPTURE(ParseFile, citm_catalog, TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json"); BENCHMARK_CAPTURE(ParseFile, citm_catalog, TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json");
BENCHMARK_CAPTURE(ParseFile, twitter, TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json"); BENCHMARK_CAPTURE(ParseFile, twitter, TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json");
BENCHMARK_CAPTURE(ParseFile, floats, TEST_DATA_DIRECTORY "/regression/floats.json"); BENCHMARK_CAPTURE(ParseFile, floats, TEST_DATA_DIRECTORY "/regression/floats.json");
BENCHMARK_CAPTURE(ParseFile, signed_ints, TEST_DATA_DIRECTORY "/regression/signed_ints.json"); BENCHMARK_CAPTURE(ParseFile, signed_ints, TEST_DATA_DIRECTORY "/regression/signed_ints.json");
BENCHMARK_CAPTURE(ParseFile, unsigned_ints, TEST_DATA_DIRECTORY "/regression/unsigned_ints.json"); BENCHMARK_CAPTURE(ParseFile, unsigned_ints, TEST_DATA_DIRECTORY "/regression/unsigned_ints.json");
BENCHMARK_CAPTURE(ParseFile, small_signed_ints, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json"); BENCHMARK_CAPTURE(ParseFile, small_signed_ints, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json");
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@@ -72,13 +72,13 @@ static void ParseString(benchmark::State& state, const char* filename)
state.SetBytesProcessed(state.iterations() * str.size()); state.SetBytesProcessed(state.iterations() * str.size());
} }
BENCHMARK_CAPTURE(ParseString, jeopardy, TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json"); BENCHMARK_CAPTURE(ParseString, jeopardy, TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json");
BENCHMARK_CAPTURE(ParseString, canada, TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json"); BENCHMARK_CAPTURE(ParseString, canada, TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json");
BENCHMARK_CAPTURE(ParseString, citm_catalog, TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json"); BENCHMARK_CAPTURE(ParseString, citm_catalog, TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json");
BENCHMARK_CAPTURE(ParseString, twitter, TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json"); BENCHMARK_CAPTURE(ParseString, twitter, TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json");
BENCHMARK_CAPTURE(ParseString, floats, TEST_DATA_DIRECTORY "/regression/floats.json"); BENCHMARK_CAPTURE(ParseString, floats, TEST_DATA_DIRECTORY "/regression/floats.json");
BENCHMARK_CAPTURE(ParseString, signed_ints, TEST_DATA_DIRECTORY "/regression/signed_ints.json"); BENCHMARK_CAPTURE(ParseString, signed_ints, TEST_DATA_DIRECTORY "/regression/signed_ints.json");
BENCHMARK_CAPTURE(ParseString, unsigned_ints, TEST_DATA_DIRECTORY "/regression/unsigned_ints.json"); BENCHMARK_CAPTURE(ParseString, unsigned_ints, TEST_DATA_DIRECTORY "/regression/unsigned_ints.json");
BENCHMARK_CAPTURE(ParseString, small_signed_ints, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json"); BENCHMARK_CAPTURE(ParseString, small_signed_ints, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json");
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@@ -98,22 +98,22 @@ static void Dump(benchmark::State& state, const char* filename, int indent)
state.SetBytesProcessed(state.iterations() * j.dump(indent).size()); state.SetBytesProcessed(state.iterations() * j.dump(indent).size());
} }
BENCHMARK_CAPTURE(Dump, jeopardy / -, TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json", -1); BENCHMARK_CAPTURE(Dump, jeopardy / -, TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json", -1);
BENCHMARK_CAPTURE(Dump, jeopardy / 4, TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json", 4); BENCHMARK_CAPTURE(Dump, jeopardy / 4, TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json", 4);
BENCHMARK_CAPTURE(Dump, canada / -, TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json", -1); BENCHMARK_CAPTURE(Dump, canada / -, TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json", -1);
BENCHMARK_CAPTURE(Dump, canada / 4, TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json", 4); BENCHMARK_CAPTURE(Dump, canada / 4, TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json", 4);
BENCHMARK_CAPTURE(Dump, citm_catalog / -, TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json", -1); BENCHMARK_CAPTURE(Dump, citm_catalog / -, TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json", -1);
BENCHMARK_CAPTURE(Dump, citm_catalog / 4, TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json", 4); BENCHMARK_CAPTURE(Dump, citm_catalog / 4, TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json", 4);
BENCHMARK_CAPTURE(Dump, twitter / -, TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json", -1); BENCHMARK_CAPTURE(Dump, twitter / -, TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json", -1);
BENCHMARK_CAPTURE(Dump, twitter / 4, TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json", 4); BENCHMARK_CAPTURE(Dump, twitter / 4, TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json", 4);
BENCHMARK_CAPTURE(Dump, floats / -, TEST_DATA_DIRECTORY "/regression/floats.json", -1); BENCHMARK_CAPTURE(Dump, floats / -, TEST_DATA_DIRECTORY "/regression/floats.json", -1);
BENCHMARK_CAPTURE(Dump, floats / 4, TEST_DATA_DIRECTORY "/regression/floats.json", 4); BENCHMARK_CAPTURE(Dump, floats / 4, TEST_DATA_DIRECTORY "/regression/floats.json", 4);
BENCHMARK_CAPTURE(Dump, signed_ints / -, TEST_DATA_DIRECTORY "/regression/signed_ints.json", -1); BENCHMARK_CAPTURE(Dump, signed_ints / -, TEST_DATA_DIRECTORY "/regression/signed_ints.json", -1);
BENCHMARK_CAPTURE(Dump, signed_ints / 4, TEST_DATA_DIRECTORY "/regression/signed_ints.json", 4); BENCHMARK_CAPTURE(Dump, signed_ints / 4, TEST_DATA_DIRECTORY "/regression/signed_ints.json", 4);
BENCHMARK_CAPTURE(Dump, unsigned_ints / -, TEST_DATA_DIRECTORY "/regression/unsigned_ints.json", -1); BENCHMARK_CAPTURE(Dump, unsigned_ints / -, TEST_DATA_DIRECTORY "/regression/unsigned_ints.json", -1);
BENCHMARK_CAPTURE(Dump, unsigned_ints / 4, TEST_DATA_DIRECTORY "/regression/unsigned_ints.json", 4); BENCHMARK_CAPTURE(Dump, unsigned_ints / 4, TEST_DATA_DIRECTORY "/regression/unsigned_ints.json", 4);
BENCHMARK_CAPTURE(Dump, small_signed_ints / -, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json", -1); BENCHMARK_CAPTURE(Dump, small_signed_ints / -, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json", -1);
BENCHMARK_CAPTURE(Dump, small_signed_ints / 4, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json", 4); BENCHMARK_CAPTURE(Dump, small_signed_ints / 4, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json", 4);
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// serialize CBOR // serialize CBOR
@@ -131,13 +131,13 @@ static void ToCbor(benchmark::State& state, const char* filename)
state.SetBytesProcessed(state.iterations() * json::to_cbor(j).size()); state.SetBytesProcessed(state.iterations() * json::to_cbor(j).size());
} }
BENCHMARK_CAPTURE(ToCbor, jeopardy, TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json"); BENCHMARK_CAPTURE(ToCbor, jeopardy, TEST_DATA_DIRECTORY "/jeopardy/jeopardy.json");
BENCHMARK_CAPTURE(ToCbor, canada, TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json"); BENCHMARK_CAPTURE(ToCbor, canada, TEST_DATA_DIRECTORY "/nativejson-benchmark/canada.json");
BENCHMARK_CAPTURE(ToCbor, citm_catalog, TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json"); BENCHMARK_CAPTURE(ToCbor, citm_catalog, TEST_DATA_DIRECTORY "/nativejson-benchmark/citm_catalog.json");
BENCHMARK_CAPTURE(ToCbor, twitter, TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json"); BENCHMARK_CAPTURE(ToCbor, twitter, TEST_DATA_DIRECTORY "/nativejson-benchmark/twitter.json");
BENCHMARK_CAPTURE(ToCbor, floats, TEST_DATA_DIRECTORY "/regression/floats.json"); BENCHMARK_CAPTURE(ToCbor, floats, TEST_DATA_DIRECTORY "/regression/floats.json");
BENCHMARK_CAPTURE(ToCbor, signed_ints, TEST_DATA_DIRECTORY "/regression/signed_ints.json"); BENCHMARK_CAPTURE(ToCbor, signed_ints, TEST_DATA_DIRECTORY "/regression/signed_ints.json");
BENCHMARK_CAPTURE(ToCbor, unsigned_ints, TEST_DATA_DIRECTORY "/regression/unsigned_ints.json"); BENCHMARK_CAPTURE(ToCbor, unsigned_ints, TEST_DATA_DIRECTORY "/regression/unsigned_ints.json");
BENCHMARK_CAPTURE(ToCbor, small_signed_ints, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json"); BENCHMARK_CAPTURE(ToCbor, small_signed_ints, TEST_DATA_DIRECTORY "/regression/small_signed_ints.json");
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
@@ -6,7 +6,8 @@
// SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me> // SPDX-FileCopyrightText: 2013-2023 Niels Lohmann <https://nlohmann.me>
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
#include <nlohmann/json.hpp>
#include "Foo.hpp" #include "Foo.hpp"
#include <nlohmann/json.hpp>
class Bar : public Foo {}; class Bar : public Foo
{};
@@ -9,4 +9,5 @@
#pragma once #pragma once
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
class Foo {}; class Foo
{};
+1 -1
View File
@@ -12,9 +12,9 @@ an implementation of the `LLVMFuzzerTestOneInput` function which processes a
passed byte array. passed byte array.
*/ */
#include <vector> // for vector
#include <cstdint> // for uint8_t #include <cstdint> // for uint8_t
#include <iostream> // for cin #include <iostream> // for cin
#include <vector> // for vector
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size); extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
+1 -1
View File
@@ -26,8 +26,8 @@ drivers.
*/ */
#include <iostream> #include <iostream>
#include <sstream>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <sstream>
using json = nlohmann::json; using json = nlohmann::json;
+1 -1
View File
@@ -20,8 +20,8 @@ drivers.
*/ */
#include <iostream> #include <iostream>
#include <sstream>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <sstream>
using json = nlohmann::json; using json = nlohmann::json;
+1 -1
View File
@@ -20,8 +20,8 @@ drivers.
*/ */
#include <iostream> #include <iostream>
#include <sstream>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <sstream>
using json = nlohmann::json; using json = nlohmann::json;
+1 -1
View File
@@ -21,8 +21,8 @@ drivers.
*/ */
#include <iostream> #include <iostream>
#include <sstream>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <sstream>
using json = nlohmann::json; using json = nlohmann::json;
+1 -1
View File
@@ -20,8 +20,8 @@ drivers.
*/ */
#include <iostream> #include <iostream>
#include <sstream>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <sstream>
using json = nlohmann::json; using json = nlohmann::json;
+1 -1
View File
@@ -26,8 +26,8 @@ drivers.
*/ */
#include <iostream> #include <iostream>
#include <sstream>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <sstream>
using json = nlohmann::json; using json = nlohmann::json;
+4 -5
View File
@@ -8,13 +8,12 @@
#pragma once #pragma once
#include <cstdio> // fopen, fclose, FILE #include <cstdio> // fopen, fclose, FILE
#include <memory> // unique_ptr
#include <test_data.hpp>
#include <doctest.h> #include <doctest.h>
#include <memory> // unique_ptr
#include <test_data.hpp>
namespace utils namespace utils {
{
inline bool check_testsuite_downloaded() inline bool check_testsuite_downloaded()
{ {
+5 -6
View File
@@ -8,12 +8,11 @@
#pragma once #pragma once
#include <cstdint> // uint8_t #include <cstdint> // uint8_t
#include <fstream> // ifstream, istreambuf_iterator, ios #include <fstream> // ifstream, istreambuf_iterator, ios
#include <vector> // vector #include <vector> // vector
namespace utils namespace utils {
{
inline std::vector<std::uint8_t> read_binary_file(const std::string& filename) inline std::vector<std::uint8_t> read_binary_file(const std::string& filename)
{ {
@@ -30,4 +29,4 @@ inline std::vector<std::uint8_t> read_binary_file(const std::string& filename)
return byte_vector; return byte_vector;
} }
} // namespace utils } // namespace utils
+7 -7
View File
@@ -11,10 +11,10 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
#include <climits> // SIZE_MAX #include <climits> // SIZE_MAX
#include <limits> // numeric_limits #include <limits> // numeric_limits
template <typename OfType, typename T, bool MinInRange, bool MaxInRange> template<typename OfType, typename T, bool MinInRange, bool MaxInRange>
struct trait_test_arg struct trait_test_arg
{ {
using of_type = OfType; using of_type = OfType;
@@ -92,10 +92,10 @@ TEST_CASE("32bit")
REQUIRE(SIZE_MAX == 0xffffffff); REQUIRE(SIZE_MAX == 0xffffffff);
} }
TEST_CASE_TEMPLATE_INVOKE(value_in_range_of_test, \ TEST_CASE_TEMPLATE_INVOKE(value_in_range_of_test,
trait_test_arg<std::size_t, std::int32_t, false, true>, \ trait_test_arg<std::size_t, std::int32_t, false, true>,
trait_test_arg<std::size_t, std::uint32_t, true, true>, \ trait_test_arg<std::size_t, std::uint32_t, true, true>,
trait_test_arg<std::size_t, std::int64_t, false, false>, \ trait_test_arg<std::size_t, std::int64_t, false, false>,
trait_test_arg<std::size_t, std::uint64_t, true, false>); trait_test_arg<std::size_t, std::uint64_t, true, false>);
TEST_CASE("BJData") TEST_CASE("BJData")
+23 -46
View File
@@ -21,36 +21,30 @@ TEST_CASE("algorithms")
{ {
SECTION("std::all_of") SECTION("std::all_of")
{ {
CHECK(std::all_of(j_array.begin(), j_array.end(), [](const json & value) CHECK(std::all_of(j_array.begin(), j_array.end(), [](const json& value) {
{
return !value.empty(); return !value.empty();
})); }));
CHECK(std::all_of(j_object.begin(), j_object.end(), [](const json & value) CHECK(std::all_of(j_object.begin(), j_object.end(), [](const json& value) {
{
return value.type() == json::value_t::number_integer; return value.type() == json::value_t::number_integer;
})); }));
} }
SECTION("std::any_of") SECTION("std::any_of")
{ {
CHECK(std::any_of(j_array.begin(), j_array.end(), [](const json & value) CHECK(std::any_of(j_array.begin(), j_array.end(), [](const json& value) {
{
return value.is_string() && value.get<std::string>() == "foo"; return value.is_string() && value.get<std::string>() == "foo";
})); }));
CHECK(std::any_of(j_object.begin(), j_object.end(), [](const json & value) CHECK(std::any_of(j_object.begin(), j_object.end(), [](const json& value) {
{
return value.get<int>() > 1; return value.get<int>() > 1;
})); }));
} }
SECTION("std::none_of") SECTION("std::none_of")
{ {
CHECK(std::none_of(j_array.begin(), j_array.end(), [](const json & value) CHECK(std::none_of(j_array.begin(), j_array.end(), [](const json& value) {
{
return value.empty(); return value.empty();
})); }));
CHECK(std::none_of(j_object.begin(), j_object.end(), [](const json & value) CHECK(std::none_of(j_object.begin(), j_object.end(), [](const json& value) {
{
return value.get<int>() <= 0; return value.get<int>() <= 0;
})); }));
} }
@@ -61,8 +55,7 @@ TEST_CASE("algorithms")
{ {
int sum = 0; int sum = 0;
std::for_each(j_array.cbegin(), j_array.cend(), [&sum](const json & value) std::for_each(j_array.cbegin(), j_array.cend(), [&sum](const json& value) {
{
if (value.is_number()) if (value.is_number())
{ {
sum += static_cast<int>(value); sum += static_cast<int>(value);
@@ -74,8 +67,7 @@ TEST_CASE("algorithms")
SECTION("writing") SECTION("writing")
{ {
auto add17 = [](json & value) auto add17 = [](json& value) {
{
if (value.is_array()) if (value.is_array())
{ {
value.push_back(17); value.push_back(17);
@@ -95,14 +87,12 @@ TEST_CASE("algorithms")
SECTION("std::count_if") SECTION("std::count_if")
{ {
CHECK(std::count_if(j_array.begin(), j_array.end(), [](const json & value) CHECK(std::count_if(j_array.begin(), j_array.end(), [](const json& value) {
{ return (value.is_number());
return (value.is_number()); }) == 3);
}) == 3); CHECK(std::count_if(j_array.begin(), j_array.end(), [](const json&) {
CHECK(std::count_if(j_array.begin(), j_array.end(), [](const json&) return true;
{ }) == 9);
return true;
}) == 9);
} }
SECTION("std::mismatch") SECTION("std::mismatch")
@@ -127,9 +117,7 @@ TEST_CASE("algorithms")
// compare objects only by size of its elements // compare objects only by size of its elements
json j_array2 = {13, 29, 3, {"Hello", "World"}, true, false, {{"one", 1}, {"two", 2}, {"three", 3}}, "foo", "baz"}; json j_array2 = {13, 29, 3, {"Hello", "World"}, true, false, {{"one", 1}, {"two", 2}, {"three", 3}}, "foo", "baz"};
CHECK(!std::equal(j_array.begin(), j_array.end(), j_array2.begin())); CHECK(!std::equal(j_array.begin(), j_array.end(), j_array2.begin()));
CHECK(std::equal(j_array.begin(), j_array.end(), j_array2.begin(), CHECK(std::equal(j_array.begin(), j_array.end(), j_array2.begin(), [](const json& a, const json& b) {
[](const json & a, const json & b)
{
return (a.size() == b.size()); return (a.size() == b.size());
})); }));
} }
@@ -143,9 +131,7 @@ TEST_CASE("algorithms")
SECTION("std::find_if") SECTION("std::find_if")
{ {
auto it = std::find_if(j_array.begin(), j_array.end(), auto it = std::find_if(j_array.begin(), j_array.end(), [](const json& value) {
[](const json & value)
{
return value.is_boolean(); return value.is_boolean();
}); });
CHECK(std::distance(j_array.begin(), it) == 4); CHECK(std::distance(j_array.begin(), it) == 4);
@@ -153,9 +139,7 @@ TEST_CASE("algorithms")
SECTION("std::find_if_not") SECTION("std::find_if_not")
{ {
auto it = std::find_if_not(j_array.begin(), j_array.end(), auto it = std::find_if_not(j_array.begin(), j_array.end(), [](const json& value) {
[](const json & value)
{
return value.is_number(); return value.is_number();
}); });
CHECK(std::distance(j_array.begin(), it) == 3); CHECK(std::distance(j_array.begin(), it) == 3);
@@ -164,11 +148,9 @@ TEST_CASE("algorithms")
SECTION("std::adjacent_find") SECTION("std::adjacent_find")
{ {
CHECK(std::adjacent_find(j_array.begin(), j_array.end()) == j_array.end()); CHECK(std::adjacent_find(j_array.begin(), j_array.end()) == j_array.end());
CHECK(std::adjacent_find(j_array.begin(), j_array.end(), CHECK(std::adjacent_find(j_array.begin(), j_array.end(), [](const json& v1, const json& v2) {
[](const json & v1, const json & v2) return v1.type() == v2.type();
{ }) == j_array.begin());
return v1.type() == v2.type();
}) == j_array.begin());
} }
} }
@@ -188,8 +170,7 @@ TEST_CASE("algorithms")
SECTION("std::partition") SECTION("std::partition")
{ {
auto it = std::partition(j_array.begin(), j_array.end(), [](const json & v) auto it = std::partition(j_array.begin(), j_array.end(), [](const json& v) {
{
return v.is_string(); return v.is_string();
}); });
CHECK(std::distance(j_array.begin(), it) == 2); CHECK(std::distance(j_array.begin(), it) == 2);
@@ -211,8 +192,7 @@ TEST_CASE("algorithms")
SECTION("with user-defined comparison") SECTION("with user-defined comparison")
{ {
json j = {3, {{"one", 1}, {"two", 2}}, {1, 2, 3}, nullptr}; json j = {3, {{"one", 1}, {"two", 2}}, {1, 2, 3}, nullptr};
std::sort(j.begin(), j.end(), [](const json & a, const json & b) std::sort(j.begin(), j.end(), [](const json& a, const json& b) {
{
return a.size() < b.size(); return a.size() < b.size();
}); });
CHECK(j == json({nullptr, 3, {{"one", 1}, {"two", 2}}, {1, 2, 3}})); CHECK(j == json({nullptr, 3, {{"one", 1}, {"two", 2}}, {1, 2, 3}}));
@@ -335,8 +315,7 @@ TEST_CASE("algorithms")
json dest_arr; json dest_arr;
const json source_arr = {0, 3, 6, 9, 12, 15, 20}; const json source_arr = {0, 3, 6, 9, 12, 15, 20};
std::copy_if(source_arr.begin(), source_arr.end(), std::back_inserter(dest_arr), [](const json & _value) std::copy_if(source_arr.begin(), source_arr.end(), std::back_inserter(dest_arr), [](const json& _value) {
{
return _value.get<int>() % 3 == 0; return _value.get<int>() % 3 == 0;
}); });
CHECK(dest_arr == json({0, 3, 6, 9, 12, 15})); CHECK(dest_arr == json({0, 3, 6, 9, 12, 15}));
@@ -349,7 +328,6 @@ TEST_CASE("algorithms")
std::copy_n(source_arr.begin(), numToCopy, std::back_inserter(dest_arr)); std::copy_n(source_arr.begin(), numToCopy, std::back_inserter(dest_arr));
CHECK(dest_arr == json{0, 1}); CHECK(dest_arr == json{0, 1});
} }
SECTION("copy n chars") SECTION("copy n chars")
{ {
@@ -361,5 +339,4 @@ TEST_CASE("algorithms")
CHECK(dest_arr == json{'1', '2', '3', '4'}); CHECK(dest_arr == json{'1', '2', '3', '4'});
} }
} }
} }
+44 -44
View File
@@ -12,8 +12,7 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
namespace namespace {
{
// special test case to check if memory is leaked if constructor throws // special test case to check if memory is leaked if constructor throws
template<class T> template<class T>
struct bad_allocator : std::allocator<T> struct bad_allocator : std::allocator<T>
@@ -21,21 +20,23 @@ struct bad_allocator : std::allocator<T>
using std::allocator<T>::allocator; using std::allocator<T>::allocator;
bad_allocator() = default; bad_allocator() = default;
template<class U> bad_allocator(const bad_allocator<U>& /*unused*/) { } template<class U>
bad_allocator(const bad_allocator<U>& /*unused*/)
{}
template<class... Args> template<class... Args>
void construct(T* /*unused*/, Args&& ... /*unused*/) // NOLINT(cppcoreguidelines-missing-std-forward) void construct(T* /*unused*/, Args&&... /*unused*/) // NOLINT(cppcoreguidelines-missing-std-forward)
{ {
throw std::bad_alloc(); throw std::bad_alloc();
} }
template <class U> template<class U>
struct rebind struct rebind
{ {
using other = bad_allocator<U>; using other = bad_allocator<U>;
}; };
}; };
} // namespace } // namespace
TEST_CASE("bad_alloc") TEST_CASE("bad_alloc")
{ {
@@ -43,21 +44,20 @@ TEST_CASE("bad_alloc")
{ {
// create JSON type using the throwing allocator // create JSON type using the throwing allocator
using bad_json = nlohmann::basic_json<std::map, using bad_json = nlohmann::basic_json<std::map,
std::vector, std::vector,
std::string, std::string,
bool, bool,
std::int64_t, std::int64_t,
std::uint64_t, std::uint64_t,
double, double,
bad_allocator>; bad_allocator>;
// creating an object should throw // creating an object should throw
CHECK_THROWS_AS(bad_json(bad_json::value_t::object), std::bad_alloc&); CHECK_THROWS_AS(bad_json(bad_json::value_t::object), std::bad_alloc&);
} }
} }
namespace namespace {
{
bool next_construct_fails = false; bool next_construct_fails = false;
bool next_destroy_fails = false; bool next_destroy_fails = false;
bool next_deallocate_fails = false; bool next_deallocate_fails = false;
@@ -68,7 +68,7 @@ struct my_allocator : std::allocator<T>
using std::allocator<T>::allocator; using std::allocator<T>::allocator;
template<class... Args> template<class... Args>
void construct(T* p, Args&& ... args) void construct(T* p, Args&&... args)
{ {
if (next_construct_fails) if (next_construct_fails)
{ {
@@ -98,11 +98,11 @@ struct my_allocator : std::allocator<T>
throw std::bad_alloc(); throw std::bad_alloc();
} }
static_cast<void>(p); // fix MSVC's C4100 warning static_cast<void>(p); // fix MSVC's C4100 warning
p->~T(); p->~T();
} }
template <class U> template<class U>
struct rebind struct rebind
{ {
using other = my_allocator<U>; using other = my_allocator<U>;
@@ -118,19 +118,19 @@ void my_allocator_clean_up(T* p)
alloc.destroy(p); alloc.destroy(p);
alloc.deallocate(p, 1); alloc.deallocate(p, 1);
} }
} // namespace } // namespace
TEST_CASE("controlled bad_alloc") TEST_CASE("controlled bad_alloc")
{ {
// create JSON type using the throwing allocator // create JSON type using the throwing allocator
using my_json = nlohmann::basic_json<std::map, using my_json = nlohmann::basic_json<std::map,
std::vector, std::vector,
std::string, std::string,
bool, bool,
std::int64_t, std::int64_t,
std::uint64_t, std::uint64_t,
double, double,
my_allocator>; my_allocator>;
SECTION("class json_value") SECTION("class json_value")
{ {
@@ -181,7 +181,7 @@ TEST_CASE("controlled bad_alloc")
SECTION("basic_json(const CompatibleObjectType&)") SECTION("basic_json(const CompatibleObjectType&)")
{ {
next_construct_fails = false; next_construct_fails = false;
const std::map<std::string, std::string> v {{"foo", "bar"}}; const std::map<std::string, std::string> v{{"foo", "bar"}};
CHECK_NOTHROW(my_json(v)); CHECK_NOTHROW(my_json(v));
next_construct_fails = true; next_construct_fails = true;
CHECK_THROWS_AS(my_json(v), std::bad_alloc&); CHECK_THROWS_AS(my_json(v), std::bad_alloc&);
@@ -191,7 +191,7 @@ TEST_CASE("controlled bad_alloc")
SECTION("basic_json(const CompatibleArrayType&)") SECTION("basic_json(const CompatibleArrayType&)")
{ {
next_construct_fails = false; next_construct_fails = false;
const std::vector<std::string> v {"foo", "bar", "baz"}; const std::vector<std::string> v{"foo", "bar", "baz"};
CHECK_NOTHROW(my_json(v)); CHECK_NOTHROW(my_json(v));
next_construct_fails = true; next_construct_fails = true;
CHECK_THROWS_AS(my_json(v), std::bad_alloc&); CHECK_THROWS_AS(my_json(v), std::bad_alloc&);
@@ -219,42 +219,42 @@ TEST_CASE("controlled bad_alloc")
} }
} }
namespace namespace {
{
template<class T> template<class T>
struct allocator_no_forward : std::allocator<T> struct allocator_no_forward : std::allocator<T>
{ {
allocator_no_forward() = default; allocator_no_forward() = default;
template <class U> template<class U>
allocator_no_forward(allocator_no_forward<U> /*unused*/) {} allocator_no_forward(allocator_no_forward<U> /*unused*/)
{}
template <class U> template<class U>
struct rebind struct rebind
{ {
using other = allocator_no_forward<U>; using other = allocator_no_forward<U>;
}; };
template <class... Args> template<class... Args>
void construct(T* p, const Args& ... args) noexcept(noexcept(::new (static_cast<void*>(p)) T(args...))) void construct(T* p, const Args&... args) noexcept(noexcept(::new(static_cast<void*>(p)) T(args...)))
{ {
// force copy even if move is available // force copy even if move is available
::new (static_cast<void*>(p)) T(args...); ::new (static_cast<void*>(p)) T(args...);
} }
}; };
} // namespace } // namespace
TEST_CASE("bad my_allocator::construct") TEST_CASE("bad my_allocator::construct")
{ {
SECTION("my_allocator::construct doesn't forward") SECTION("my_allocator::construct doesn't forward")
{ {
using bad_alloc_json = nlohmann::basic_json<std::map, using bad_alloc_json = nlohmann::basic_json<std::map,
std::vector, std::vector,
std::string, std::string,
bool, bool,
std::int64_t, std::int64_t,
std::uint64_t, std::uint64_t,
double, double,
allocator_no_forward>; allocator_no_forward>;
bad_alloc_json j; bad_alloc_json j;
j["test"] = bad_alloc_json::array_t(); j["test"] = bad_alloc_json::array_t();
+36 -30
View File
@@ -30,13 +30,19 @@ class alt_string
static constexpr auto npos = static_cast<std::size_t>(-1); static constexpr auto npos = static_cast<std::size_t>(-1);
alt_string(const char* str): str_impl(str) {} alt_string(const char* str)
alt_string(const char* str, std::size_t count): str_impl(str, count) {} : str_impl(str)
alt_string(size_t count, char chr): str_impl(count, chr) {} {}
alt_string(const char* str, std::size_t count)
: str_impl(str, count)
{}
alt_string(size_t count, char chr)
: str_impl(count, chr)
{}
alt_string() = default; alt_string() = default;
template <typename...TParams> template<typename... TParams>
alt_string& append(TParams&& ...params) alt_string& append(TParams&&... params)
{ {
str_impl.append(std::forward<TParams>(params)...); str_impl.append(std::forward<TParams>(params)...);
return *this; return *this;
@@ -47,7 +53,7 @@ class alt_string
str_impl.push_back(c); str_impl.push_back(c);
} }
template <typename op_type> template<typename op_type>
bool operator==(const op_type& op) const bool operator==(const op_type& op) const
{ {
return str_impl == op; return str_impl == op;
@@ -58,7 +64,7 @@ class alt_string
return str_impl == op.str_impl; return str_impl == op.str_impl;
} }
template <typename op_type> template<typename op_type>
bool operator!=(const op_type& op) const bool operator!=(const op_type& op) const
{ {
return str_impl != op; return str_impl != op;
@@ -74,17 +80,17 @@ class alt_string
return str_impl.size(); return str_impl.size();
} }
void resize (std::size_t n) void resize(std::size_t n)
{ {
str_impl.resize(n); str_impl.resize(n);
} }
void resize (std::size_t n, char c) void resize(std::size_t n, char c)
{ {
str_impl.resize(n, c); str_impl.resize(n, c);
} }
template <typename op_type> template<typename op_type>
bool operator<(const op_type& op) const noexcept bool operator<(const op_type& op) const noexcept
{ {
return str_impl < op; return str_impl < op;
@@ -158,7 +164,7 @@ class alt_string
} }
private: private:
std::string str_impl {}; std::string str_impl{};
friend bool operator<(const char* /*op1*/, const alt_string& /*op2*/) noexcept; friend bool operator<(const char* /*op1*/, const alt_string& /*op2*/) noexcept;
}; };
@@ -168,16 +174,16 @@ void int_to_string(alt_string& target, std::size_t value)
target = std::to_string(value).c_str(); target = std::to_string(value).c_str();
} }
using alt_json = nlohmann::basic_json < using alt_json = nlohmann::basic_json<
std::map, std::map,
std::vector, std::vector,
alt_string, alt_string,
bool, bool,
std::int64_t, std::int64_t,
std::uint64_t, std::uint64_t,
double, double,
std::allocator, std::allocator,
nlohmann::adl_serializer >; nlohmann::adl_serializer>;
bool operator<(const char* op1, const alt_string& op2) noexcept bool operator<(const char* op1, const alt_string& op2) noexcept
{ {
@@ -225,14 +231,14 @@ TEST_CASE("alternative string type")
{ {
alt_json doc; alt_json doc;
doc["list"] = { 1, 0, 2 }; doc["list"] = {1, 0, 2};
alt_string dump = doc.dump(); alt_string dump = doc.dump();
CHECK(dump == R"({"list":[1,0,2]})"); CHECK(dump == R"({"list":[1,0,2]})");
} }
{ {
alt_json doc; alt_json doc;
doc["object"] = { {"currency", "USD"}, {"value", 42.99} }; doc["object"] = {{"currency", "USD"}, {"value", 42.99}};
alt_string dump = doc.dump(); alt_string dump = doc.dump();
CHECK(dump == R"({"object":{"currency":"USD","value":42.99}})"); CHECK(dump == R"({"object":{"currency":"USD","value":42.99}})");
} }
@@ -259,11 +265,11 @@ TEST_CASE("alternative string type")
for (const auto& item : doc_array.items()) for (const auto& item : doc_array.items())
{ {
if (item.key() == "0" ) if (item.key() == "0")
{ {
CHECK( item.value() == "foo" ); CHECK(item.value() == "foo");
} }
else if (item.key() == "1" ) else if (item.key() == "1")
{ {
CHECK(item.value() == "bar"); CHECK(item.value() == "bar");
} }
@@ -280,14 +286,14 @@ TEST_CASE("alternative string type")
doc["Who are you?"] = "I'm Batman"; doc["Who are you?"] = "I'm Batman";
CHECK("I'm Batman" == doc["Who are you?"]); CHECK("I'm Batman" == doc["Who are you?"]);
CHECK(doc["Who are you?"] == "I'm Batman"); CHECK(doc["Who are you?"] == "I'm Batman");
CHECK_FALSE("I'm Batman" != doc["Who are you?"]); CHECK_FALSE("I'm Batman" != doc["Who are you?"]);
CHECK_FALSE(doc["Who are you?"] != "I'm Batman"); CHECK_FALSE(doc["Who are you?"] != "I'm Batman");
CHECK("I'm Bruce Wayne" != doc["Who are you?"]); CHECK("I'm Bruce Wayne" != doc["Who are you?"]);
CHECK(doc["Who are you?"] != "I'm Bruce Wayne"); CHECK(doc["Who are you?"] != "I'm Bruce Wayne");
CHECK_FALSE("I'm Bruce Wayne" == doc["Who are you?"]); CHECK_FALSE("I'm Bruce Wayne" == doc["Who are you?"]);
CHECK_FALSE(doc["Who are you?"] == "I'm Bruce Wayne"); CHECK_FALSE(doc["Who are you?"] == "I'm Bruce Wayne");
{ {
const alt_json& const_doc = doc; const alt_json& const_doc = doc;
+5 -1
View File
@@ -18,7 +18,11 @@ DOCTEST_CLANG_SUPPRESS_WARNING("-Wstrict-overflow")
static int assert_counter; static int assert_counter;
/// set failure variable to true instead of calling assert(x) /// set failure variable to true instead of calling assert(x)
#define JSON_ASSERT(x) {if (!(x)) ++assert_counter; } #define JSON_ASSERT(x) \
{ \
if (!(x)) \
++assert_counter; \
}
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
+2 -2
View File
@@ -11,8 +11,8 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
#include <fstream>
#include "make_test_data_available.hpp" #include "make_test_data_available.hpp"
#include <fstream>
TEST_CASE("Binary Formats" * doctest::skip()) TEST_CASE("Binary Formats" * doctest::skip())
{ {
@@ -142,7 +142,7 @@ TEST_CASE("Binary Formats" * doctest::skip())
const auto bjdata_1_size = json::to_bjdata(j).size(); const auto bjdata_1_size = json::to_bjdata(j).size();
const auto bjdata_2_size = json::to_bjdata(j, true).size(); const auto bjdata_2_size = json::to_bjdata(j, true).size();
const auto bjdata_3_size = json::to_bjdata(j, true, true).size(); const auto bjdata_3_size = json::to_bjdata(j, true, true).size();
const auto bson_size = json::to_bson({{"", j}}).size(); // wrap array in object for BSON const auto bson_size = json::to_bson({{"", j}}).size(); // wrap array in object for BSON
const auto cbor_size = json::to_cbor(j).size(); const auto cbor_size = json::to_cbor(j).size();
const auto msgpack_size = json::to_msgpack(j).size(); const auto msgpack_size = json::to_msgpack(j).size();
const auto ubjson_1_size = json::to_ubjson(j).size(); const auto ubjson_1_size = json::to_ubjson(j).size();
+887 -329
View File
File diff suppressed because it is too large. Load diff
+870 -399
View File
File diff suppressed because it is too large. Load diff
+30 -30
View File
@@ -18,7 +18,7 @@ TEST_CASE("capacity")
{ {
SECTION("boolean") SECTION("boolean")
{ {
json j = true; // NOLINT(misc-const-correctness) json j = true; // NOLINT(misc-const-correctness)
const json j_const = true; const json j_const = true;
SECTION("result of empty") SECTION("result of empty")
@@ -36,7 +36,7 @@ TEST_CASE("capacity")
SECTION("string") SECTION("string")
{ {
json j = "hello world"; // NOLINT(misc-const-correctness) json j = "hello world"; // NOLINT(misc-const-correctness)
const json j_const = "hello world"; const json j_const = "hello world";
SECTION("result of empty") SECTION("result of empty")
@@ -56,7 +56,7 @@ TEST_CASE("capacity")
{ {
SECTION("empty array") SECTION("empty array")
{ {
json j = json::array(); // NOLINT(misc-const-correctness) json j = json::array(); // NOLINT(misc-const-correctness)
const json j_const = json::array(); const json j_const = json::array();
SECTION("result of empty") SECTION("result of empty")
@@ -74,7 +74,7 @@ TEST_CASE("capacity")
SECTION("filled array") SECTION("filled array")
{ {
json j = {1, 2, 3}; // NOLINT(misc-const-correctness) json j = {1, 2, 3}; // NOLINT(misc-const-correctness)
const json j_const = {1, 2, 3}; const json j_const = {1, 2, 3};
SECTION("result of empty") SECTION("result of empty")
@@ -95,7 +95,7 @@ TEST_CASE("capacity")
{ {
SECTION("empty object") SECTION("empty object")
{ {
json j = json::object(); // NOLINT(misc-const-correctness) json j = json::object(); // NOLINT(misc-const-correctness)
const json j_const = json::object(); const json j_const = json::object();
SECTION("result of empty") SECTION("result of empty")
@@ -113,7 +113,7 @@ TEST_CASE("capacity")
SECTION("filled object") SECTION("filled object")
{ {
json j = {{"one", 1}, {"two", 2}, {"three", 3}}; // NOLINT(misc-const-correctness) json j = {{"one", 1}, {"two", 2}, {"three", 3}}; // NOLINT(misc-const-correctness)
const json j_const = {{"one", 1}, {"two", 2}, {"three", 3}}; const json j_const = {{"one", 1}, {"two", 2}, {"three", 3}};
SECTION("result of empty") SECTION("result of empty")
@@ -132,7 +132,7 @@ TEST_CASE("capacity")
SECTION("number (integer)") SECTION("number (integer)")
{ {
json j = -23; // NOLINT(misc-const-correctness) json j = -23; // NOLINT(misc-const-correctness)
const json j_const = -23; const json j_const = -23;
SECTION("result of empty") SECTION("result of empty")
@@ -150,7 +150,7 @@ TEST_CASE("capacity")
SECTION("number (unsigned)") SECTION("number (unsigned)")
{ {
json j = 23u; // NOLINT(misc-const-correctness) json j = 23u; // NOLINT(misc-const-correctness)
const json j_const = 23u; const json j_const = 23u;
SECTION("result of empty") SECTION("result of empty")
@@ -168,7 +168,7 @@ TEST_CASE("capacity")
SECTION("number (float)") SECTION("number (float)")
{ {
json j = 23.42; // NOLINT(misc-const-correctness) json j = 23.42; // NOLINT(misc-const-correctness)
const json j_const = 23.42; const json j_const = 23.42;
SECTION("result of empty") SECTION("result of empty")
@@ -186,7 +186,7 @@ TEST_CASE("capacity")
SECTION("null") SECTION("null")
{ {
json j = nullptr; // NOLINT(misc-const-correctness) json j = nullptr; // NOLINT(misc-const-correctness)
const json j_const = nullptr; const json j_const = nullptr;
SECTION("result of empty") SECTION("result of empty")
@@ -207,7 +207,7 @@ TEST_CASE("capacity")
{ {
SECTION("boolean") SECTION("boolean")
{ {
json j = true; // NOLINT(misc-const-correctness) json j = true; // NOLINT(misc-const-correctness)
const json j_const = true; const json j_const = true;
SECTION("result of size") SECTION("result of size")
@@ -227,7 +227,7 @@ TEST_CASE("capacity")
SECTION("string") SECTION("string")
{ {
json j = "hello world"; // NOLINT(misc-const-correctness) json j = "hello world"; // NOLINT(misc-const-correctness)
const json j_const = "hello world"; const json j_const = "hello world";
SECTION("result of size") SECTION("result of size")
@@ -249,7 +249,7 @@ TEST_CASE("capacity")
{ {
SECTION("empty array") SECTION("empty array")
{ {
json j = json::array(); // NOLINT(misc-const-correctness) json j = json::array(); // NOLINT(misc-const-correctness)
const json j_const = json::array(); const json j_const = json::array();
SECTION("result of size") SECTION("result of size")
@@ -269,7 +269,7 @@ TEST_CASE("capacity")
SECTION("filled array") SECTION("filled array")
{ {
json j = {1, 2, 3}; // NOLINT(misc-const-correctness) json j = {1, 2, 3}; // NOLINT(misc-const-correctness)
const json j_const = {1, 2, 3}; const json j_const = {1, 2, 3};
SECTION("result of size") SECTION("result of size")
@@ -292,7 +292,7 @@ TEST_CASE("capacity")
{ {
SECTION("empty object") SECTION("empty object")
{ {
json j = json::object(); // NOLINT(misc-const-correctness) json j = json::object(); // NOLINT(misc-const-correctness)
const json j_const = json::object(); const json j_const = json::object();
SECTION("result of size") SECTION("result of size")
@@ -312,7 +312,7 @@ TEST_CASE("capacity")
SECTION("filled object") SECTION("filled object")
{ {
json j = {{"one", 1}, {"two", 2}, {"three", 3}}; // NOLINT(misc-const-correctness) json j = {{"one", 1}, {"two", 2}, {"three", 3}}; // NOLINT(misc-const-correctness)
const json j_const = {{"one", 1}, {"two", 2}, {"three", 3}}; const json j_const = {{"one", 1}, {"two", 2}, {"three", 3}};
SECTION("result of size") SECTION("result of size")
@@ -333,7 +333,7 @@ TEST_CASE("capacity")
SECTION("number (integer)") SECTION("number (integer)")
{ {
json j = -23; // NOLINT(misc-const-correctness) json j = -23; // NOLINT(misc-const-correctness)
const json j_const = -23; const json j_const = -23;
SECTION("result of size") SECTION("result of size")
@@ -353,7 +353,7 @@ TEST_CASE("capacity")
SECTION("number (unsigned)") SECTION("number (unsigned)")
{ {
json j = 23u; // NOLINT(misc-const-correctness) json j = 23u; // NOLINT(misc-const-correctness)
const json j_const = 23u; const json j_const = 23u;
SECTION("result of size") SECTION("result of size")
@@ -373,7 +373,7 @@ TEST_CASE("capacity")
SECTION("number (float)") SECTION("number (float)")
{ {
json j = 23.42; // NOLINT(misc-const-correctness) json j = 23.42; // NOLINT(misc-const-correctness)
const json j_const = 23.42; const json j_const = 23.42;
SECTION("result of size") SECTION("result of size")
@@ -393,7 +393,7 @@ TEST_CASE("capacity")
SECTION("null") SECTION("null")
{ {
json j = nullptr; // NOLINT(misc-const-correctness) json j = nullptr; // NOLINT(misc-const-correctness)
const json j_const = nullptr; const json j_const = nullptr;
SECTION("result of size") SECTION("result of size")
@@ -416,7 +416,7 @@ TEST_CASE("capacity")
{ {
SECTION("boolean") SECTION("boolean")
{ {
json j = true; // NOLINT(misc-const-correctness) json j = true; // NOLINT(misc-const-correctness)
const json j_const = true; const json j_const = true;
SECTION("result of max_size") SECTION("result of max_size")
@@ -428,7 +428,7 @@ TEST_CASE("capacity")
SECTION("string") SECTION("string")
{ {
json j = "hello world"; // NOLINT(misc-const-correctness) json j = "hello world"; // NOLINT(misc-const-correctness)
const json j_const = "hello world"; const json j_const = "hello world";
SECTION("result of max_size") SECTION("result of max_size")
@@ -442,7 +442,7 @@ TEST_CASE("capacity")
{ {
SECTION("empty array") SECTION("empty array")
{ {
json j = json::array(); // NOLINT(misc-const-correctness) json j = json::array(); // NOLINT(misc-const-correctness)
const json j_const = json::array(); const json j_const = json::array();
SECTION("result of max_size") SECTION("result of max_size")
@@ -454,7 +454,7 @@ TEST_CASE("capacity")
SECTION("filled array") SECTION("filled array")
{ {
json j = {1, 2, 3}; // NOLINT(misc-const-correctness) json j = {1, 2, 3}; // NOLINT(misc-const-correctness)
const json j_const = {1, 2, 3}; const json j_const = {1, 2, 3};
SECTION("result of max_size") SECTION("result of max_size")
@@ -469,7 +469,7 @@ TEST_CASE("capacity")
{ {
SECTION("empty object") SECTION("empty object")
{ {
json j = json::object(); // NOLINT(misc-const-correctness) json j = json::object(); // NOLINT(misc-const-correctness)
const json j_const = json::object(); const json j_const = json::object();
SECTION("result of max_size") SECTION("result of max_size")
@@ -481,7 +481,7 @@ TEST_CASE("capacity")
SECTION("filled object") SECTION("filled object")
{ {
json j = {{"one", 1}, {"two", 2}, {"three", 3}}; // NOLINT(misc-const-correctness) json j = {{"one", 1}, {"two", 2}, {"three", 3}}; // NOLINT(misc-const-correctness)
const json j_const = {{"one", 1}, {"two", 2}, {"three", 3}}; const json j_const = {{"one", 1}, {"two", 2}, {"three", 3}};
SECTION("result of max_size") SECTION("result of max_size")
@@ -494,7 +494,7 @@ TEST_CASE("capacity")
SECTION("number (integer)") SECTION("number (integer)")
{ {
json j = -23; // NOLINT(misc-const-correctness) json j = -23; // NOLINT(misc-const-correctness)
const json j_const = -23; const json j_const = -23;
SECTION("result of max_size") SECTION("result of max_size")
@@ -506,7 +506,7 @@ TEST_CASE("capacity")
SECTION("number (unsigned)") SECTION("number (unsigned)")
{ {
json j = 23u; // NOLINT(misc-const-correctness) json j = 23u; // NOLINT(misc-const-correctness)
const json j_const = 23u; const json j_const = 23u;
SECTION("result of max_size") SECTION("result of max_size")
@@ -518,7 +518,7 @@ TEST_CASE("capacity")
SECTION("number (float)") SECTION("number (float)")
{ {
json j = 23.42; // NOLINT(misc-const-correctness) json j = 23.42; // NOLINT(misc-const-correctness)
const json j_const = 23.42; const json j_const = 23.42;
SECTION("result of max_size") SECTION("result of max_size")
@@ -530,7 +530,7 @@ TEST_CASE("capacity")
SECTION("null") SECTION("null")
{ {
json j = nullptr; // NOLINT(misc-const-correctness) json j = nullptr; // NOLINT(misc-const-correctness)
const json j_const = nullptr; const json j_const = nullptr;
SECTION("result of max_size") SECTION("result of max_size")
+562 -427
View File
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -49,7 +49,7 @@ TEST_CASE("const_iterator class")
{ {
SECTION("create from uninitialized iterator") SECTION("create from uninitialized iterator")
{ {
const json::iterator it {}; const json::iterator it{};
json::const_iterator const cit(it); json::const_iterator const cit(it);
} }
+6 -7
View File
@@ -387,18 +387,18 @@ TEST_CASE("iterator class")
SECTION("primitive_iterator_t") SECTION("primitive_iterator_t")
{ {
using Iter = nlohmann::detail::primitive_iterator_t; using Iter = nlohmann::detail::primitive_iterator_t;
CHECK(std::is_same < decltype(std::declval<Iter&>()++), Iter >::value); CHECK(std::is_same<decltype(std::declval<Iter&>()++), Iter>::value);
} }
SECTION("iter_impl") SECTION("iter_impl")
{ {
using Iter = nlohmann::detail::iter_impl<json>; using Iter = nlohmann::detail::iter_impl<json>;
CHECK(std::is_same < decltype(std::declval<Iter&>()++), Iter >::value); CHECK(std::is_same<decltype(std::declval<Iter&>()++), Iter>::value);
} }
SECTION("json_reverse_iterator") SECTION("json_reverse_iterator")
{ {
using Base = nlohmann::detail::iter_impl<json>; using Base = nlohmann::detail::iter_impl<json>;
using Iter = nlohmann::detail::json_reverse_iterator<Base>; using Iter = nlohmann::detail::json_reverse_iterator<Base>;
CHECK(std::is_same < decltype(std::declval<Iter&>()++), Iter >::value); CHECK(std::is_same<decltype(std::declval<Iter&>()++), Iter>::value);
} }
} }
SECTION("post-decrement") SECTION("post-decrement")
@@ -406,18 +406,18 @@ TEST_CASE("iterator class")
SECTION("primitive_iterator_t") SECTION("primitive_iterator_t")
{ {
using Iter = nlohmann::detail::primitive_iterator_t; using Iter = nlohmann::detail::primitive_iterator_t;
CHECK(std::is_same < decltype(std::declval<Iter&>()--), Iter >::value); CHECK(std::is_same<decltype(std::declval<Iter&>()--), Iter>::value);
} }
SECTION("iter_impl") SECTION("iter_impl")
{ {
using Iter = nlohmann::detail::iter_impl<json>; using Iter = nlohmann::detail::iter_impl<json>;
CHECK(std::is_same < decltype(std::declval<Iter&>()--), Iter >::value ); CHECK(std::is_same<decltype(std::declval<Iter&>()--), Iter>::value);
} }
SECTION("json_reverse_iterator") SECTION("json_reverse_iterator")
{ {
using Base = nlohmann::detail::iter_impl<json>; using Base = nlohmann::detail::iter_impl<json>;
using Iter = nlohmann::detail::json_reverse_iterator<Base>; using Iter = nlohmann::detail::json_reverse_iterator<Base>;
CHECK(std::is_same < decltype(std::declval<Iter&>()--), Iter >::value ); CHECK(std::is_same<decltype(std::declval<Iter&>()--), Iter>::value);
} }
} }
} }
@@ -462,7 +462,6 @@ TEST_CASE("iterator class")
using Iter = nlohmann::detail::json_reverse_iterator<Base>; using Iter = nlohmann::detail::json_reverse_iterator<Base>;
CHECK_FALSE(is_detected<can_post_decrement_temporary, Iter&>::value); CHECK_FALSE(is_detected<can_post_decrement_temporary, Iter&>::value);
} }
} }
} }
} }
+4 -5
View File
@@ -12,22 +12,21 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
namespace namespace {
{
// shortcut to scan a string literal // shortcut to scan a string literal
json::lexer::token_type scan_string(const char* s, bool ignore_comments = false); json::lexer::token_type scan_string(const char* s, bool ignore_comments = false);
json::lexer::token_type scan_string(const char* s, const bool ignore_comments) json::lexer::token_type scan_string(const char* s, const bool ignore_comments)
{ {
auto ia = nlohmann::detail::input_adapter(s); auto ia = nlohmann::detail::input_adapter(s);
return nlohmann::detail::lexer<json, decltype(ia)>(std::move(ia), ignore_comments).scan(); // NOLINT(hicpp-move-const-arg,performance-move-const-arg) return nlohmann::detail::lexer<json, decltype(ia)>(std::move(ia), ignore_comments).scan(); // NOLINT(hicpp-move-const-arg,performance-move-const-arg)
} }
} // namespace } // namespace
std::string get_error_message(const char* s, bool ignore_comments = false); std::string get_error_message(const char* s, bool ignore_comments = false);
std::string get_error_message(const char* s, const bool ignore_comments) std::string get_error_message(const char* s, const bool ignore_comments)
{ {
auto ia = nlohmann::detail::input_adapter(s); auto ia = nlohmann::detail::input_adapter(s);
auto lexer = nlohmann::detail::lexer<json, decltype(ia)>(std::move(ia), ignore_comments); // NOLINT(hicpp-move-const-arg,performance-move-const-arg) auto lexer = nlohmann::detail::lexer<json, decltype(ia)>(std::move(ia), ignore_comments); // NOLINT(hicpp-move-const-arg,performance-move-const-arg)
lexer.scan(); lexer.scan();
return lexer.get_error_message(); return lexer.get_error_message();
} }
+181 -127
View File
@@ -12,13 +12,12 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
#ifdef JSON_TEST_NO_GLOBAL_UDLS #ifdef JSON_TEST_NO_GLOBAL_UDLS
using namespace nlohmann::literals; // NOLINT(google-build-using-namespace) using namespace nlohmann::literals; // NOLINT(google-build-using-namespace)
#endif #endif
#include <valarray> #include <valarray>
namespace namespace {
{
class SaxEventLogger class SaxEventLogger
{ {
public: public:
@@ -124,14 +123,15 @@ class SaxEventLogger
return false; return false;
} }
std::vector<std::string> events {}; std::vector<std::string> events{};
bool errored = false; bool errored = false;
}; };
class SaxCountdown : public nlohmann::json::json_sax_t class SaxCountdown : public nlohmann::json::json_sax_t
{ {
public: public:
explicit SaxCountdown(const int count) : events_left(count) explicit SaxCountdown(const int count)
: events_left(count)
{} {}
bool null() override bool null() override
@@ -249,8 +249,7 @@ bool accept_helper(const std::string& s)
CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept(false) == !el.errored); CHECK(json::parser(nlohmann::detail::input_adapter(s)).accept(false) == !el.errored);
// 5. parse with simple callback // 5. parse with simple callback
json::parser_callback_t const cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept json::parser_callback_t const cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept {
{
return true; return true;
}; };
json const j_cb = json::parse(s, cb, false); json const j_cb = json::parse(s, cb, false);
@@ -302,7 +301,7 @@ void comments_helper(const std::string& s)
} }
} }
} // namespace } // namespace
TEST_CASE("parser class") TEST_CASE("parser class")
{ {
@@ -369,7 +368,7 @@ TEST_CASE("parser class")
CHECK_THROWS_AS(parser_helper("\uFF01"), json::parse_error&); CHECK_THROWS_AS(parser_helper("\uFF01"), json::parse_error&);
CHECK_THROWS_AS(parser_helper("[-4:1,]"), json::parse_error&); CHECK_THROWS_AS(parser_helper("[-4:1,]"), json::parse_error&);
// unescaped control characters // unescaped control characters
CHECK_THROWS_WITH_AS(parser_helper("\"\x00\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: missing closing quote; last read: '\"'", json::parse_error&); // NOLINT(bugprone-string-literal-with-embedded-nul) CHECK_THROWS_WITH_AS(parser_helper("\"\x00\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: missing closing quote; last read: '\"'", json::parse_error&); // NOLINT(bugprone-string-literal-with-embedded-nul)
CHECK_THROWS_WITH_AS(parser_helper("\"\x01\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0001 (SOH) must be escaped to \\u0001; last read: '\"<U+0001>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x01\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0001 (SOH) must be escaped to \\u0001; last read: '\"<U+0001>'", json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("\"\x02\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0002 (STX) must be escaped to \\u0002; last read: '\"<U+0002>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x02\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0002 (STX) must be escaped to \\u0002; last read: '\"<U+0002>'", json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("\"\x03\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0003 (ETX) must be escaped to \\u0003; last read: '\"<U+0003>'", json::parse_error&); CHECK_THROWS_WITH_AS(parser_helper("\"\x03\""), "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: control character U+0003 (ETX) must be escaped to \\u0003; last read: '\"<U+0003>'", json::parse_error&);
@@ -592,39 +591,56 @@ TEST_CASE("parser class")
CHECK_THROWS_AS(parser_helper("+0"), json::parse_error&); CHECK_THROWS_AS(parser_helper("+0"), json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("01"), CHECK_THROWS_WITH_AS(parser_helper("01"),
"[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - unexpected number literal; expected end of input", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - unexpected number literal; expected end of input",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("-01"), CHECK_THROWS_WITH_AS(parser_helper("-01"),
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - unexpected number literal; expected end of input", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - unexpected number literal; expected end of input",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("--1"), CHECK_THROWS_WITH_AS(parser_helper("--1"),
"[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '--'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '--'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("1."), CHECK_THROWS_WITH_AS(parser_helper("1."),
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '1.'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '1.'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("1E"), CHECK_THROWS_WITH_AS(parser_helper("1E"),
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("1E-"), CHECK_THROWS_WITH_AS(parser_helper("1E-"),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '1E-'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '1E-'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("1.E1"), CHECK_THROWS_WITH_AS(parser_helper("1.E1"),
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '1.E'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '1.E'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("-1E"), CHECK_THROWS_WITH_AS(parser_helper("-1E"),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '-1E'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '-1E'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("-0E#"), CHECK_THROWS_WITH_AS(parser_helper("-0E#"),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '-0E#'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '-0E#'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("-0E-#"), CHECK_THROWS_WITH_AS(parser_helper("-0E-#"),
"[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '-0E-#'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '-0E-#'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("-0#"), CHECK_THROWS_WITH_AS(parser_helper("-0#"),
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: '-0#'; expected end of input", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: '-0#'; expected end of input",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("-0.0:"), CHECK_THROWS_WITH_AS(parser_helper("-0.0:"),
"[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - unexpected ':'; expected end of input", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - unexpected ':'; expected end of input",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("-0.0Z"), CHECK_THROWS_WITH_AS(parser_helper("-0.0Z"),
"[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: '-0.0Z'; expected end of input", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: '-0.0Z'; expected end of input",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("-0E123:"), CHECK_THROWS_WITH_AS(parser_helper("-0E123:"),
"[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - unexpected ':'; expected end of input", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - unexpected ':'; expected end of input",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("-0e0-:"), CHECK_THROWS_WITH_AS(parser_helper("-0e0-:"),
"[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-:'; expected end of input", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-:'; expected end of input",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("-0e-:"), CHECK_THROWS_WITH_AS(parser_helper("-0e-:"),
"[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '-0e-:'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid number; expected digit after exponent sign; last read: '-0e-:'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("-0f"), CHECK_THROWS_WITH_AS(parser_helper("-0f"),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: '-0f'; expected end of input", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: '-0f'; expected end of input",
json::parse_error&);
} }
} }
} }
@@ -692,7 +708,7 @@ TEST_CASE("parser class")
CHECK(accept_helper("\uFF01") == false); CHECK(accept_helper("\uFF01") == false);
CHECK(accept_helper("[-4:1,]") == false); CHECK(accept_helper("[-4:1,]") == false);
// unescaped control characters // unescaped control characters
CHECK(accept_helper("\"\x00\"") == false); // NOLINT(bugprone-string-literal-with-embedded-nul) CHECK(accept_helper("\"\x00\"") == false); // NOLINT(bugprone-string-literal-with-embedded-nul)
CHECK(accept_helper("\"\x01\"") == false); CHECK(accept_helper("\"\x01\"") == false);
CHECK(accept_helper("\"\x02\"") == false); CHECK(accept_helper("\"\x02\"") == false);
CHECK(accept_helper("\"\x03\"") == false); CHECK(accept_helper("\"\x03\"") == false);
@@ -895,119 +911,170 @@ TEST_CASE("parser class")
{ {
// unexpected end of number // unexpected end of number
CHECK_THROWS_WITH_AS(parser_helper("0."), CHECK_THROWS_WITH_AS(parser_helper("0."),
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '0.'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '0.'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("-"), CHECK_THROWS_WITH_AS(parser_helper("-"),
"[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("--"), CHECK_THROWS_WITH_AS(parser_helper("--"),
"[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '--'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '--'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("-0."), CHECK_THROWS_WITH_AS(parser_helper("-0."),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected digit after '.'; last read: '-0.'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid number; expected digit after '.'; last read: '-0.'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("-."), CHECK_THROWS_WITH_AS(parser_helper("-."),
"[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-.'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-.'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("-:"), CHECK_THROWS_WITH_AS(parser_helper("-:"),
"[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-:'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid number; expected digit after '-'; last read: '-:'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("0.:"), CHECK_THROWS_WITH_AS(parser_helper("0.:"),
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '0.:'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected digit after '.'; last read: '0.:'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("e."), CHECK_THROWS_WITH_AS(parser_helper("e."),
"[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'e'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'e'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("1e."), CHECK_THROWS_WITH_AS(parser_helper("1e."),
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e.'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e.'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("1e/"), CHECK_THROWS_WITH_AS(parser_helper("1e/"),
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e/'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e/'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("1e:"), CHECK_THROWS_WITH_AS(parser_helper("1e:"),
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e:'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1e:'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("1E."), CHECK_THROWS_WITH_AS(parser_helper("1E."),
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E.'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E.'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("1E/"), CHECK_THROWS_WITH_AS(parser_helper("1E/"),
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E/'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E/'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("1E:"), CHECK_THROWS_WITH_AS(parser_helper("1E:"),
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E:'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid number; expected '+', '-', or digit after exponent; last read: '1E:'",
json::parse_error&);
// unexpected end of null // unexpected end of null
CHECK_THROWS_WITH_AS(parser_helper("n"), CHECK_THROWS_WITH_AS(parser_helper("n"),
"[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 'n'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 'n'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("nu"), CHECK_THROWS_WITH_AS(parser_helper("nu"),
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'nu'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'nu'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("nul"), CHECK_THROWS_WITH_AS(parser_helper("nul"),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nul'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nul'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("nulk"), CHECK_THROWS_WITH_AS(parser_helper("nulk"),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nulk'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nulk'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("nulm"), CHECK_THROWS_WITH_AS(parser_helper("nulm"),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nulm'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'nulm'",
json::parse_error&);
// unexpected end of true // unexpected end of true
CHECK_THROWS_WITH_AS(parser_helper("t"), CHECK_THROWS_WITH_AS(parser_helper("t"),
"[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 't'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 't'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("tr"), CHECK_THROWS_WITH_AS(parser_helper("tr"),
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'tr'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'tr'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("tru"), CHECK_THROWS_WITH_AS(parser_helper("tru"),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'tru'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'tru'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("trud"), CHECK_THROWS_WITH_AS(parser_helper("trud"),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'trud'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'trud'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("truf"), CHECK_THROWS_WITH_AS(parser_helper("truf"),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'truf'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'truf'",
json::parse_error&);
// unexpected end of false // unexpected end of false
CHECK_THROWS_WITH_AS(parser_helper("f"), CHECK_THROWS_WITH_AS(parser_helper("f"),
"[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 'f'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid literal; last read: 'f'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("fa"), CHECK_THROWS_WITH_AS(parser_helper("fa"),
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'fa'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing value - invalid literal; last read: 'fa'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("fal"), CHECK_THROWS_WITH_AS(parser_helper("fal"),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'fal'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid literal; last read: 'fal'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("fals"), CHECK_THROWS_WITH_AS(parser_helper("fals"),
"[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'fals'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'fals'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("falsd"), CHECK_THROWS_WITH_AS(parser_helper("falsd"),
"[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'falsd'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'falsd'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("falsf"), CHECK_THROWS_WITH_AS(parser_helper("falsf"),
"[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'falsf'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid literal; last read: 'falsf'",
json::parse_error&);
// missing/unexpected end of array // missing/unexpected end of array
CHECK_THROWS_WITH_AS(parser_helper("["), CHECK_THROWS_WITH_AS(parser_helper("["),
"[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("[1"), CHECK_THROWS_WITH_AS(parser_helper("[1"),
"[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing array - unexpected end of input; expected ']'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 3: syntax error while parsing array - unexpected end of input; expected ']'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("[1,"), CHECK_THROWS_WITH_AS(parser_helper("[1,"),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("[1,]"), CHECK_THROWS_WITH_AS(parser_helper("[1,]"),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("]"), CHECK_THROWS_WITH_AS(parser_helper("]"),
"[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected ']'; expected '[', '{', or a literal",
json::parse_error&);
// missing/unexpected end of object // missing/unexpected end of object
CHECK_THROWS_WITH_AS(parser_helper("{"), CHECK_THROWS_WITH_AS(parser_helper("{"),
"[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing object key - unexpected end of input; expected string literal", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing object key - unexpected end of input; expected string literal",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("{\"foo\""), CHECK_THROWS_WITH_AS(parser_helper("{\"foo\""),
"[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing object separator - unexpected end of input; expected ':'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing object separator - unexpected end of input; expected ':'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":"), CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":"),
"[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected end of input; expected '[', '{', or a literal",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":}"), CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":}"),
"[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected '}'; expected '[', '{', or a literal", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - unexpected '}'; expected '[', '{', or a literal",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":1,}"), CHECK_THROWS_WITH_AS(parser_helper("{\"foo\":1,}"),
"[json.exception.parse_error.101] parse error at line 1, column 10: syntax error while parsing object key - unexpected '}'; expected string literal", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 10: syntax error while parsing object key - unexpected '}'; expected string literal",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("}"), CHECK_THROWS_WITH_AS(parser_helper("}"),
"[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected '}'; expected '[', '{', or a literal", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - unexpected '}'; expected '[', '{', or a literal",
json::parse_error&);
// missing/unexpected end of string // missing/unexpected end of string
CHECK_THROWS_WITH_AS(parser_helper("\""), CHECK_THROWS_WITH_AS(parser_helper("\""),
"[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: missing closing quote; last read: '\"'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 2: syntax error while parsing value - invalid string: missing closing quote; last read: '\"'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("\"\\\""), CHECK_THROWS_WITH_AS(parser_helper("\"\\\""),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: missing closing quote; last read: '\"\\\"'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: missing closing quote; last read: '\"\\\"'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("\"\\u\""), CHECK_THROWS_WITH_AS(parser_helper("\"\\u\""),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u\"'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u\"'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("\"\\u0\""), CHECK_THROWS_WITH_AS(parser_helper("\"\\u0\""),
"[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u0\"'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u0\"'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("\"\\u01\""), CHECK_THROWS_WITH_AS(parser_helper("\"\\u01\""),
"[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u01\"'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u01\"'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("\"\\u012\""), CHECK_THROWS_WITH_AS(parser_helper("\"\\u012\""),
"[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u012\"'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u012\"'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("\"\\u"), CHECK_THROWS_WITH_AS(parser_helper("\"\\u"),
"[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 4: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("\"\\u0"), CHECK_THROWS_WITH_AS(parser_helper("\"\\u0"),
"[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u0'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 5: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u0'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("\"\\u01"), CHECK_THROWS_WITH_AS(parser_helper("\"\\u01"),
"[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u01'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 6: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u01'",
json::parse_error&);
CHECK_THROWS_WITH_AS(parser_helper("\"\\u012"), CHECK_THROWS_WITH_AS(parser_helper("\"\\u012"),
"[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u012'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 7: syntax error while parsing value - invalid string: '\\u' must be followed by 4 hex digits; last read: '\"\\u012'",
json::parse_error&);
// invalid escapes // invalid escapes
for (int c = 1; c < 128; ++c) for (int c = 1; c < 128; ++c)
@@ -1054,8 +1121,7 @@ TEST_CASE("parser class")
// invalid \uxxxx escapes // invalid \uxxxx escapes
{ {
// check whether character is a valid hex character // check whether character is a valid hex character
const auto valid = [](int c) const auto valid = [](int c) {
{
switch (c) switch (c)
{ {
case ('0'): case ('0'):
@@ -1159,11 +1225,14 @@ TEST_CASE("parser class")
CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\""), "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\"'", json::parse_error&); CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\""), "[json.exception.parse_error.101] parse error at line 1, column 8: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\"'", json::parse_error&);
// invalid surrogate pair // invalid surrogate pair
CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\uD80C\""), CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\uD80C\""),
"[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uD80C'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uD80C'",
json::parse_error&);
CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\u0000\""), CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\u0000\""),
"[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\u0000'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\u0000'",
json::parse_error&);
CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\uFFFF\""), CHECK_THROWS_WITH_AS(_ = json::parse("\"\\uD80C\\uFFFF\""),
"[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uFFFF'", json::parse_error&); "[json.exception.parse_error.101] parse error at line 1, column 13: syntax error while parsing value - invalid string: surrogate U+D800..U+DBFF must be followed by U+DC00..U+DFFF; last read: '\"\\uD80C\\uFFFF'",
json::parse_error&);
} }
SECTION("parse errors (accept)") SECTION("parse errors (accept)")
@@ -1269,8 +1338,7 @@ TEST_CASE("parser class")
// invalid \uxxxx escapes // invalid \uxxxx escapes
{ {
// check whether character is a valid hex character // check whether character is a valid hex character
const auto valid = [](int c) const auto valid = [](int c) {
{
switch (c) switch (c)
{ {
case ('0'): case ('0'):
@@ -1361,8 +1429,7 @@ TEST_CASE("parser class")
// test case to make sure the callback is properly evaluated after reading a key // test case to make sure the callback is properly evaluated after reading a key
{ {
json::parser_callback_t const cb = [](int /*unused*/, json::parse_event_t event, json& /*unused*/) noexcept json::parser_callback_t const cb = [](int /*unused*/, json::parse_event_t event, json& /*unused*/) noexcept {
{
return event != json::parse_event_t::key; return event != json::parse_event_t::key;
}; };
@@ -1400,77 +1467,69 @@ TEST_CASE("parser class")
SECTION("filter nothing") SECTION("filter nothing")
{ {
json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept {
{
return true; return true;
}); });
CHECK (j_object == json({{"foo", 2}, {"bar", {{"baz", 1}}}})); CHECK(j_object == json({{"foo", 2}, {"bar", {{"baz", 1}}}}));
json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept {
{
return true; return true;
}); });
CHECK (j_array == json({1, 2, {3, 4, 5}, 4, 5})); CHECK(j_array == json({1, 2, {3, 4, 5}, 4, 5}));
} }
SECTION("filter everything") SECTION("filter everything")
{ {
json const j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept json const j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept {
{
return false; return false;
}); });
// the top-level object will be discarded, leaving a null // the top-level object will be discarded, leaving a null
CHECK (j_object.is_null()); CHECK(j_object.is_null());
json const j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept json const j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t /*unused*/, const json& /*unused*/) noexcept {
{
return false; return false;
}); });
// the top-level array will be discarded, leaving a null // the top-level array will be discarded, leaving a null
CHECK (j_array.is_null()); CHECK(j_array.is_null());
} }
SECTION("filter specific element") SECTION("filter specific element")
{ {
json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t event, 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 // filter all number(2) elements
return event != json::parse_event_t::value || j != json(2); return event != json::parse_event_t::value || j != json(2);
}); });
CHECK (j_object == json({{"bar", {{"baz", 1}}}})); CHECK(j_object == json({{"bar", {{"baz", 1}}}}));
json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t event, const json & j) noexcept json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t event, const json& j) noexcept {
{
return event != json::parse_event_t::value || j != json(2); return event != json::parse_event_t::value || j != json(2);
}); });
CHECK (j_array == json({1, {3, 4, 5}, 4, 5})); CHECK(j_array == json({1, {3, 4, 5}, 4, 5}));
} }
SECTION("filter object in array") SECTION("filter object in array")
{ {
json j_filtered1 = json::parse(structured_array, [](int /*unused*/, json::parse_event_t e, const json & parsed) json j_filtered1 = json::parse(structured_array, [](int /*unused*/, json::parse_event_t e, const json& parsed) {
{
return !(e == json::parse_event_t::object_end && parsed.contains("foo")); return !(e == json::parse_event_t::object_end && parsed.contains("foo"));
}); });
// the specified object will be discarded, and removed. // the specified object will be discarded, and removed.
CHECK (j_filtered1.size() == 2); CHECK(j_filtered1.size() == 2);
CHECK (j_filtered1 == json({1, {{"qux", "baz"}}})); CHECK(j_filtered1 == json({1, {{"qux", "baz"}}}));
json j_filtered2 = json::parse(structured_array, [](int /*unused*/, json::parse_event_t e, const json& /*parsed*/) noexcept json j_filtered2 = json::parse(structured_array, [](int /*unused*/, json::parse_event_t e, const json& /*parsed*/) noexcept {
{
return e != json::parse_event_t::object_end; return e != json::parse_event_t::object_end;
}); });
// removed all objects in array. // removed all objects in array.
CHECK (j_filtered2.size() == 1); CHECK(j_filtered2.size() == 1);
CHECK (j_filtered2 == json({1})); CHECK(j_filtered2 == json({1}));
} }
SECTION("filter specific events") SECTION("filter specific events")
@@ -1478,8 +1537,7 @@ TEST_CASE("parser class")
SECTION("first closing event") SECTION("first closing event")
{ {
{ {
json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept {
{
static bool first = true; static bool first = true;
if (e == json::parse_event_t::object_end && first) if (e == json::parse_event_t::object_end && first)
{ {
@@ -1491,12 +1549,11 @@ TEST_CASE("parser class")
}); });
// the first completed object will be discarded // the first completed object will be discarded
CHECK (j_object == json({{"foo", 2}})); CHECK(j_object == json({{"foo", 2}}));
} }
{ {
json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept json j_array = json::parse(s_array, [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept {
{
static bool first = true; static bool first = true;
if (e == json::parse_event_t::array_end && first) if (e == json::parse_event_t::array_end && first)
{ {
@@ -1508,7 +1565,7 @@ TEST_CASE("parser class")
}); });
// the first completed array will be discarded // the first completed array will be discarded
CHECK (j_array == json({1, 2, 4, 5})); CHECK(j_array == json({1, 2, 4, 5}));
} }
} }
} }
@@ -1519,14 +1576,12 @@ TEST_CASE("parser class")
// object and array is discarded only after the closing character // object and array is discarded only after the closing character
// has been read // has been read
json j_empty_object = json::parse("{}", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept json j_empty_object = json::parse("{}", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept {
{
return e != json::parse_event_t::object_end; return e != json::parse_event_t::object_end;
}); });
CHECK(j_empty_object == json()); CHECK(j_empty_object == json());
json j_empty_array = json::parse("[]", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept json j_empty_array = json::parse("[]", [](int /*unused*/, json::parse_event_t e, const json& /*unused*/) noexcept {
{
return e != json::parse_event_t::array_end; return e != json::parse_event_t::array_end;
}); });
CHECK(j_empty_array == json()); CHECK(j_empty_array == json());
@@ -1545,7 +1600,7 @@ TEST_CASE("parser class")
SECTION("from std::array") SECTION("from std::array")
{ {
std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e'} }; std::array<uint8_t, 5> v{{'t', 'r', 'u', 'e'}};
json j; json j;
json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j);
CHECK(j == json(true)); CHECK(j == json(true));
@@ -1553,7 +1608,7 @@ TEST_CASE("parser class")
SECTION("from array") SECTION("from array")
{ {
uint8_t v[] = {'t', 'r', 'u', 'e'}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) uint8_t v[] = {'t', 'r', 'u', 'e'}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
json j; json j;
json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j); json::parser(nlohmann::detail::input_adapter(std::begin(v), std::end(v))).parse(true, j);
CHECK(j == json(true)); CHECK(j == json(true));
@@ -1593,8 +1648,7 @@ TEST_CASE("parser class")
{ {
SECTION("parser with callback") SECTION("parser with callback")
{ {
json::parser_callback_t const cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept json::parser_callback_t const cb = [](int /*unused*/, json::parse_event_t /*unused*/, json& /*unused*/) noexcept {
{
return true; return true;
}; };
+199 -192
View File
@@ -21,9 +21,9 @@ using nlohmann::json;
#if JSON_HAS_THREE_WAY_COMPARISON #if JSON_HAS_THREE_WAY_COMPARISON
// this can be replaced with the doctest stl extension header in version 2.5 // this can be replaced with the doctest stl extension header in version 2.5
namespace doctest namespace doctest {
{ template<>
template<> struct StringMaker<std::partial_ordering> struct StringMaker<std::partial_ordering>
{ {
static String convert(const std::partial_ordering& order) static String convert(const std::partial_ordering& order)
{ {
@@ -46,20 +46,19 @@ template<> struct StringMaker<std::partial_ordering>
return "{?}"; return "{?}";
} }
}; };
} // namespace doctest } // namespace doctest
#endif #endif
namespace namespace {
{
// helper function to check std::less<json::value_t> // helper function to check std::less<json::value_t>
// see https://en.cppreference.com/w/cpp/utility/functional/less // see https://en.cppreference.com/w/cpp/utility/functional/less
template <typename A, typename B, typename U = std::less<json::value_t>> template<typename A, typename B, typename U = std::less<json::value_t>>
bool f(A a, B b, U u = U()) bool f(A a, B b, U u = U())
{ {
return u(a, b); return u(a, b);
} }
} // namespace } // namespace
TEST_CASE("lexicographical comparison operators") TEST_CASE("lexicographical comparison operators")
{ {
@@ -87,33 +86,32 @@ TEST_CASE("lexicographical comparison operators")
SECTION("types") SECTION("types")
{ {
std::vector<json::value_t> j_types = std::vector<json::value_t> j_types =
{ {
json::value_t::null, json::value_t::null,
json::value_t::boolean, json::value_t::boolean,
json::value_t::number_integer, json::value_t::number_integer,
json::value_t::number_unsigned, json::value_t::number_unsigned,
json::value_t::number_float, json::value_t::number_float,
json::value_t::object, json::value_t::object,
json::value_t::array, json::value_t::array,
json::value_t::string, json::value_t::string,
json::value_t::binary, json::value_t::binary,
json::value_t::discarded json::value_t::discarded};
};
std::vector<std::vector<bool>> expected_lt = std::vector<std::vector<bool>> expected_lt =
{ {
//0 1 2 3 4 5 6 7 8 9 //0 1 2 3 4 5 6 7 8 9
{f_, _t, _t, _t, _t, _t, _t, _t, _t, f_}, // 0 {f_, _t, _t, _t, _t, _t, _t, _t, _t, f_}, // 0
{f_, f_, _t, _t, _t, _t, _t, _t, _t, f_}, // 1 {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_}, // 2
{f_, f_, f_, f_, f_, _t, _t, _t, _t, f_}, // 3 {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_, _t, _t, _t, _t, f_}, // 4
{f_, f_, f_, f_, f_, f_, _t, _t, _t, f_}, // 5 {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_, _t, _t, f_}, // 6
{f_, f_, f_, f_, f_, f_, f_, f_, _t, f_}, // 7 {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_}, // 8
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 9 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 9
}; };
SECTION("comparison: less") SECTION("comparison: less")
{ {
@@ -141,19 +139,19 @@ TEST_CASE("lexicographical comparison operators")
SECTION("comparison: 3-way") SECTION("comparison: 3-way")
{ {
std::vector<std::vector<std::partial_ordering>> expected = std::vector<std::vector<std::partial_ordering>> expected =
{ {
//0 1 2 3 4 5 6 7 8 9 //0 1 2 3 4 5 6 7 8 9
{eq, lt, lt, lt, lt, lt, lt, lt, lt, un}, // 0 {eq, lt, lt, lt, lt, lt, lt, lt, lt, un}, // 0
{gt, eq, lt, lt, lt, lt, lt, lt, lt, un}, // 1 {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}, // 2
{gt, gt, eq, eq, eq, lt, lt, lt, lt, un}, // 3 {gt, gt, eq, eq, eq, lt, lt, lt, lt, un}, // 3
{gt, gt, eq, eq, eq, lt, lt, lt, lt, un}, // 4 {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, eq, lt, lt, lt, un}, // 5
{gt, gt, gt, gt, gt, gt, eq, lt, lt, un}, // 6 {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, eq, lt, un}, // 7
{gt, gt, gt, gt, gt, gt, gt, gt, eq, un}, // 8 {gt, gt, gt, gt, gt, gt, gt, gt, eq, un}, // 8
{un, un, un, un, un, un, un, un, un, un}, // 9 {un, un, un, un, un, un, un, un, un, un}, // 9
}; };
// check expected partial_ordering against expected boolean // check expected partial_ordering against expected boolean
REQUIRE(expected.size() == expected_lt.size()); REQUIRE(expected.size() == expected_lt.size());
@@ -177,7 +175,7 @@ TEST_CASE("lexicographical comparison operators")
{ {
CAPTURE(i) CAPTURE(i)
CAPTURE(j) CAPTURE(j)
CHECK((j_types[i] <=> j_types[j]) == expected[i][j]); // *NOPAD* CHECK((j_types[i] <= > j_types[j]) == expected[i][j]); // *NOPAD*
} }
} }
} }
@@ -187,102 +185,113 @@ TEST_CASE("lexicographical comparison operators")
SECTION("values") SECTION("values")
{ {
json j_values = json j_values =
{ {
nullptr, nullptr, // 0 1 nullptr,
-17, 42, // 2 3 nullptr, // 0 1
8u, 13u, // 4 5 -17,
3.14159, 23.42, // 6 7 42, // 2 3
nan, nan, // 8 9 8u,
"foo", "bar", // 10 11 13u, // 4 5
true, false, // 12 13 3.14159,
{1, 2, 3}, {"one", "two", "three"}, // 14 15 23.42, // 6 7
{{"first", 1}, {"second", 2}}, {{"a", "A"}, {"b", {"B"}}}, // 16 17 nan,
json::binary({1, 2, 3}), json::binary({1, 2, 4}), // 18 19 nan, // 8 9
json(json::value_t::discarded), json(json::value_t::discarded) // 20 21 "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
};
std::vector<std::vector<bool>> expected_eq = 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 //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_}, // 0
{_t, _t, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 1 {_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_, _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_, _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_, _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_, _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_, _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_, _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_}, // 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_, 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_, _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_, _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_, _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_, _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_, _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_, _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_, _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_, _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_, _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_, _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_}, // 20
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 21 {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 = 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 //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_}, // 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_, _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_, _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_, 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_, _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, 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, _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_, _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_}, // 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_, _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_, 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_, 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, 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_, _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_, _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_, 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, 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_, _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_, _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_}, // 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_}, // 20
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 21 {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") SECTION("compares unordered")
{ {
std::vector<std::vector<bool>> expected = 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 //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}, // 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_, 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}, // 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}, // 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}, // 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}, // 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}, // 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_, 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}, // 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_, _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}, // 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}, // 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}, // 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}, // 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}, // 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}, // 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}, // 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}, // 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}, // 18
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, _t, _t}, // 19 {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}, // 20
{_t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t}, // 21 {_t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t, _t}, // 21
}; };
// check if two values compare unordered as expected // check if two values compare unordered as expected
REQUIRE(expected.size() == j_values.size()); REQUIRE(expected.size() == j_values.size());
@@ -302,31 +311,31 @@ TEST_CASE("lexicographical comparison operators")
SECTION("compares unordered (inverse)") SECTION("compares unordered (inverse)")
{ {
std::vector<std::vector<bool>> expected = 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 //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_}, // 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_, 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_}, // 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_}, // 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_}, // 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_}, // 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_}, // 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_, 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_}, // 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_, _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_}, // 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_}, // 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_}, // 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_}, // 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_}, // 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_}, // 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_}, // 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_}, // 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_}, // 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_}, // 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_}, // 20
{f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 21 {f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_, f_}, // 21
}; };
// check that two values compare unordered as expected (with legacy-mode enabled) // check that two values compare unordered as expected (with legacy-mode enabled)
REQUIRE(expected.size() == j_values.size()); REQUIRE(expected.size() == j_values.size());
@@ -497,31 +506,31 @@ TEST_CASE("lexicographical comparison operators")
SECTION("comparison: 3-way") SECTION("comparison: 3-way")
{ {
std::vector<std::vector<std::partial_ordering>> expected = 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 //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}, // 0
{eq, eq, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, lt, un, un}, // 1 {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, 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, 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, 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, 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, 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, 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}, // 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, 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, 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, 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, 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, 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, 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, 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, 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, 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, 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 {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}, // 20
{un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un}, // 21 {un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un, un}, // 21
}; };
// check expected partial_ordering against expected booleans // check expected partial_ordering against expected booleans
REQUIRE(expected.size() == expected_eq.size()); REQUIRE(expected.size() == expected_eq.size());
@@ -552,7 +561,7 @@ TEST_CASE("lexicographical comparison operators")
{ {
CAPTURE(i) CAPTURE(i)
CAPTURE(j) CAPTURE(j)
CHECK((j_values[i] <=> j_values[j]) == expected[i][j]); // *NOPAD* CHECK((j_values[i] <= > j_values[j]) == expected[i][j]); // *NOPAD*
} }
} }
} }
@@ -576,20 +585,18 @@ TEST_CASE("lexicographical comparison operators")
[1,2,[3,4,5],4,5] [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 json j_object = json::parse(s_object, [](int /*unused*/, json::parse_event_t /*unused*/, const json& j) noexcept {
{
// filter all number(2) elements // filter all number(2) elements
return j != json(2); return j != json(2);
}); });
CHECK (j_object == json({{"bar", {{"baz", 1}}}})); 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 /*unused*/, const json& j) noexcept {
{
return j != json(2); return j != json(2);
}); });
CHECK (j_array == json({1, {3, 4, 5}, 4, 5})); CHECK(j_array == json({1, {3, 4, 5}, 4, 5}));
} }
} }
#endif #endif
+2 -2
View File
@@ -130,7 +130,7 @@ TEST_CASE("concepts")
SECTION("Swappable") SECTION("Swappable")
{ {
{ {
json j {1, 2, 3}; json j{1, 2, 3};
json::iterator it1 = j.begin(); json::iterator it1 = j.begin();
json::iterator it2 = j.end(); json::iterator it2 = j.end();
swap(it1, it2); swap(it1, it2);
@@ -138,7 +138,7 @@ TEST_CASE("concepts")
CHECK(it2 == j.begin()); CHECK(it2 == j.begin());
} }
{ {
json j {1, 2, 3}; json j{1, 2, 3};
json::const_iterator it1 = j.cbegin(); json::const_iterator it1 = j.cbegin();
json::const_iterator it2 = j.cend(); json::const_iterator it2 = j.cend();
swap(it1, it2); swap(it1, it2);
+56 -58
View File
@@ -131,7 +131,7 @@ TEST_CASE("constructors")
SECTION("filled object") SECTION("filled object")
{ {
json::object_t const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; json::object_t const o{{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
json const j(o); json const j(o);
CHECK(j.type() == json::value_t::object); CHECK(j.type() == json::value_t::object);
} }
@@ -140,12 +140,12 @@ TEST_CASE("constructors")
SECTION("create an object (implicit)") SECTION("create an object (implicit)")
{ {
// reference object // reference object
json::object_t const o_reference {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; json::object_t const o_reference{{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
json const j_reference(o_reference); json const j_reference(o_reference);
SECTION("std::map<json::string_t, json>") SECTION("std::map<json::string_t, json>")
{ {
std::map<json::string_t, json> const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; std::map<json::string_t, json> const o{{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
json const j(o); json const j(o);
CHECK(j.type() == json::value_t::object); CHECK(j.type() == json::value_t::object);
CHECK(j == j_reference); CHECK(j == j_reference);
@@ -153,8 +153,7 @@ TEST_CASE("constructors")
SECTION("std::map<std::string, std::string> #600") SECTION("std::map<std::string, std::string> #600")
{ {
const std::map<std::string, std::string> m const std::map<std::string, std::string> m{
{
{"a", "b"}, {"a", "b"},
{"c", "d"}, {"c", "d"},
{"e", "f"}, {"e", "f"},
@@ -166,7 +165,7 @@ TEST_CASE("constructors")
SECTION("std::map<const char*, json>") SECTION("std::map<const char*, json>")
{ {
std::map<const char*, json> const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; std::map<const char*, json> const o{{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
json const j(o); json const j(o);
CHECK(j.type() == json::value_t::object); CHECK(j.type() == json::value_t::object);
CHECK(j == j_reference); CHECK(j == j_reference);
@@ -174,7 +173,7 @@ TEST_CASE("constructors")
SECTION("std::multimap<json::string_t, json>") SECTION("std::multimap<json::string_t, json>")
{ {
std::multimap<json::string_t, json> const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; std::multimap<json::string_t, json> const o{{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
json const j(o); json const j(o);
CHECK(j.type() == json::value_t::object); CHECK(j.type() == json::value_t::object);
CHECK(j == j_reference); CHECK(j == j_reference);
@@ -182,7 +181,7 @@ TEST_CASE("constructors")
SECTION("std::unordered_map<json::string_t, json>") SECTION("std::unordered_map<json::string_t, json>")
{ {
std::unordered_map<json::string_t, json> const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; std::unordered_map<json::string_t, json> const o{{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
json const j(o); json const j(o);
CHECK(j.type() == json::value_t::object); CHECK(j.type() == json::value_t::object);
CHECK(j == j_reference); CHECK(j == j_reference);
@@ -190,7 +189,7 @@ TEST_CASE("constructors")
SECTION("std::unordered_multimap<json::string_t, json>") SECTION("std::unordered_multimap<json::string_t, json>")
{ {
std::unordered_multimap<json::string_t, json> const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; std::unordered_multimap<json::string_t, json> const o{{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}};
json const j(o); json const j(o);
CHECK(j.type() == json::value_t::object); CHECK(j.type() == json::value_t::object);
CHECK(j == j_reference); CHECK(j == j_reference);
@@ -215,7 +214,7 @@ TEST_CASE("constructors")
SECTION("filled array") SECTION("filled array")
{ {
json::array_t const a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json::array_t const a{json(1), json(1u), json(2.2), json(false), json("string"), json()};
json const j(a); json const j(a);
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
@@ -224,12 +223,12 @@ TEST_CASE("constructors")
SECTION("create an array (implicit)") SECTION("create an array (implicit)")
{ {
// reference array // reference array
json::array_t const a_reference {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json::array_t const a_reference{json(1), json(1u), json(2.2), json(false), json("string"), json()};
json const j_reference(a_reference); json const j_reference(a_reference);
SECTION("std::list<json>") SECTION("std::list<json>")
{ {
std::list<json> const a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; std::list<json> const a{json(1), json(1u), json(2.2), json(false), json("string"), json()};
json const j(a); json const j(a);
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
CHECK(j == j_reference); CHECK(j == j_reference);
@@ -258,7 +257,7 @@ TEST_CASE("constructors")
SECTION("std::tuple") SECTION("std::tuple")
{ {
const auto t = std::make_tuple(1.0, std::string{"string"}, 42, std::vector<int> {0, 1}); const auto t = std::make_tuple(1.0, std::string{"string"}, 42, std::vector<int>{0, 1});
json const j(t); json const j(t);
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
@@ -292,7 +291,7 @@ TEST_CASE("constructors")
SECTION("std::forward_list<json>") SECTION("std::forward_list<json>")
{ {
std::forward_list<json> const a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; std::forward_list<json> const a{json(1), json(1u), json(2.2), json(false), json("string"), json()};
json const j(a); json const j(a);
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
CHECK(j == j_reference); CHECK(j == j_reference);
@@ -300,7 +299,7 @@ TEST_CASE("constructors")
SECTION("std::array<json, 6>") SECTION("std::array<json, 6>")
{ {
std::array<json, 6> const a {{json(1), json(1u), json(2.2), json(false), json("string"), json()}}; std::array<json, 6> const a{{json(1), json(1u), json(2.2), json(false), json("string"), json()}};
json const j(a); json const j(a);
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
CHECK(j == j_reference); CHECK(j == j_reference);
@@ -341,7 +340,7 @@ TEST_CASE("constructors")
SECTION("std::vector<json>") SECTION("std::vector<json>")
{ {
std::vector<json> const a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; std::vector<json> const a{json(1), json(1u), json(2.2), json(false), json("string"), json()};
json const j(a); json const j(a);
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
CHECK(j == j_reference); CHECK(j == j_reference);
@@ -349,7 +348,7 @@ TEST_CASE("constructors")
SECTION("std::deque<json>") SECTION("std::deque<json>")
{ {
std::deque<json> const a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; std::deque<json> const a{json(1), json(1u), json(2.2), json(false), json("string"), json()};
json const j(a); json const j(a);
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
CHECK(j == j_reference); CHECK(j == j_reference);
@@ -357,7 +356,7 @@ TEST_CASE("constructors")
SECTION("std::set<json>") SECTION("std::set<json>")
{ {
std::set<json> const a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; std::set<json> const a{json(1), json(1u), json(2.2), json(false), json("string"), json()};
json const j(a); json const j(a);
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
// we cannot really check for equality here // we cannot really check for equality here
@@ -365,7 +364,7 @@ TEST_CASE("constructors")
SECTION("std::unordered_set<json>") SECTION("std::unordered_set<json>")
{ {
std::unordered_set<json> const a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; std::unordered_set<json> const a{json(1), json(1u), json(2.2), json(false), json("string"), json()};
json const j(a); json const j(a);
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
// we cannot really check for equality here // we cannot really check for equality here
@@ -390,7 +389,7 @@ TEST_CASE("constructors")
SECTION("filled string") SECTION("filled string")
{ {
json::string_t const s {"Hello world"}; json::string_t const s{"Hello world"};
json const j(s); json const j(s);
CHECK(j.type() == json::value_t::string); CHECK(j.type() == json::value_t::string);
} }
@@ -399,12 +398,12 @@ TEST_CASE("constructors")
SECTION("create a string (implicit)") SECTION("create a string (implicit)")
{ {
// reference string // reference string
json::string_t const s_reference {"Hello world"}; json::string_t const s_reference{"Hello world"};
json const j_reference(s_reference); json const j_reference(s_reference);
SECTION("std::string") SECTION("std::string")
{ {
std::string const s {"Hello world"}; std::string const s{"Hello world"};
json const j(s); json const j(s);
CHECK(j.type() == json::value_t::string); CHECK(j.type() == json::value_t::string);
CHECK(j == j_reference); CHECK(j == j_reference);
@@ -412,7 +411,7 @@ TEST_CASE("constructors")
SECTION("char[]") SECTION("char[]")
{ {
char const s[] {"Hello world"}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) char const s[]{"Hello world"}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
json const j(s); json const j(s);
CHECK(j.type() == json::value_t::string); CHECK(j.type() == json::value_t::string);
CHECK(j == j_reference); CHECK(j == j_reference);
@@ -420,7 +419,7 @@ TEST_CASE("constructors")
SECTION("const char*") SECTION("const char*")
{ {
const char* s {"Hello world"}; const char* s{"Hello world"};
json const j(s); json const j(s);
CHECK(j.type() == json::value_t::string); CHECK(j.type() == json::value_t::string);
CHECK(j == j_reference); CHECK(j == j_reference);
@@ -918,13 +917,13 @@ TEST_CASE("constructors")
{ {
SECTION("explicit") SECTION("explicit")
{ {
json const j(json::initializer_list_t {}); json const j(json::initializer_list_t{});
CHECK(j.type() == json::value_t::object); CHECK(j.type() == json::value_t::object);
} }
SECTION("implicit") SECTION("implicit")
{ {
json const j {}; json const j{};
CHECK(j.type() == json::value_t::null); CHECK(j.type() == json::value_t::null);
} }
} }
@@ -935,13 +934,13 @@ TEST_CASE("constructors")
{ {
SECTION("explicit") SECTION("explicit")
{ {
json const j(json::initializer_list_t {json(json::array_t())}); json const j(json::initializer_list_t{json(json::array_t())});
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
SECTION("implicit") SECTION("implicit")
{ {
json const j {json::array_t()}; json const j{json::array_t()};
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
} }
@@ -950,13 +949,13 @@ TEST_CASE("constructors")
{ {
SECTION("explicit") SECTION("explicit")
{ {
json const j(json::initializer_list_t {json(json::object_t())}); json const j(json::initializer_list_t{json(json::object_t())});
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
SECTION("implicit") SECTION("implicit")
{ {
json const j {json::object_t()}; json const j{json::object_t()};
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
} }
@@ -965,13 +964,13 @@ TEST_CASE("constructors")
{ {
SECTION("explicit") SECTION("explicit")
{ {
json const j(json::initializer_list_t {json("Hello world")}); json const j(json::initializer_list_t{json("Hello world")});
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
SECTION("implicit") SECTION("implicit")
{ {
json const j {"Hello world"}; json const j{"Hello world"};
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
} }
@@ -980,13 +979,13 @@ TEST_CASE("constructors")
{ {
SECTION("explicit") SECTION("explicit")
{ {
json const j(json::initializer_list_t {json(true)}); json const j(json::initializer_list_t{json(true)});
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
SECTION("implicit") SECTION("implicit")
{ {
json const j {true}; json const j{true};
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
} }
@@ -995,13 +994,13 @@ TEST_CASE("constructors")
{ {
SECTION("explicit") SECTION("explicit")
{ {
json const j(json::initializer_list_t {json(1)}); json const j(json::initializer_list_t{json(1)});
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
SECTION("implicit") SECTION("implicit")
{ {
json const j {1}; json const j{1};
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
} }
@@ -1010,13 +1009,13 @@ TEST_CASE("constructors")
{ {
SECTION("explicit") SECTION("explicit")
{ {
json const j(json::initializer_list_t {json(1u)}); json const j(json::initializer_list_t{json(1u)});
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
SECTION("implicit") SECTION("implicit")
{ {
json const j {1u}; json const j{1u};
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
} }
@@ -1025,13 +1024,13 @@ TEST_CASE("constructors")
{ {
SECTION("explicit") SECTION("explicit")
{ {
json const j(json::initializer_list_t {json(42.23)}); json const j(json::initializer_list_t{json(42.23)});
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
SECTION("implicit") SECTION("implicit")
{ {
json const j {42.23}; json const j{42.23};
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
} }
@@ -1041,13 +1040,13 @@ TEST_CASE("constructors")
{ {
SECTION("explicit") SECTION("explicit")
{ {
json const j(json::initializer_list_t {1, 1u, 42.23, true, nullptr, json::object_t(), json::array_t()}); json const j(json::initializer_list_t{1, 1u, 42.23, true, nullptr, json::object_t(), json::array_t()});
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
SECTION("implicit") SECTION("implicit")
{ {
json const j {1, 1u, 42.23, true, nullptr, json::object_t(), json::array_t()}; json const j{1, 1u, 42.23, true, nullptr, json::object_t(), json::array_t()};
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
} }
@@ -1056,13 +1055,13 @@ TEST_CASE("constructors")
{ {
SECTION("object") SECTION("object")
{ {
json const j { {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false} }; json const j{{"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}};
CHECK(j.type() == json::value_t::object); CHECK(j.type() == json::value_t::object);
} }
SECTION("array") SECTION("array")
{ {
json const j { {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }; json const j{{"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13};
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
} }
@@ -1077,14 +1076,14 @@ TEST_CASE("constructors")
SECTION("object") SECTION("object")
{ {
json const j = json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false} }); json const j = json::object({{"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}});
CHECK(j.type() == json::value_t::object); CHECK(j.type() == json::value_t::object);
} }
SECTION("object with error") SECTION("object with error")
{ {
json _; json _;
CHECK_THROWS_WITH_AS(_ = json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }), "[json.exception.type_error.301] cannot create object from initializer list", json::type_error&); CHECK_THROWS_WITH_AS(_ = json::object({{"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13}), "[json.exception.type_error.301] cannot create object from initializer list", json::type_error&);
} }
SECTION("empty array") SECTION("empty array")
@@ -1095,7 +1094,7 @@ TEST_CASE("constructors")
SECTION("array") SECTION("array")
{ {
json const j = json::array({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false} }); json const j = json::array({{"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}});
CHECK(j.type() == json::value_t::array); CHECK(j.type() == json::value_t::array);
} }
} }
@@ -1144,7 +1143,7 @@ TEST_CASE("constructors")
{ {
json::array_t source = {1, 2, 3}; json::array_t source = {1, 2, 3};
const auto* source_addr = source.data(); const auto* source_addr = source.data();
json j {std::move(source)}; json j{std::move(source)};
const auto* target_addr = j[0].get_ref<json::array_t const&>().data(); const auto* target_addr = j[0].get_ref<json::array_t const&>().data();
const bool success = (target_addr == source_addr); const bool success = (target_addr == source_addr);
CHECK(success); CHECK(success);
@@ -1154,7 +1153,7 @@ TEST_CASE("constructors")
{ {
json::array_t source = {1, 2, 3}; json::array_t source = {1, 2, 3};
const auto* source_addr = source.data(); const auto* source_addr = source.data();
json const j {{"key", std::move(source)}}; json const j{{"key", std::move(source)}};
const auto* target_addr = j["key"].get_ref<json::array_t const&>().data(); const auto* target_addr = j["key"].get_ref<json::array_t const&>().data();
const bool success = (target_addr == source_addr); const bool success = (target_addr == source_addr);
CHECK(success); CHECK(success);
@@ -1187,7 +1186,7 @@ TEST_CASE("constructors")
{ {
json::object_t source = {{"hello", "world"}}; json::object_t source = {{"hello", "world"}};
const json* source_addr = &source.at("hello"); const json* source_addr = &source.at("hello");
json j {std::move(source)}; json j{std::move(source)};
CHECK(&(j[0].get_ref<json::object_t const&>().at("hello")) == source_addr); CHECK(&(j[0].get_ref<json::object_t const&>().at("hello")) == source_addr);
} }
@@ -1195,7 +1194,7 @@ TEST_CASE("constructors")
{ {
json::object_t source = {{"hello", "world"}}; json::object_t source = {{"hello", "world"}};
const json* source_addr = &source.at("hello"); const json* source_addr = &source.at("hello");
json j {{"key", std::move(source)}}; json j{{"key", std::move(source)}};
CHECK(&(j["key"].get_ref<json::object_t const&>().at("hello")) == source_addr); CHECK(&(j["key"].get_ref<json::object_t const&>().at("hello")) == source_addr);
} }
@@ -1220,23 +1219,23 @@ TEST_CASE("constructors")
{ {
SECTION("constructor with implicit types (array)") SECTION("constructor with implicit types (array)")
{ {
json source {1, 2, 3}; json source{1, 2, 3};
const json* source_addr = &source[0]; const json* source_addr = &source[0];
json j {std::move(source), {}}; json j{std::move(source), {}};
CHECK(&j[0][0] == source_addr); CHECK(&j[0][0] == source_addr);
} }
SECTION("constructor with implicit types (object)") SECTION("constructor with implicit types (object)")
{ {
json source {1, 2, 3}; json source{1, 2, 3};
const json* source_addr = &source[0]; const json* source_addr = &source[0];
json j {{"key", std::move(source)}}; json j{{"key", std::move(source)}};
CHECK(&j["key"][0] == source_addr); CHECK(&j["key"][0] == source_addr);
} }
SECTION("assignment with implicit types (array)") SECTION("assignment with implicit types (array)")
{ {
json source {1, 2, 3}; json source{1, 2, 3};
const json* source_addr = &source[0]; const json* source_addr = &source[0];
json j = {std::move(source), {}}; json j = {std::move(source), {}};
CHECK(&j[0][0] == source_addr); CHECK(&j[0][0] == source_addr);
@@ -1244,13 +1243,12 @@ TEST_CASE("constructors")
SECTION("assignment with implicit types (object)") SECTION("assignment with implicit types (object)")
{ {
json source {1, 2, 3}; json source{1, 2, 3};
const json* source_addr = &source[0]; const json* source_addr = &source[0];
json j = {{"key", std::move(source)}}; json j = {{"key", std::move(source)}};
CHECK(&j["key"][0] == source_addr); CHECK(&j["key"][0] == source_addr);
} }
} }
} }
} }
+21 -21
View File
@@ -17,82 +17,82 @@ TEST_CASE("other constructors and destructor")
{ {
SECTION("object") SECTION("object")
{ {
json j {{"foo", 1}, {"bar", false}}; json j{{"foo", 1}, {"bar", false}};
json k(j); // NOLINT(performance-unnecessary-copy-initialization) json k(j); // NOLINT(performance-unnecessary-copy-initialization)
CHECK(j == k); CHECK(j == k);
} }
SECTION("array") SECTION("array")
{ {
json j {"foo", 1, 42.23, false}; json j{"foo", 1, 42.23, false};
json k(j); // NOLINT(performance-unnecessary-copy-initialization) json k(j); // NOLINT(performance-unnecessary-copy-initialization)
CHECK(j == k); CHECK(j == k);
} }
SECTION("null") SECTION("null")
{ {
json j(nullptr); json j(nullptr);
json k(j); // NOLINT(performance-unnecessary-copy-initialization) json k(j); // NOLINT(performance-unnecessary-copy-initialization)
CHECK(j == k); CHECK(j == k);
} }
SECTION("boolean") SECTION("boolean")
{ {
json j(true); json j(true);
json k(j); // NOLINT(performance-unnecessary-copy-initialization) json k(j); // NOLINT(performance-unnecessary-copy-initialization)
CHECK(j == k); CHECK(j == k);
} }
SECTION("string") SECTION("string")
{ {
json j("Hello world"); json j("Hello world");
json k(j); // NOLINT(performance-unnecessary-copy-initialization) json k(j); // NOLINT(performance-unnecessary-copy-initialization)
CHECK(j == k); CHECK(j == k);
} }
SECTION("number (integer)") SECTION("number (integer)")
{ {
json j(42); json j(42);
json k(j); // NOLINT(performance-unnecessary-copy-initialization) json k(j); // NOLINT(performance-unnecessary-copy-initialization)
CHECK(j == k); CHECK(j == k);
} }
SECTION("number (unsigned)") SECTION("number (unsigned)")
{ {
json j(42u); json j(42u);
json k(j); // NOLINT(performance-unnecessary-copy-initialization) json k(j); // NOLINT(performance-unnecessary-copy-initialization)
CHECK(j == k); CHECK(j == k);
} }
SECTION("number (floating-point)") SECTION("number (floating-point)")
{ {
json j(42.23); json j(42.23);
json k(j); // NOLINT(performance-unnecessary-copy-initialization) json k(j); // NOLINT(performance-unnecessary-copy-initialization)
CHECK(j == k); CHECK(j == k);
} }
SECTION("binary") SECTION("binary")
{ {
json j = json::binary({1, 2, 3}); json j = json::binary({1, 2, 3});
json k(j); // NOLINT(performance-unnecessary-copy-initialization) json k(j); // NOLINT(performance-unnecessary-copy-initialization)
CHECK(j == k); CHECK(j == k);
} }
} }
SECTION("move constructor") SECTION("move constructor")
{ {
json j {{"foo", "bar"}, {"baz", {1, 2, 3, 4}}, {"a", 42u}, {"b", 42.23}, {"c", nullptr}}; json j{{"foo", "bar"}, {"baz", {1, 2, 3, 4}}, {"a", 42u}, {"b", 42.23}, {"c", nullptr}};
CHECK(j.type() == json::value_t::object); CHECK(j.type() == json::value_t::object);
const json k(std::move(j)); const json k(std::move(j));
CHECK(k.type() == json::value_t::object); CHECK(k.type() == json::value_t::object);
CHECK(j.type() == json::value_t::null); // NOLINT: access after move is OK here CHECK(j.type() == json::value_t::null); // NOLINT: access after move is OK here
} }
SECTION("copy assignment") SECTION("copy assignment")
{ {
SECTION("object") SECTION("object")
{ {
json j {{"foo", 1}, {"bar", false}}; json j{{"foo", 1}, {"bar", false}};
json k; json k;
k = j; k = j;
CHECK(j == k); CHECK(j == k);
@@ -100,7 +100,7 @@ TEST_CASE("other constructors and destructor")
SECTION("array") SECTION("array")
{ {
json j {"foo", 1, 42.23, false}; json j{"foo", 1, 42.23, false};
json k; json k;
k = j; k = j;
CHECK(j == k); CHECK(j == k);
@@ -167,20 +167,20 @@ TEST_CASE("other constructors and destructor")
{ {
SECTION("object") SECTION("object")
{ {
auto* j = new json {{"foo", 1}, {"bar", false}}; // NOLINT(cppcoreguidelines-owning-memory) auto* j = new json{{"foo", 1}, {"bar", false}}; // NOLINT(cppcoreguidelines-owning-memory)
delete j; // NOLINT(cppcoreguidelines-owning-memory) delete j; // NOLINT(cppcoreguidelines-owning-memory)
} }
SECTION("array") SECTION("array")
{ {
auto* j = new json {"foo", 1, 1u, false, 23.42}; // NOLINT(cppcoreguidelines-owning-memory) auto* j = new json{"foo", 1, 1u, false, 23.42}; // NOLINT(cppcoreguidelines-owning-memory)
delete j; // NOLINT(cppcoreguidelines-owning-memory) delete j; // NOLINT(cppcoreguidelines-owning-memory)
} }
SECTION("string") SECTION("string")
{ {
auto* j = new json("Hello world"); // NOLINT(cppcoreguidelines-owning-memory) auto* j = new json("Hello world"); // NOLINT(cppcoreguidelines-owning-memory)
delete j; // NOLINT(cppcoreguidelines-owning-memory) delete j; // NOLINT(cppcoreguidelines-owning-memory)
} }
} }
} }
+4 -5
View File
@@ -14,13 +14,12 @@ using nlohmann::json;
#include <sstream> #include <sstream>
namespace namespace {
{
struct alt_string_iter struct alt_string_iter
{ {
alt_string_iter() = default; alt_string_iter() = default;
alt_string_iter(const char* cstr) alt_string_iter(const char* cstr)
: impl(cstr) : impl(cstr)
{} {}
void reserve(std::size_t s) void reserve(std::size_t s)
@@ -62,7 +61,7 @@ struct alt_string_data
{ {
alt_string_data() = default; alt_string_data() = default;
alt_string_data(const char* cstr) alt_string_data(const char* cstr)
: impl(cstr) : impl(cstr)
{} {}
void reserve(std::size_t s) void reserve(std::size_t s)
@@ -102,7 +101,7 @@ void check_escaped(const char* original, const char* escaped, const bool ensure_
s.dump_escaped(original, ensure_ascii); s.dump_escaped(original, ensure_ascii);
CHECK(ss.str() == escaped); CHECK(ss.str() == escaped);
} }
} // namespace } // namespace
TEST_CASE("convenience functions") TEST_CASE("convenience functions")
{ {
+186 -113
View File
@@ -37,12 +37,11 @@ TEST_CASE("value conversion")
SECTION("get an object (explicit)") SECTION("get an object (explicit)")
{ {
const json::object_t o_reference = {{"object", json::object()}, const json::object_t o_reference = {{"object", json::object()},
{"array", {1, 2, 3, 4}}, {"array", {1, 2, 3, 4}},
{"number", 42}, {"number", 42},
{"boolean", false}, {"boolean", false},
{"null", nullptr}, {"null", nullptr},
{"string", "Hello world"} {"string", "Hello world"}};
};
json j(o_reference); json j(o_reference);
SECTION("json::object_t") SECTION("json::object_t")
@@ -83,37 +82,43 @@ TEST_CASE("value conversion")
{ {
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::null).get<json::object_t>(), json(json::value_t::null).get<json::object_t>(),
"[json.exception.type_error.302] type must be object, but is null", json::type_error&); "[json.exception.type_error.302] type must be object, but is null",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::array).get<json::object_t>(), json(json::value_t::array).get<json::object_t>(),
"[json.exception.type_error.302] type must be object, but is array", json::type_error&); "[json.exception.type_error.302] type must be object, but is array",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::string).get<json::object_t>(), json(json::value_t::string).get<json::object_t>(),
"[json.exception.type_error.302] type must be object, but is string", json::type_error&); "[json.exception.type_error.302] type must be object, but is string",
json::type_error&);
CHECK_THROWS_WITH_AS(json(json::value_t::boolean).get<json::object_t>(), CHECK_THROWS_WITH_AS(json(json::value_t::boolean).get<json::object_t>(),
"[json.exception.type_error.302] type must be object, " "[json.exception.type_error.302] type must be object, "
"but is boolean", json::type_error&); "but is boolean",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::number_integer).get<json::object_t>(), json(json::value_t::number_integer).get<json::object_t>(),
"[json.exception.type_error.302] type must be object, but is number", json::type_error&); "[json.exception.type_error.302] type must be object, but is number",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::number_unsigned).get<json::object_t>(), json(json::value_t::number_unsigned).get<json::object_t>(),
"[json.exception.type_error.302] type must be object, but is number", json::type_error&); "[json.exception.type_error.302] type must be object, but is number",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::number_float).get<json::object_t>(), json(json::value_t::number_float).get<json::object_t>(),
"[json.exception.type_error.302] type must be object, but is number", json::type_error&); "[json.exception.type_error.302] type must be object, but is number",
json::type_error&);
} }
} }
SECTION("get an object (explicit, get_to)") SECTION("get an object (explicit, get_to)")
{ {
const json::object_t o_reference = {{"object", json::object()}, const json::object_t o_reference = {{"object", json::object()},
{"array", {1, 2, 3, 4}}, {"array", {1, 2, 3, 4}},
{"number", 42}, {"number", 42},
{"boolean", false}, {"boolean", false},
{"null", nullptr}, {"null", nullptr},
{"string", "Hello world"} {"string", "Hello world"}};
};
json j(o_reference); json j(o_reference);
SECTION("json::object_t") SECTION("json::object_t")
@@ -156,12 +161,11 @@ TEST_CASE("value conversion")
SECTION("get an object (implicit)") SECTION("get an object (implicit)")
{ {
const json::object_t o_reference = {{"object", json::object()}, const json::object_t o_reference = {{"object", json::object()},
{"array", {1, 2, 3, 4}}, {"array", {1, 2, 3, 4}},
{"number", 42}, {"number", 42},
{"boolean", false}, {"boolean", false},
{"null", nullptr}, {"null", nullptr},
{"string", "Hello world"} {"string", "Hello world"}};
};
json j(o_reference); json j(o_reference);
SECTION("json::object_t") SECTION("json::object_t")
@@ -198,8 +202,7 @@ TEST_CASE("value conversion")
SECTION("get an array (explicit)") SECTION("get an array (explicit)")
{ {
const json::array_t a_reference{json(1), json(1u), json(2.2), const json::array_t a_reference{json(1), json(1u), json(2.2), json(false), json("string"), json()};
json(false), json("string"), json()};
json j(a_reference); json j(a_reference);
SECTION("json::array_t") SECTION("json::array_t")
@@ -221,7 +224,8 @@ TEST_CASE("value conversion")
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::null).get<std::forward_list<json>>(), json(json::value_t::null).get<std::forward_list<json>>(),
"[json.exception.type_error.302] type must be array, but is null", json::type_error&); "[json.exception.type_error.302] type must be array, but is null",
json::type_error&);
} }
SECTION("std::vector<json>") SECTION("std::vector<json>")
@@ -231,7 +235,8 @@ TEST_CASE("value conversion")
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::null).get<std::vector<json>>(), json(json::value_t::null).get<std::vector<json>>(),
"[json.exception.type_error.302] type must be array, but is null", json::type_error&); "[json.exception.type_error.302] type must be array, but is null",
json::type_error&);
#if !defined(JSON_NOEXCEPTION) #if !defined(JSON_NOEXCEPTION)
SECTION("reserve is called on containers that supports it") SECTION("reserve is called on containers that supports it")
@@ -246,8 +251,8 @@ TEST_CASE("value conversion")
SECTION("built-in arrays") SECTION("built-in arrays")
{ {
const char str[] = "a string"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) const char str[] = "a string"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
const int nbs[] = {0, 1, 2}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) const int nbs[] = {0, 1, 2}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
const json j2 = nbs; const json j2 = nbs;
const json j3 = str; const json j3 = str;
@@ -268,35 +273,42 @@ TEST_CASE("value conversion")
{ {
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::object).get<std::vector<int>>(), json(json::value_t::object).get<std::vector<int>>(),
"[json.exception.type_error.302] type must be array, but is object", json::type_error&); "[json.exception.type_error.302] type must be array, but is object",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::null).get<json::array_t>(), json(json::value_t::null).get<json::array_t>(),
"[json.exception.type_error.302] type must be array, but is null", json::type_error&); "[json.exception.type_error.302] type must be array, but is null",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::object).get<json::array_t>(), json(json::value_t::object).get<json::array_t>(),
"[json.exception.type_error.302] type must be array, but is object", json::type_error&); "[json.exception.type_error.302] type must be array, but is object",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::string).get<json::array_t>(), json(json::value_t::string).get<json::array_t>(),
"[json.exception.type_error.302] type must be array, but is string", json::type_error&); "[json.exception.type_error.302] type must be array, but is string",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::boolean).get<json::array_t>(), json(json::value_t::boolean).get<json::array_t>(),
"[json.exception.type_error.302] type must be array, but is boolean", json::type_error&); "[json.exception.type_error.302] type must be array, but is boolean",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::number_integer).get<json::array_t>(), json(json::value_t::number_integer).get<json::array_t>(),
"[json.exception.type_error.302] type must be array, but is number", json::type_error&); "[json.exception.type_error.302] type must be array, but is number",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::number_unsigned).get<json::array_t>(), json(json::value_t::number_unsigned).get<json::array_t>(),
"[json.exception.type_error.302] type must be array, but is number", json::type_error&); "[json.exception.type_error.302] type must be array, but is number",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::number_float).get<json::array_t>(), json(json::value_t::number_float).get<json::array_t>(),
"[json.exception.type_error.302] type must be array, but is number", json::type_error&); "[json.exception.type_error.302] type must be array, but is number",
json::type_error&);
} }
} }
SECTION("get an array (explicit, get_to)") SECTION("get an array (explicit, get_to)")
{ {
const json::array_t a_reference{json(1), json(1u), json(2.2), const json::array_t a_reference{json(1), json(1u), json(2.2), json(false), json("string"), json()};
json(false), json("string"), json()};
json j(a_reference); json j(a_reference);
SECTION("json::array_t") SECTION("json::array_t")
@@ -336,8 +348,8 @@ TEST_CASE("value conversion")
SECTION("built-in arrays") SECTION("built-in arrays")
{ {
const int nbs[] = {0, 1, 2}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) const int nbs[] = {0, 1, 2}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
int nbs2[] = {0, 0, 0}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) int nbs2[] = {0, 0, 0}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
const json j2 = nbs; const json j2 = nbs;
j2.get_to(nbs2); j2.get_to(nbs2);
@@ -355,8 +367,7 @@ TEST_CASE("value conversion")
#if JSON_USE_IMPLICIT_CONVERSIONS #if JSON_USE_IMPLICIT_CONVERSIONS
SECTION("get an array (implicit)") SECTION("get an array (implicit)")
{ {
const json::array_t a_reference{json(1), json(1u), json(2.2), const json::array_t a_reference{json(1), json(1u), json(2.2), json(false), json("string"), json()};
json(false), json("string"), json()};
json j(a_reference); json j(a_reference);
SECTION("json::array_t") SECTION("json::array_t")
@@ -419,44 +430,58 @@ TEST_CASE("value conversion")
{ {
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::null).get<json::string_t>(), json(json::value_t::null).get<json::string_t>(),
"[json.exception.type_error.302] type must be string, but is null", json::type_error&); "[json.exception.type_error.302] type must be string, but is null",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::object).get<json::string_t>(), json(json::value_t::object).get<json::string_t>(),
"[json.exception.type_error.302] type must be string, but is object", json::type_error&); "[json.exception.type_error.302] type must be string, but is object",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::array).get<json::string_t>(), json(json::value_t::array).get<json::string_t>(),
"[json.exception.type_error.302] type must be string, but is array", json::type_error&); "[json.exception.type_error.302] type must be string, but is array",
json::type_error&);
CHECK_THROWS_WITH_AS(json(json::value_t::boolean).get<json::string_t>(), CHECK_THROWS_WITH_AS(json(json::value_t::boolean).get<json::string_t>(),
"[json.exception.type_error.302] type must be string, " "[json.exception.type_error.302] type must be string, "
"but is boolean", json::type_error&); "but is boolean",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::number_integer).get<json::string_t>(), json(json::value_t::number_integer).get<json::string_t>(),
"[json.exception.type_error.302] type must be string, but is number", json::type_error&); "[json.exception.type_error.302] type must be string, but is number",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::number_unsigned).get<json::string_t>(), json(json::value_t::number_unsigned).get<json::string_t>(),
"[json.exception.type_error.302] type must be string, but is number", json::type_error&); "[json.exception.type_error.302] type must be string, but is number",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::number_float).get<json::string_t>(), json(json::value_t::number_float).get<json::string_t>(),
"[json.exception.type_error.302] type must be string, but is number", json::type_error&); "[json.exception.type_error.302] type must be string, but is number",
json::type_error&);
} }
#if defined(JSON_HAS_CPP_17) #if defined(JSON_HAS_CPP_17)
SECTION("exception in case of a non-string type using string_view") SECTION("exception in case of a non-string type using string_view")
{ {
CHECK_THROWS_WITH_AS(json(json::value_t::null).get<std::string_view>(), CHECK_THROWS_WITH_AS(json(json::value_t::null).get<std::string_view>(),
"[json.exception.type_error.302] type must be string, but is null", json::type_error&); "[json.exception.type_error.302] type must be string, but is null",
json::type_error&);
CHECK_THROWS_WITH_AS(json(json::value_t::object).get<std::string_view>(), CHECK_THROWS_WITH_AS(json(json::value_t::object).get<std::string_view>(),
"[json.exception.type_error.302] type must be string, but is object", json::type_error&); "[json.exception.type_error.302] type must be string, but is object",
json::type_error&);
CHECK_THROWS_WITH_AS(json(json::value_t::array).get<std::string_view>(), CHECK_THROWS_WITH_AS(json(json::value_t::array).get<std::string_view>(),
"[json.exception.type_error.302] type must be string, but is array", json::type_error&); "[json.exception.type_error.302] type must be string, but is array",
json::type_error&);
CHECK_THROWS_WITH_AS(json(json::value_t::boolean).get<std::string_view>(), CHECK_THROWS_WITH_AS(json(json::value_t::boolean).get<std::string_view>(),
"[json.exception.type_error.302] type must be string, but is boolean", json::type_error&); "[json.exception.type_error.302] type must be string, but is boolean",
json::type_error&);
CHECK_THROWS_WITH_AS(json(json::value_t::number_integer).get<std::string_view>(), CHECK_THROWS_WITH_AS(json(json::value_t::number_integer).get<std::string_view>(),
"[json.exception.type_error.302] type must be string, but is number", json::type_error&); "[json.exception.type_error.302] type must be string, but is number",
json::type_error&);
CHECK_THROWS_WITH_AS(json(json::value_t::number_unsigned).get<std::string_view>(), CHECK_THROWS_WITH_AS(json(json::value_t::number_unsigned).get<std::string_view>(),
"[json.exception.type_error.302] type must be string, but is number", json::type_error&); "[json.exception.type_error.302] type must be string, but is number",
json::type_error&);
CHECK_THROWS_WITH_AS(json(json::value_t::number_float).get<std::string_view>(), CHECK_THROWS_WITH_AS(json(json::value_t::number_float).get<std::string_view>(),
"[json.exception.type_error.302] type must be string, but is number", json::type_error&); "[json.exception.type_error.302] type must be string, but is number",
json::type_error&);
} }
#endif #endif
} }
@@ -499,19 +524,26 @@ TEST_CASE("value conversion")
CHECK(n2 == n); CHECK(n2 == n);
CHECK_THROWS_WITH_AS(json(json::value_t::string).get<std::nullptr_t>(), CHECK_THROWS_WITH_AS(json(json::value_t::string).get<std::nullptr_t>(),
"[json.exception.type_error.302] type must be null, but is string", json::type_error&); "[json.exception.type_error.302] type must be null, but is string",
json::type_error&);
CHECK_THROWS_WITH_AS(json(json::value_t::object).get<std::nullptr_t>(), CHECK_THROWS_WITH_AS(json(json::value_t::object).get<std::nullptr_t>(),
"[json.exception.type_error.302] type must be null, but is object", json::type_error&); "[json.exception.type_error.302] type must be null, but is object",
json::type_error&);
CHECK_THROWS_WITH_AS(json(json::value_t::array).get<std::nullptr_t>(), CHECK_THROWS_WITH_AS(json(json::value_t::array).get<std::nullptr_t>(),
"[json.exception.type_error.302] type must be null, but is array", json::type_error&); "[json.exception.type_error.302] type must be null, but is array",
json::type_error&);
CHECK_THROWS_WITH_AS(json(json::value_t::boolean).get<std::nullptr_t>(), CHECK_THROWS_WITH_AS(json(json::value_t::boolean).get<std::nullptr_t>(),
"[json.exception.type_error.302] type must be null, but is boolean", json::type_error&); "[json.exception.type_error.302] type must be null, but is boolean",
json::type_error&);
CHECK_THROWS_WITH_AS(json(json::value_t::number_integer).get<std::nullptr_t>(), CHECK_THROWS_WITH_AS(json(json::value_t::number_integer).get<std::nullptr_t>(),
"[json.exception.type_error.302] type must be null, but is number", json::type_error&); "[json.exception.type_error.302] type must be null, but is number",
json::type_error&);
CHECK_THROWS_WITH_AS(json(json::value_t::number_unsigned).get<std::nullptr_t>(), CHECK_THROWS_WITH_AS(json(json::value_t::number_unsigned).get<std::nullptr_t>(),
"[json.exception.type_error.302] type must be null, but is number", json::type_error&); "[json.exception.type_error.302] type must be null, but is number",
json::type_error&);
CHECK_THROWS_WITH_AS(json(json::value_t::number_float).get<std::nullptr_t>(), CHECK_THROWS_WITH_AS(json(json::value_t::number_float).get<std::nullptr_t>(),
"[json.exception.type_error.302] type must be null, but is number", json::type_error&); "[json.exception.type_error.302] type must be null, but is number",
json::type_error&);
} }
#if JSON_USE_IMPLICIT_CONVERSIONS #if JSON_USE_IMPLICIT_CONVERSIONS
@@ -526,13 +558,13 @@ TEST_CASE("value conversion")
CHECK(json(s) == j); CHECK(json(s) == j);
} }
#if defined(JSON_HAS_CPP_17) #if defined(JSON_HAS_CPP_17)
SECTION("std::string_view") SECTION("std::string_view")
{ {
std::string_view const s = j.get<std::string_view>(); std::string_view const s = j.get<std::string_view>();
CHECK(json(s) == j); CHECK(json(s) == j);
} }
#endif #endif
SECTION("std::string") SECTION("std::string")
{ {
@@ -572,28 +604,35 @@ TEST_CASE("value conversion")
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::null).get<json::boolean_t>(), json(json::value_t::null).get<json::boolean_t>(),
"[json.exception.type_error.302] type must be boolean, but is null", json::type_error&); "[json.exception.type_error.302] type must be boolean, but is null",
json::type_error&);
CHECK_THROWS_WITH_AS(json(json::value_t::object).get<json::boolean_t>(), CHECK_THROWS_WITH_AS(json(json::value_t::object).get<json::boolean_t>(),
"[json.exception.type_error.302] type must be boolean, " "[json.exception.type_error.302] type must be boolean, "
"but is object", json::type_error&); "but is object",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::array).get<json::boolean_t>(), json(json::value_t::array).get<json::boolean_t>(),
"[json.exception.type_error.302] type must be boolean, but is array", json::type_error&); "[json.exception.type_error.302] type must be boolean, but is array",
json::type_error&);
CHECK_THROWS_WITH_AS(json(json::value_t::string).get<json::boolean_t>(), CHECK_THROWS_WITH_AS(json(json::value_t::string).get<json::boolean_t>(),
"[json.exception.type_error.302] type must be boolean, " "[json.exception.type_error.302] type must be boolean, "
"but is string", json::type_error&); "but is string",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::number_integer).get<json::boolean_t>(), json(json::value_t::number_integer).get<json::boolean_t>(),
"[json.exception.type_error.302] type must be boolean, but is " "[json.exception.type_error.302] type must be boolean, but is "
"number", json::type_error&); "number",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::number_unsigned).get<json::boolean_t>(), json(json::value_t::number_unsigned).get<json::boolean_t>(),
"[json.exception.type_error.302] type must be boolean, but is " "[json.exception.type_error.302] type must be boolean, but is "
"number", json::type_error&); "number",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::number_float).get<json::boolean_t>(), json(json::value_t::number_float).get<json::boolean_t>(),
"[json.exception.type_error.302] type must be boolean, but is " "[json.exception.type_error.302] type must be boolean, but is "
"number", json::type_error&); "number",
json::type_error&);
} }
} }
@@ -832,20 +871,25 @@ TEST_CASE("value conversion")
{ {
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::null).get<json::number_integer_t>(), json(json::value_t::null).get<json::number_integer_t>(),
"[json.exception.type_error.302] type must be number, but is null", json::type_error&); "[json.exception.type_error.302] type must be number, but is null",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::object).get<json::number_integer_t>(), json(json::value_t::object).get<json::number_integer_t>(),
"[json.exception.type_error.302] type must be number, but is object", json::type_error&); "[json.exception.type_error.302] type must be number, but is object",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::array).get<json::number_integer_t>(), json(json::value_t::array).get<json::number_integer_t>(),
"[json.exception.type_error.302] type must be number, but is array", json::type_error&); "[json.exception.type_error.302] type must be number, but is array",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::string).get<json::number_integer_t>(), json(json::value_t::string).get<json::number_integer_t>(),
"[json.exception.type_error.302] type must be number, but is string", json::type_error&); "[json.exception.type_error.302] type must be number, but is string",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::boolean).get<json::number_integer_t>(), json(json::value_t::boolean).get<json::number_integer_t>(),
"[json.exception.type_error.302] type must be number, but is " "[json.exception.type_error.302] type must be number, but is "
"boolean", json::type_error&); "boolean",
json::type_error&);
CHECK_NOTHROW( CHECK_NOTHROW(
json(json::value_t::number_float).get<json::number_integer_t>()); json(json::value_t::number_float).get<json::number_integer_t>());
@@ -1095,20 +1139,25 @@ TEST_CASE("value conversion")
{ {
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::null).get<json::number_float_t>(), json(json::value_t::null).get<json::number_float_t>(),
"[json.exception.type_error.302] type must be number, but is null", json::type_error&); "[json.exception.type_error.302] type must be number, but is null",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::object).get<json::number_float_t>(), json(json::value_t::object).get<json::number_float_t>(),
"[json.exception.type_error.302] type must be number, but is object", json::type_error&); "[json.exception.type_error.302] type must be number, but is object",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::array).get<json::number_float_t>(), json(json::value_t::array).get<json::number_float_t>(),
"[json.exception.type_error.302] type must be number, but is array", json::type_error&); "[json.exception.type_error.302] type must be number, but is array",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::string).get<json::number_float_t>(), json(json::value_t::string).get<json::number_float_t>(),
"[json.exception.type_error.302] type must be number, but is string", json::type_error&); "[json.exception.type_error.302] type must be number, but is string",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
json(json::value_t::boolean).get<json::number_float_t>(), json(json::value_t::boolean).get<json::number_float_t>(),
"[json.exception.type_error.302] type must be number, but is " "[json.exception.type_error.302] type must be number, but is "
"boolean", json::type_error&); "boolean",
json::type_error&);
CHECK_NOTHROW( CHECK_NOTHROW(
json(json::value_t::number_integer).get<json::number_float_t>()); json(json::value_t::number_integer).get<json::number_float_t>());
@@ -1265,8 +1314,16 @@ TEST_CASE("value conversion")
SECTION("get an enum") SECTION("get an enum")
{ {
enum c_enum { value_1, value_2 }; enum c_enum
enum class cpp_enum { value_1, value_2 }; {
value_1,
value_2
};
enum class cpp_enum
{
value_1,
value_2
};
CHECK(json(value_1).get<c_enum>() == value_1); CHECK(json(value_1).get<c_enum>() == value_1);
CHECK(json(cpp_enum::value_1).get<cpp_enum>() == cpp_enum::value_1); CHECK(json(cpp_enum::value_1).get<cpp_enum>() == cpp_enum::value_1);
@@ -1325,7 +1382,8 @@ TEST_CASE("value conversion")
{ {
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
(json().get<std::map<std::string, int>>()), (json().get<std::map<std::string, int>>()),
"[json.exception.type_error.302] type must be object, but is null", json::type_error&); "[json.exception.type_error.302] type must be object, but is null",
json::type_error&);
} }
} }
@@ -1367,7 +1425,8 @@ TEST_CASE("value conversion")
{ {
std::array<int, 6> arr6 = {{1, 2, 3, 4, 5, 6}}; std::array<int, 6> arr6 = {{1, 2, 3, 4, 5, 6}};
CHECK_THROWS_WITH_AS(j1.get_to(arr6), "[json.exception.out_of_range.401] " CHECK_THROWS_WITH_AS(j1.get_to(arr6), "[json.exception.out_of_range.401] "
"array index 4 is out of range", json::out_of_range&); "array index 4 is out of range",
json::out_of_range&);
} }
SECTION("std::array is smaller than JSON") SECTION("std::array is smaller than JSON")
@@ -1436,10 +1495,12 @@ TEST_CASE("value conversion")
json const j8 = 2; json const j8 = 2;
CHECK_THROWS_WITH_AS((j7.get<std::map<int, int>>()), CHECK_THROWS_WITH_AS((j7.get<std::map<int, int>>()),
"[json.exception.type_error.302] type must be array, " "[json.exception.type_error.302] type must be array, "
"but is number", json::type_error&); "but is number",
json::type_error&);
CHECK_THROWS_WITH_AS((j8.get<std::map<int, int>>()), CHECK_THROWS_WITH_AS((j8.get<std::map<int, int>>()),
"[json.exception.type_error.302] type must be array, " "[json.exception.type_error.302] type must be array, "
"but is number", json::type_error&); "but is number",
json::type_error&);
SECTION("superfluous entries") SECTION("superfluous entries")
{ {
@@ -1461,10 +1522,12 @@ TEST_CASE("value conversion")
json const j8 = 2; json const j8 = 2;
CHECK_THROWS_WITH_AS((j7.get<std::unordered_map<int, int>>()), CHECK_THROWS_WITH_AS((j7.get<std::unordered_map<int, int>>()),
"[json.exception.type_error.302] type must be array, " "[json.exception.type_error.302] type must be array, "
"but is number", json::type_error&); "but is number",
json::type_error&);
CHECK_THROWS_WITH_AS((j8.get<std::unordered_map<int, int>>()), CHECK_THROWS_WITH_AS((j8.get<std::unordered_map<int, int>>()),
"[json.exception.type_error.302] type must be array, " "[json.exception.type_error.302] type must be array, "
"but is number", json::type_error&); "but is number",
json::type_error&);
SECTION("superfluous entries") SECTION("superfluous entries")
{ {
@@ -1480,38 +1543,48 @@ TEST_CASE("value conversion")
// that's what I thought when other test like this one broke // that's what I thought when other test like this one broke
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
(json().get<std::list<int>>()), (json().get<std::list<int>>()),
"[json.exception.type_error.302] type must be array, but is null", json::type_error&); "[json.exception.type_error.302] type must be array, but is null",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
(json().get<std::vector<int>>()), (json().get<std::vector<int>>()),
"[json.exception.type_error.302] type must be array, but is null", json::type_error&); "[json.exception.type_error.302] type must be array, but is null",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
(json().get<std::vector<json>>()), (json().get<std::vector<json>>()),
"[json.exception.type_error.302] type must be array, but is null", json::type_error&); "[json.exception.type_error.302] type must be array, but is null",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
(json().get<std::list<json>>()), (json().get<std::list<json>>()),
"[json.exception.type_error.302] type must be array, but is null", json::type_error&); "[json.exception.type_error.302] type must be array, but is null",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
(json().get<std::valarray<int>>()), (json().get<std::valarray<int>>()),
"[json.exception.type_error.302] type must be array, but is null", json::type_error&); "[json.exception.type_error.302] type must be array, but is null",
json::type_error&);
CHECK_THROWS_WITH_AS( CHECK_THROWS_WITH_AS(
(json().get<std::map<int, int>>()), (json().get<std::map<int, int>>()),
"[json.exception.type_error.302] type must be array, but is null", json::type_error&); "[json.exception.type_error.302] type must be array, but is null",
json::type_error&);
} }
} }
} }
} }
enum class cards {kreuz, pik, herz, karo}; enum class cards
{
kreuz,
pik,
herz,
karo
};
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
NLOHMANN_JSON_SERIALIZE_ENUM(cards, NLOHMANN_JSON_SERIALIZE_ENUM(cards,
{ {{cards::kreuz, "kreuz"},
{cards::kreuz, "kreuz"}, {cards::pik, "pik"},
{cards::pik, "pik"}, {cards::pik, "puk"}, // second entry for cards::puk; will not be used
{cards::pik, "puk"}, // second entry for cards::puk; will not be used {cards::herz, "herz"},
{cards::herz, "herz"}, {cards::karo, "karo"}})
{cards::karo, "karo"}
})
enum TaskState enum TaskState
{ {
@@ -1523,12 +1596,12 @@ enum TaskState
// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) - false positive
NLOHMANN_JSON_SERIALIZE_ENUM(TaskState, NLOHMANN_JSON_SERIALIZE_ENUM(TaskState,
{ {
{TS_INVALID, nullptr}, {TS_INVALID, nullptr},
{TS_STOPPED, "stopped"}, {TS_STOPPED, "stopped"},
{TS_RUNNING, "running"}, {TS_RUNNING, "running"},
{TS_COMPLETED, "completed"}, {TS_COMPLETED, "completed"},
}) })
TEST_CASE("JSON to enum mapping") TEST_CASE("JSON to enum mapping")
{ {
+114 -118
View File
@@ -30,25 +30,25 @@ class json_metadata
{ {
return m_metadata; return m_metadata;
} }
private: private:
metadata_t m_metadata = {}; metadata_t m_metadata = {};
}; };
template<class T> template<class T>
using json_with_metadata = using json_with_metadata =
nlohmann::basic_json < nlohmann::basic_json<
std::map, std::map,
std::vector, std::vector,
std::string, std::string,
bool, bool,
std::int64_t, std::int64_t,
std::uint64_t, std::uint64_t,
double, double,
std::allocator, std::allocator,
nlohmann::adl_serializer, nlohmann::adl_serializer,
std::vector<std::uint8_t>, std::vector<std::uint8_t>,
json_metadata<T> json_metadata<T>>;
>;
TEST_CASE("JSON Node Metadata") TEST_CASE("JSON Node Metadata")
{ {
@@ -56,18 +56,18 @@ TEST_CASE("JSON Node Metadata")
{ {
using json = json_with_metadata<int>; using json = json_with_metadata<int>;
json null; json null;
auto obj = json::object(); auto obj = json::object();
auto array = json::array(); auto array = json::array();
null.metadata() = 1; null.metadata() = 1;
obj.metadata() = 2; obj.metadata() = 2;
array.metadata() = 3; array.metadata() = 3;
auto copy = array; auto copy = array;
CHECK(null.metadata() == 1); CHECK(null.metadata() == 1);
CHECK(obj.metadata() == 2); CHECK(obj.metadata() == 2);
CHECK(array.metadata() == 3); CHECK(array.metadata() == 3);
CHECK(copy.metadata() == 3); CHECK(copy.metadata() == 3);
} }
SECTION("type vector<int>") SECTION("type vector<int>")
{ {
@@ -77,11 +77,11 @@ TEST_CASE("JSON Node Metadata")
auto copy = value; auto copy = value;
value.metadata().emplace_back(2); value.metadata().emplace_back(2);
CHECK(copy.metadata().size() == 1); CHECK(copy.metadata().size() == 1);
CHECK(copy.metadata().at(0) == 1); CHECK(copy.metadata().at(0) == 1);
CHECK(value.metadata().size() == 2); CHECK(value.metadata().size() == 2);
CHECK(value.metadata().at(0) == 1); CHECK(value.metadata().at(0) == 1);
CHECK(value.metadata().at(1) == 2); CHECK(value.metadata().at(1) == 2);
} }
SECTION("copy ctor") SECTION("copy ctor")
{ {
@@ -92,15 +92,15 @@ TEST_CASE("JSON Node Metadata")
json copy = value; json copy = value;
CHECK(copy.metadata().size() == 2); CHECK(copy.metadata().size() == 2);
CHECK(copy.metadata().at(0) == 1); CHECK(copy.metadata().at(0) == 1);
CHECK(copy.metadata().at(1) == 2); CHECK(copy.metadata().at(1) == 2);
CHECK(value.metadata().size() == 2); CHECK(value.metadata().size() == 2);
CHECK(value.metadata().at(0) == 1); CHECK(value.metadata().at(0) == 1);
CHECK(value.metadata().at(1) == 2); CHECK(value.metadata().at(1) == 2);
value.metadata().clear(); value.metadata().clear();
CHECK(copy.metadata().size() == 2); CHECK(copy.metadata().size() == 2);
CHECK(value.metadata().size() == 0); CHECK(value.metadata().size() == 0);
} }
SECTION("move ctor") SECTION("move ctor")
@@ -112,9 +112,9 @@ TEST_CASE("JSON Node Metadata")
const json moved = std::move(value); const json moved = std::move(value);
CHECK(moved.metadata().size() == 2); CHECK(moved.metadata().size() == 2);
CHECK(moved.metadata().at(0) == 1); CHECK(moved.metadata().at(0) == 1);
CHECK(moved.metadata().at(1) == 2); CHECK(moved.metadata().at(1) == 2);
} }
SECTION("move assign") SECTION("move assign")
{ {
@@ -126,9 +126,9 @@ TEST_CASE("JSON Node Metadata")
json moved; json moved;
moved = std::move(value); moved = std::move(value);
CHECK(moved.metadata().size() == 2); CHECK(moved.metadata().size() == 2);
CHECK(moved.metadata().at(0) == 1); CHECK(moved.metadata().at(0) == 1);
CHECK(moved.metadata().at(1) == 2); CHECK(moved.metadata().at(1) == 2);
} }
SECTION("copy assign") SECTION("copy assign")
{ {
@@ -140,22 +140,22 @@ TEST_CASE("JSON Node Metadata")
json copy; json copy;
copy = value; copy = value;
CHECK(copy.metadata().size() == 2); CHECK(copy.metadata().size() == 2);
CHECK(copy.metadata().at(0) == 1); CHECK(copy.metadata().at(0) == 1);
CHECK(copy.metadata().at(1) == 2); CHECK(copy.metadata().at(1) == 2);
CHECK(value.metadata().size() == 2); CHECK(value.metadata().size() == 2);
CHECK(value.metadata().at(0) == 1); CHECK(value.metadata().at(0) == 1);
CHECK(value.metadata().at(1) == 2); CHECK(value.metadata().at(1) == 2);
value.metadata().clear(); value.metadata().clear();
CHECK(copy.metadata().size() == 2); CHECK(copy.metadata().size() == 2);
CHECK(value.metadata().size() == 0); CHECK(value.metadata().size() == 0);
} }
SECTION("type unique_ptr<int>") SECTION("type unique_ptr<int>")
{ {
using json = json_with_metadata<std::unique_ptr<int>>; using json = json_with_metadata<std::unique_ptr<int>>;
json value; json value;
value.metadata().reset(new int(42)); // NOLINT(cppcoreguidelines-owning-memory) value.metadata().reset(new int(42)); // NOLINT(cppcoreguidelines-owning-memory)
auto moved = std::move(value); auto moved = std::move(value);
CHECK(moved.metadata() != nullptr); CHECK(moved.metadata() != nullptr);
@@ -171,14 +171,14 @@ TEST_CASE("JSON Node Metadata")
json const array(10, value); json const array(10, value);
CHECK(value.metadata().size() == 2); CHECK(value.metadata().size() == 2);
CHECK(value.metadata().at(0) == 1); CHECK(value.metadata().at(0) == 1);
CHECK(value.metadata().at(1) == 2); CHECK(value.metadata().at(1) == 2);
for (const auto& val : array) for (const auto& val : array)
{ {
CHECK(val.metadata().size() == 2); CHECK(val.metadata().size() == 2);
CHECK(val.metadata().at(0) == 1); CHECK(val.metadata().at(0) == 1);
CHECK(val.metadata().at(1) == 2); CHECK(val.metadata().at(1) == 2);
} }
} }
} }
@@ -188,38 +188,38 @@ TEST_CASE("JSON Node Metadata")
class visitor_adaptor class visitor_adaptor
{ {
public: public:
template <class Fnc> template<class Fnc>
void visit(const Fnc& fnc) const; void visit(const Fnc& fnc) const;
private: private:
template <class Ptr, class Fnc> template<class Ptr, class Fnc>
void do_visit(const Ptr& ptr, const Fnc& fnc) const; void do_visit(const Ptr& ptr, const Fnc& fnc) const;
}; };
using json_with_visitor_t = nlohmann::basic_json < using json_with_visitor_t = nlohmann::basic_json<
std::map, std::map,
std::vector, std::vector,
std::string, std::string,
bool, bool,
std::int64_t, std::int64_t,
std::uint64_t, std::uint64_t,
double, double,
std::allocator, std::allocator,
nlohmann::adl_serializer, nlohmann::adl_serializer,
std::vector<std::uint8_t>, std::vector<std::uint8_t>,
visitor_adaptor visitor_adaptor>;
>;
template <class Fnc> template<class Fnc>
void visitor_adaptor::visit(const Fnc& fnc) const void visitor_adaptor::visit(const Fnc& fnc) const
{ {
do_visit(json_with_visitor_t::json_pointer{}, fnc); do_visit(json_with_visitor_t::json_pointer{}, fnc);
} }
template <class Ptr, class Fnc> template<class Ptr, class Fnc>
void visitor_adaptor::do_visit(const Ptr& ptr, const Fnc& fnc) const void visitor_adaptor::do_visit(const Ptr& ptr, const Fnc& fnc) const
{ {
using value_t = nlohmann::detail::value_t; using value_t = nlohmann::detail::value_t;
const json_with_visitor_t& json = *static_cast<const json_with_visitor_t*>(this); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast) const json_with_visitor_t& json = *static_cast<const json_with_visitor_t*>(this); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
switch (json.type()) switch (json.type())
{ {
case value_t::object: case value_t::object:
@@ -252,7 +252,7 @@ TEST_CASE("JSON Visit Node")
{ {
json_with_visitor_t json; json_with_visitor_t json;
json["null"]; json["null"];
json["int"] = -1; json["int"] = -1;
json["uint"] = 1U; json["uint"] = 1U;
json["float"] = 1.0; json["float"] = 1.0;
json["boolean"] = true; json["boolean"] = true;
@@ -261,8 +261,7 @@ TEST_CASE("JSON Visit Node")
json["array"].push_back(1); json["array"].push_back(1);
json["array"].push_back(json); json["array"].push_back(json);
std::set<std::string> expected std::set<std::string> expected{
{
"/null - null - null", "/null - null - null",
"/int - number_integer - -1", "/int - number_integer - -1",
"/uint - number_unsigned - 1", "/uint - number_unsigned - 1",
@@ -279,58 +278,55 @@ TEST_CASE("JSON Visit Node")
"/array/2/boolean - boolean - true", "/array/2/boolean - boolean - true",
"/array/2/string - string - \"string\"", "/array/2/string - string - \"string\"",
"/array/2/array/0 - number_integer - 0", "/array/2/array/0 - number_integer - 0",
"/array/2/array/1 - number_integer - 1" "/array/2/array/1 - number_integer - 1"};
};
json.visit( json.visit(
[&](const json_with_visitor_t::json_pointer & p, [&](const json_with_visitor_t::json_pointer& p,
const json_with_visitor_t& j) const json_with_visitor_t& j) {
{ std::stringstream str;
std::stringstream str; str << p.to_string() << " - ";
str << p.to_string() << " - " ; using value_t = nlohmann::detail::value_t;
using value_t = nlohmann::detail::value_t; switch (j.type())
switch (j.type()) {
{ case value_t::object:
case value_t::object: str << "object";
str << "object"; break;
break; case value_t::array:
case value_t::array: str << "array";
str << "array"; break;
break; case value_t::discarded:
case value_t::discarded: str << "discarded";
str << "discarded"; break;
break; case value_t::null:
case value_t::null: str << "null";
str << "null"; break;
break; case value_t::string:
case value_t::string: str << "string";
str << "string"; break;
break; case value_t::boolean:
case value_t::boolean: str << "boolean";
str << "boolean"; break;
break; case value_t::number_integer:
case value_t::number_integer: str << "number_integer";
str << "number_integer"; break;
break; case value_t::number_unsigned:
case value_t::number_unsigned: str << "number_unsigned";
str << "number_unsigned"; break;
break; case value_t::number_float:
case value_t::number_float: str << "number_float";
str << "number_float"; break;
break; case value_t::binary:
case value_t::binary: str << "binary";
str << "binary"; break;
break; default:
default: str << "error";
str << "error"; break;
break; }
} str << " - " << j.dump();
str << " - " << j.dump(); CHECK(json.at(p) == j);
CHECK(json.at(p) == j); INFO(str.str());
INFO(str.str()); CHECK(expected.count(str.str()) == 1);
CHECK(expected.count(str.str()) == 1); expected.erase(str.str());
expected.erase(str.str()); });
}
);
CHECK(expected.empty()); CHECK(expected.empty());
} }
+40 -115
View File
@@ -12,7 +12,7 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
#ifdef JSON_TEST_NO_GLOBAL_UDLS #ifdef JSON_TEST_NO_GLOBAL_UDLS
using namespace nlohmann::literals; // NOLINT(google-build-using-namespace) using namespace nlohmann::literals; // NOLINT(google-build-using-namespace)
#endif #endif
#include <iostream> #include <iostream>
@@ -20,8 +20,7 @@ using nlohmann::json;
#include <sstream> #include <sstream>
#include <valarray> #include <valarray>
namespace namespace {
{
struct SaxEventLogger : public nlohmann::json_sax<json> struct SaxEventLogger : public nlohmann::json_sax<json>
{ {
bool null() override bool null() override
@@ -125,7 +124,7 @@ struct SaxEventLogger : public nlohmann::json_sax<json>
return false; return false;
} }
std::vector<std::string> events {}; std::vector<std::string> events{};
}; };
struct SaxEventLoggerExitAfterStartObject : public SaxEventLogger struct SaxEventLoggerExitAfterStartObject : public SaxEventLogger
@@ -169,7 +168,7 @@ struct SaxEventLoggerExitAfterStartArray : public SaxEventLogger
} }
}; };
template <typename T> template<typename T>
class proxy_iterator class proxy_iterator
{ {
public: public:
@@ -182,7 +181,9 @@ class proxy_iterator
using iterator_category = std::input_iterator_tag; using iterator_category = std::input_iterator_tag;
proxy_iterator() = default; proxy_iterator() = default;
explicit proxy_iterator(iterator& it) : m_it(std::addressof(it)) {} explicit proxy_iterator(iterator& it)
: m_it(std::addressof(it))
{}
proxy_iterator& operator++() proxy_iterator& operator++()
{ {
@@ -214,7 +215,7 @@ class proxy_iterator
private: private:
iterator* m_it = nullptr; iterator* m_it = nullptr;
}; };
} // namespace } // namespace
TEST_CASE("deserialization") TEST_CASE("deserialization")
{ {
@@ -236,12 +237,7 @@ TEST_CASE("deserialization")
CHECK(json::sax_parse(ss3, &l)); CHECK(json::sax_parse(ss3, &l));
CHECK(l.events.size() == 11); CHECK(l.events.size() == 11);
CHECK(l.events == std::vector<std::string>( CHECK(l.events == std::vector<std::string>(
{ {"start_array()", "string(foo)", "number_unsigned(1)", "number_unsigned(2)", "number_unsigned(3)", "boolean(false)", "start_object()", "key(one)", "number_unsigned(1)", "end_object()", "end_array()"}));
"start_array()", "string(foo)", "number_unsigned(1)",
"number_unsigned(2)", "number_unsigned(3)", "boolean(false)",
"start_object()", "key(one)", "number_unsigned(1)",
"end_object()", "end_array()"
}));
} }
SECTION("string literal") SECTION("string literal")
@@ -255,12 +251,7 @@ TEST_CASE("deserialization")
CHECK(json::sax_parse(s, &l)); CHECK(json::sax_parse(s, &l));
CHECK(l.events.size() == 11); CHECK(l.events.size() == 11);
CHECK(l.events == std::vector<std::string>( CHECK(l.events == std::vector<std::string>(
{ {"start_array()", "string(foo)", "number_unsigned(1)", "number_unsigned(2)", "number_unsigned(3)", "boolean(false)", "start_object()", "key(one)", "number_unsigned(1)", "end_object()", "end_array()"}));
"start_array()", "string(foo)", "number_unsigned(1)",
"number_unsigned(2)", "number_unsigned(3)", "boolean(false)",
"start_object()", "key(one)", "number_unsigned(1)",
"end_object()", "end_array()"
}));
} }
SECTION("string_t") SECTION("string_t")
@@ -274,12 +265,7 @@ TEST_CASE("deserialization")
CHECK(json::sax_parse(s, &l)); CHECK(json::sax_parse(s, &l));
CHECK(l.events.size() == 11); CHECK(l.events.size() == 11);
CHECK(l.events == std::vector<std::string>( CHECK(l.events == std::vector<std::string>(
{ {"start_array()", "string(foo)", "number_unsigned(1)", "number_unsigned(2)", "number_unsigned(3)", "boolean(false)", "start_object()", "key(one)", "number_unsigned(1)", "end_object()", "end_array()"}));
"start_array()", "string(foo)", "number_unsigned(1)",
"number_unsigned(2)", "number_unsigned(3)", "boolean(false)",
"start_object()", "key(one)", "number_unsigned(1)",
"end_object()", "end_array()"
}));
} }
SECTION("operator<<") SECTION("operator<<")
@@ -331,12 +317,7 @@ TEST_CASE("deserialization")
CHECK(!json::sax_parse(ss5, &l)); CHECK(!json::sax_parse(ss5, &l));
CHECK(l.events.size() == 11); CHECK(l.events.size() == 11);
CHECK(l.events == std::vector<std::string>( CHECK(l.events == std::vector<std::string>(
{ {"start_array()", "string(foo)", "number_unsigned(1)", "number_unsigned(2)", "number_unsigned(3)", "boolean(false)", "start_object()", "key(one)", "number_unsigned(1)", "end_object()", "parse_error(29)"}));
"start_array()", "string(foo)", "number_unsigned(1)",
"number_unsigned(2)", "number_unsigned(3)", "boolean(false)",
"start_object()", "key(one)", "number_unsigned(1)",
"end_object()", "parse_error(29)"
}));
} }
SECTION("string") SECTION("string")
@@ -354,12 +335,7 @@ TEST_CASE("deserialization")
CHECK(!json::sax_parse(s, &l)); CHECK(!json::sax_parse(s, &l));
CHECK(l.events.size() == 11); CHECK(l.events.size() == 11);
CHECK(l.events == std::vector<std::string>( CHECK(l.events == std::vector<std::string>(
{ {"start_array()", "string(foo)", "number_unsigned(1)", "number_unsigned(2)", "number_unsigned(3)", "boolean(false)", "start_object()", "key(one)", "number_unsigned(1)", "end_object()", "parse_error(29)"}));
"start_array()", "string(foo)", "number_unsigned(1)",
"number_unsigned(2)", "number_unsigned(3)", "boolean(false)",
"start_object()", "key(one)", "number_unsigned(1)",
"end_object()", "parse_error(29)"
}));
} }
SECTION("operator<<") SECTION("operator<<")
@@ -402,7 +378,7 @@ TEST_CASE("deserialization")
SECTION("from std::array") SECTION("from std::array")
{ {
std::array<uint8_t, 5> const v { {'t', 'r', 'u', 'e'} }; std::array<uint8_t, 5> const v{{'t', 'r', 'u', 'e'}};
CHECK(json::parse(v) == json(true)); CHECK(json::parse(v) == json(true));
CHECK(json::accept(v)); CHECK(json::accept(v));
@@ -414,7 +390,7 @@ TEST_CASE("deserialization")
SECTION("from array") SECTION("from array")
{ {
uint8_t v[] = {'t', 'r', 'u', 'e'}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) uint8_t v[] = {'t', 'r', 'u', 'e'}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
CHECK(json::parse(v) == json(true)); CHECK(json::parse(v) == json(true));
CHECK(json::accept(v)); CHECK(json::accept(v));
@@ -426,7 +402,7 @@ TEST_CASE("deserialization")
SECTION("from chars") SECTION("from chars")
{ {
auto* v = new uint8_t[5]; // NOLINT(cppcoreguidelines-owning-memory) auto* v = new uint8_t[5]; // NOLINT(cppcoreguidelines-owning-memory)
v[0] = 't'; v[0] = 't';
v[1] = 'r'; v[1] = 'r';
v[2] = 'u'; v[2] = 'u';
@@ -440,7 +416,7 @@ TEST_CASE("deserialization")
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"boolean(true)"})); CHECK(l.events == std::vector<std::string>({"boolean(true)"}));
delete[] v; // NOLINT(cppcoreguidelines-owning-memory) delete[] v; // NOLINT(cppcoreguidelines-owning-memory)
} }
SECTION("from std::string") SECTION("from std::string")
@@ -493,12 +469,11 @@ TEST_CASE("deserialization")
CHECK(json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>({"boolean(true)"})); CHECK(l.events == std::vector<std::string>({"boolean(true)"}));
} }
SECTION("from std::array") SECTION("from std::array")
{ {
std::array<uint8_t, 5> v { {'t', 'r', 'u', 'e'} }; std::array<uint8_t, 5> v{{'t', 'r', 'u', 'e'}};
CHECK(json::parse(std::begin(v), std::end(v)) == json(true)); CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
CHECK(json::accept(std::begin(v), std::end(v))); CHECK(json::accept(std::begin(v), std::end(v)));
@@ -510,7 +485,7 @@ TEST_CASE("deserialization")
SECTION("from array") SECTION("from array")
{ {
uint8_t v[] = {'t', 'r', 'u', 'e'}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) uint8_t v[] = {'t', 'r', 'u', 'e'}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays)
CHECK(json::parse(std::begin(v), std::end(v)) == json(true)); CHECK(json::parse(std::begin(v), std::end(v)) == json(true));
CHECK(json::accept(std::begin(v), std::end(v))); CHECK(json::accept(std::begin(v), std::end(v)));
@@ -585,8 +560,7 @@ TEST_CASE("deserialization")
json j; json j;
json_sax_dom_parser<json> sax(j, true); json_sax_dom_parser<json> sax(j, true);
CHECK(json::sax_parse(proxy(first), proxy(last), &sax, CHECK(json::sax_parse(proxy(first), proxy(last), &sax, input_format_t::json, false));
input_format_t::json, false));
CHECK(j.dump() == str1); CHECK(j.dump() == str1);
CHECK(std::string(first, last) == str2); CHECK(std::string(first, last) == str2);
} }
@@ -865,10 +839,7 @@ TEST_CASE("deserialization")
CHECK(!json::sax_parse(std::begin(v), std::end(v), &l)); CHECK(!json::sax_parse(std::begin(v), std::end(v), &l));
CHECK(l.events.size() == 4); CHECK(l.events.size() == 4);
CHECK(l.events == std::vector<std::string>( CHECK(l.events == std::vector<std::string>(
{ {"start_object()", "key()", "number_unsigned(11)", "parse_error(7)"}));
"start_object()", "key()", "number_unsigned(11)",
"parse_error(7)"
}));
} }
} }
} }
@@ -888,9 +859,7 @@ TEST_CASE("deserialization")
CHECK(!json::sax_parse(bom, &l)); CHECK(!json::sax_parse(bom, &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>( CHECK(l.events == std::vector<std::string>(
{ {"parse_error(4)"}));
"parse_error(4)"
}));
} }
SECTION("BOM and content") SECTION("BOM and content")
@@ -904,14 +873,10 @@ TEST_CASE("deserialization")
CHECK(json::sax_parse(bom + "1", &l2)); CHECK(json::sax_parse(bom + "1", &l2));
CHECK(l1.events.size() == 1); CHECK(l1.events.size() == 1);
CHECK(l1.events == std::vector<std::string>( CHECK(l1.events == std::vector<std::string>(
{ {"number_unsigned(1)"}));
"number_unsigned(1)"
}));
CHECK(l2.events.size() == 1); CHECK(l2.events.size() == 1);
CHECK(l2.events == std::vector<std::string>( CHECK(l2.events == std::vector<std::string>(
{ {"number_unsigned(1)"}));
"number_unsigned(1)"
}));
} }
SECTION("2 byte of BOM") SECTION("2 byte of BOM")
@@ -927,14 +892,10 @@ TEST_CASE("deserialization")
CHECK(!json::sax_parse(bom.substr(0, 2), &l2)); CHECK(!json::sax_parse(bom.substr(0, 2), &l2));
CHECK(l1.events.size() == 1); CHECK(l1.events.size() == 1);
CHECK(l1.events == std::vector<std::string>( CHECK(l1.events == std::vector<std::string>(
{ {"parse_error(3)"}));
"parse_error(3)"
}));
CHECK(l2.events.size() == 1); CHECK(l2.events.size() == 1);
CHECK(l2.events == std::vector<std::string>( CHECK(l2.events == std::vector<std::string>(
{ {"parse_error(3)"}));
"parse_error(3)"
}));
} }
SECTION("1 byte of BOM") SECTION("1 byte of BOM")
@@ -950,14 +911,10 @@ TEST_CASE("deserialization")
CHECK(!json::sax_parse(bom.substr(0, 1), &l2)); CHECK(!json::sax_parse(bom.substr(0, 1), &l2));
CHECK(l1.events.size() == 1); CHECK(l1.events.size() == 1);
CHECK(l1.events == std::vector<std::string>( CHECK(l1.events == std::vector<std::string>(
{ {"parse_error(2)"}));
"parse_error(2)"
}));
CHECK(l2.events.size() == 1); CHECK(l2.events.size() == 1);
CHECK(l2.events == std::vector<std::string>( CHECK(l2.events == std::vector<std::string>(
{ {"parse_error(2)"}));
"parse_error(2)"
}));
} }
SECTION("variations") SECTION("variations")
@@ -990,9 +947,7 @@ TEST_CASE("deserialization")
CHECK(json::sax_parse(s + "null", &l)); CHECK(json::sax_parse(s + "null", &l));
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
CHECK(l.events == std::vector<std::string>( CHECK(l.events == std::vector<std::string>(
{ {"null()"}));
"null()"
}));
} }
else else
{ {
@@ -1008,23 +963,17 @@ TEST_CASE("deserialization")
if (i0 != 0) if (i0 != 0)
{ {
CHECK(l.events == std::vector<std::string>( CHECK(l.events == std::vector<std::string>(
{ {"parse_error(1)"}));
"parse_error(1)"
}));
} }
else if (i1 != 0) else if (i1 != 0)
{ {
CHECK(l.events == std::vector<std::string>( CHECK(l.events == std::vector<std::string>(
{ {"parse_error(2)"}));
"parse_error(2)"
}));
} }
else else
{ {
CHECK(l.events == std::vector<std::string>( CHECK(l.events == std::vector<std::string>(
{ {"parse_error(3)"}));
"parse_error(3)"
}));
} }
} }
} }
@@ -1055,37 +1004,22 @@ TEST_CASE("deserialization")
json::sax_parse(s, &default_logger); json::sax_parse(s, &default_logger);
CHECK(default_logger.events.size() == 14); CHECK(default_logger.events.size() == 14);
CHECK(default_logger.events == std::vector<std::string>( CHECK(default_logger.events == std::vector<std::string>(
{ {"start_array()", "number_unsigned(1)", "start_array()", "string(string)", "number_float(43.12)", "end_array()", "null()", "start_object()", "key(key1)", "boolean(true)", "key(key2)", "boolean(false)", "end_object()", "end_array()"}));
"start_array()", "number_unsigned(1)", "start_array()",
"string(string)", "number_float(43.12)", "end_array()", "null()",
"start_object()", "key(key1)", "boolean(true)", "key(key2)",
"boolean(false)", "end_object()", "end_array()"
}));
json::sax_parse(s, &exit_after_start_object); json::sax_parse(s, &exit_after_start_object);
CHECK(exit_after_start_object.events.size() == 8); CHECK(exit_after_start_object.events.size() == 8);
CHECK(exit_after_start_object.events == std::vector<std::string>( CHECK(exit_after_start_object.events == std::vector<std::string>(
{ {"start_array()", "number_unsigned(1)", "start_array()", "string(string)", "number_float(43.12)", "end_array()", "null()", "start_object()"}));
"start_array()", "number_unsigned(1)", "start_array()",
"string(string)", "number_float(43.12)", "end_array()", "null()",
"start_object()"
}));
json::sax_parse(s, &exit_after_key); json::sax_parse(s, &exit_after_key);
CHECK(exit_after_key.events.size() == 9); CHECK(exit_after_key.events.size() == 9);
CHECK(exit_after_key.events == std::vector<std::string>( CHECK(exit_after_key.events == std::vector<std::string>(
{ {"start_array()", "number_unsigned(1)", "start_array()", "string(string)", "number_float(43.12)", "end_array()", "null()", "start_object()", "key(key1)"}));
"start_array()", "number_unsigned(1)", "start_array()",
"string(string)", "number_float(43.12)", "end_array()", "null()",
"start_object()", "key(key1)"
}));
json::sax_parse(s, &exit_after_start_array); json::sax_parse(s, &exit_after_start_array);
CHECK(exit_after_start_array.events.size() == 1); CHECK(exit_after_start_array.events.size() == 1);
CHECK(exit_after_start_array.events == std::vector<std::string>( CHECK(exit_after_start_array.events == std::vector<std::string>(
{ {"start_array()"}));
"start_array()"
}));
} }
SECTION("JSON Lines") SECTION("JSON Lines")
@@ -1131,13 +1065,7 @@ TEST_CASE("deserialization")
} }
} }
TEST_CASE_TEMPLATE("deserialization of different character types (ASCII)", T, TEST_CASE_TEMPLATE("deserialization of different character types (ASCII)", T, char, unsigned char, signed char, wchar_t, char16_t, char32_t, std::uint8_t, std::int8_t, std::int16_t, std::uint16_t, std::int32_t, std::uint32_t)
char, unsigned char, signed char,
wchar_t,
char16_t, char32_t,
std::uint8_t, std::int8_t,
std::int16_t, std::uint16_t,
std::int32_t, std::uint32_t)
{ {
std::vector<T> const v = {'t', 'r', 'u', 'e'}; std::vector<T> const v = {'t', 'r', 'u', 'e'};
CHECK(json::parse(v) == json(true)); CHECK(json::parse(v) == json(true));
@@ -1149,8 +1077,7 @@ TEST_CASE_TEMPLATE("deserialization of different character types (ASCII)", T,
CHECK(l.events == std::vector<std::string>({"boolean(true)"})); CHECK(l.events == std::vector<std::string>({"boolean(true)"}));
} }
TEST_CASE_TEMPLATE("deserialization of different character types (UTF-8)", T, TEST_CASE_TEMPLATE("deserialization of different character types (UTF-8)", T, char, unsigned char, std::uint8_t)
char, unsigned char, std::uint8_t)
{ {
// a star emoji // a star emoji
std::vector<T> const v = {'"', static_cast<T>(0xe2u), static_cast<T>(0xadu), static_cast<T>(0x90u), static_cast<T>(0xefu), static_cast<T>(0xb8u), static_cast<T>(0x8fu), '"'}; std::vector<T> const v = {'"', static_cast<T>(0xe2u), static_cast<T>(0xadu), static_cast<T>(0x90u), static_cast<T>(0xefu), static_cast<T>(0xb8u), static_cast<T>(0x8fu), '"'};
@@ -1162,8 +1089,7 @@ TEST_CASE_TEMPLATE("deserialization of different character types (UTF-8)", T,
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
} }
TEST_CASE_TEMPLATE("deserialization of different character types (UTF-16)", T, TEST_CASE_TEMPLATE("deserialization of different character types (UTF-16)", T, char16_t, std::uint16_t)
char16_t, std::uint16_t)
{ {
// a star emoji // a star emoji
std::vector<T> const v = {static_cast<T>('"'), static_cast<T>(0x2b50), static_cast<T>(0xfe0f), static_cast<T>('"')}; std::vector<T> const v = {static_cast<T>('"'), static_cast<T>(0x2b50), static_cast<T>(0xfe0f), static_cast<T>('"')};
@@ -1175,8 +1101,7 @@ TEST_CASE_TEMPLATE("deserialization of different character types (UTF-16)", T,
CHECK(l.events.size() == 1); CHECK(l.events.size() == 1);
} }
TEST_CASE_TEMPLATE("deserialization of different character types (UTF-32)", T, TEST_CASE_TEMPLATE("deserialization of different character types (UTF-32)", T, char32_t, std::uint32_t)
char32_t, std::uint32_t)
{ {
// a star emoji // a star emoji
std::vector<T> const v = {static_cast<T>('"'), static_cast<T>(0x2b50), static_cast<T>(0xfe0f), static_cast<T>('"')}; std::vector<T> const v = {static_cast<T>('"'), static_cast<T>(0x2b50), static_cast<T>(0xfe0f), static_cast<T>('"')};
+6 -4
View File
@@ -23,11 +23,13 @@ using json = nlohmann::json;
class sax_no_exception : public nlohmann::detail::json_sax_dom_parser<json> class sax_no_exception : public nlohmann::detail::json_sax_dom_parser<json>
{ {
public: public:
explicit sax_no_exception(json& j) : nlohmann::detail::json_sax_dom_parser<json>(j, false) {} explicit sax_no_exception(json& j)
: nlohmann::detail::json_sax_dom_parser<json>(j, false)
{}
static bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex) static bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex)
{ {
error_string = new std::string(ex.what()); // NOLINT(cppcoreguidelines-owning-memory) error_string = new std::string(ex.what()); // NOLINT(cppcoreguidelines-owning-memory)
return false; return false;
} }
@@ -43,9 +45,9 @@ TEST_CASE("Tests with disabled exceptions")
json j; json j;
sax_no_exception sax(j); sax_no_exception sax(j);
CHECK (!json::sax_parse("xyz", &sax)); CHECK(!json::sax_parse("xyz", &sax));
CHECK(*sax_no_exception::error_string == "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'x'"); CHECK(*sax_no_exception::error_string == "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'x'");
delete sax_no_exception::error_string; // NOLINT(cppcoreguidelines-owning-memory) delete sax_no_exception::error_string; // NOLINT(cppcoreguidelines-owning-memory)
} }
} }
+22 -11
View File
@@ -45,9 +45,11 @@ TEST_CASE("element access 1")
SECTION("access outside bounds") SECTION("access outside bounds")
{ {
CHECK_THROWS_WITH_AS(j.at(8), CHECK_THROWS_WITH_AS(j.at(8),
"[json.exception.out_of_range.401] array index 8 is out of range", json::out_of_range&); "[json.exception.out_of_range.401] array index 8 is out of range",
json::out_of_range&);
CHECK_THROWS_WITH_AS(j_const.at(8), CHECK_THROWS_WITH_AS(j_const.at(8),
"[json.exception.out_of_range.401] array index 8 is out of range", json::out_of_range&); "[json.exception.out_of_range.401] array index 8 is out of range",
json::out_of_range&);
} }
SECTION("access on non-array type") SECTION("access on non-array type")
@@ -359,26 +361,34 @@ TEST_CASE("element access 1")
json jarray2 = {"foo", "bar"}; json jarray2 = {"foo", "bar"};
CHECK_THROWS_WITH_AS(jarray.erase(jarray2.begin()), CHECK_THROWS_WITH_AS(jarray.erase(jarray2.begin()),
"[json.exception.invalid_iterator.202] iterator does not fit current value", json::invalid_iterator&); "[json.exception.invalid_iterator.202] iterator does not fit current value",
json::invalid_iterator&);
CHECK_THROWS_WITH_AS(jarray.erase(jarray.begin(), jarray2.end()), CHECK_THROWS_WITH_AS(jarray.erase(jarray.begin(), jarray2.end()),
"[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&); "[json.exception.invalid_iterator.203] iterators do not fit current value",
json::invalid_iterator&);
CHECK_THROWS_WITH_AS(jarray.erase(jarray2.begin(), jarray.end()), CHECK_THROWS_WITH_AS(jarray.erase(jarray2.begin(), jarray.end()),
"[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&); "[json.exception.invalid_iterator.203] iterators do not fit current value",
json::invalid_iterator&);
CHECK_THROWS_WITH_AS(jarray.erase(jarray2.begin(), jarray2.end()), CHECK_THROWS_WITH_AS(jarray.erase(jarray2.begin(), jarray2.end()),
"[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&); "[json.exception.invalid_iterator.203] iterators do not fit current value",
json::invalid_iterator&);
} }
{ {
json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}}; json jarray = {1, 1u, true, nullptr, "string", 42.23, json::object(), {1, 2, 3}};
json const jarray2 = {"foo", "bar"}; json const jarray2 = {"foo", "bar"};
CHECK_THROWS_WITH_AS(jarray.erase(jarray2.cbegin()), CHECK_THROWS_WITH_AS(jarray.erase(jarray2.cbegin()),
"[json.exception.invalid_iterator.202] iterator does not fit current value", json::invalid_iterator&); "[json.exception.invalid_iterator.202] iterator does not fit current value",
json::invalid_iterator&);
CHECK_THROWS_WITH_AS(jarray.erase(jarray.cbegin(), jarray2.cend()), CHECK_THROWS_WITH_AS(jarray.erase(jarray.cbegin(), jarray2.cend()),
"[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&); "[json.exception.invalid_iterator.203] iterators do not fit current value",
json::invalid_iterator&);
CHECK_THROWS_WITH_AS(jarray.erase(jarray2.cbegin(), jarray.cend()), CHECK_THROWS_WITH_AS(jarray.erase(jarray2.cbegin(), jarray.cend()),
"[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&); "[json.exception.invalid_iterator.203] iterators do not fit current value",
json::invalid_iterator&);
CHECK_THROWS_WITH_AS(jarray.erase(jarray2.cbegin(), jarray2.cend()), CHECK_THROWS_WITH_AS(jarray.erase(jarray2.cbegin(), jarray2.cend()),
"[json.exception.invalid_iterator.203] iterators do not fit current value", json::invalid_iterator&); "[json.exception.invalid_iterator.203] iterators do not fit current value",
json::invalid_iterator&);
} }
} }
} }
@@ -530,7 +540,8 @@ TEST_CASE("element access 1")
{ {
json j; json j;
CHECK_THROWS_WITH_AS(j.erase(j.begin()), CHECK_THROWS_WITH_AS(j.erase(j.begin()),
"[json.exception.type_error.307] cannot use erase() with null", json::type_error&); "[json.exception.type_error.307] cannot use erase() with null",
json::type_error&);
} }
} }
File diff suppressed because it is too large. Load diff
+42 -42
View File
@@ -23,42 +23,42 @@ TEST_CASE("hash<nlohmann::json>")
std::set<std::size_t> hashes; std::set<std::size_t> hashes;
// null // null
hashes.insert(std::hash<json> {}(json(nullptr))); hashes.insert(std::hash<json>{}(json(nullptr)));
// boolean // boolean
hashes.insert(std::hash<json> {}(json(true))); hashes.insert(std::hash<json>{}(json(true)));
hashes.insert(std::hash<json> {}(json(false))); hashes.insert(std::hash<json>{}(json(false)));
// string // string
hashes.insert(std::hash<json> {}(json(""))); hashes.insert(std::hash<json>{}(json("")));
hashes.insert(std::hash<json> {}(json("foo"))); hashes.insert(std::hash<json>{}(json("foo")));
// number // number
hashes.insert(std::hash<json> {}(json(0))); hashes.insert(std::hash<json>{}(json(0)));
hashes.insert(std::hash<json> {}(json(static_cast<unsigned>(0)))); hashes.insert(std::hash<json>{}(json(static_cast<unsigned>(0))));
hashes.insert(std::hash<json> {}(json(-1))); hashes.insert(std::hash<json>{}(json(-1)));
hashes.insert(std::hash<json> {}(json(0.0))); hashes.insert(std::hash<json>{}(json(0.0)));
hashes.insert(std::hash<json> {}(json(42.23))); hashes.insert(std::hash<json>{}(json(42.23)));
// array // array
hashes.insert(std::hash<json> {}(json::array())); hashes.insert(std::hash<json>{}(json::array()));
hashes.insert(std::hash<json> {}(json::array({1, 2, 3}))); hashes.insert(std::hash<json>{}(json::array({1, 2, 3})));
// object // object
hashes.insert(std::hash<json> {}(json::object())); hashes.insert(std::hash<json>{}(json::object()));
hashes.insert(std::hash<json> {}(json::object({{"foo", "bar"}}))); hashes.insert(std::hash<json>{}(json::object({{"foo", "bar"}})));
// binary // binary
hashes.insert(std::hash<json> {}(json::binary({}))); hashes.insert(std::hash<json>{}(json::binary({})));
hashes.insert(std::hash<json> {}(json::binary({}, 0))); hashes.insert(std::hash<json>{}(json::binary({}, 0)));
hashes.insert(std::hash<json> {}(json::binary({}, 42))); hashes.insert(std::hash<json>{}(json::binary({}, 42)));
hashes.insert(std::hash<json> {}(json::binary({1, 2, 3}))); hashes.insert(std::hash<json>{}(json::binary({1, 2, 3})));
hashes.insert(std::hash<json> {}(json::binary({1, 2, 3}, 0))); hashes.insert(std::hash<json>{}(json::binary({1, 2, 3}, 0)));
hashes.insert(std::hash<json> {}(json::binary({1, 2, 3}, 42))); hashes.insert(std::hash<json>{}(json::binary({1, 2, 3}, 42)));
// discarded // discarded
hashes.insert(std::hash<json> {}(json(json::value_t::discarded))); hashes.insert(std::hash<json>{}(json(json::value_t::discarded)));
CHECK(hashes.size() == 21); CHECK(hashes.size() == 21);
} }
@@ -72,42 +72,42 @@ TEST_CASE("hash<nlohmann::ordered_json>")
std::set<std::size_t> hashes; std::set<std::size_t> hashes;
// null // null
hashes.insert(std::hash<ordered_json> {}(ordered_json(nullptr))); hashes.insert(std::hash<ordered_json>{}(ordered_json(nullptr)));
// boolean // boolean
hashes.insert(std::hash<ordered_json> {}(ordered_json(true))); hashes.insert(std::hash<ordered_json>{}(ordered_json(true)));
hashes.insert(std::hash<ordered_json> {}(ordered_json(false))); hashes.insert(std::hash<ordered_json>{}(ordered_json(false)));
// string // string
hashes.insert(std::hash<ordered_json> {}(ordered_json(""))); hashes.insert(std::hash<ordered_json>{}(ordered_json("")));
hashes.insert(std::hash<ordered_json> {}(ordered_json("foo"))); hashes.insert(std::hash<ordered_json>{}(ordered_json("foo")));
// number // number
hashes.insert(std::hash<ordered_json> {}(ordered_json(0))); hashes.insert(std::hash<ordered_json>{}(ordered_json(0)));
hashes.insert(std::hash<ordered_json> {}(ordered_json(static_cast<unsigned>(0)))); hashes.insert(std::hash<ordered_json>{}(ordered_json(static_cast<unsigned>(0))));
hashes.insert(std::hash<ordered_json> {}(ordered_json(-1))); hashes.insert(std::hash<ordered_json>{}(ordered_json(-1)));
hashes.insert(std::hash<ordered_json> {}(ordered_json(0.0))); hashes.insert(std::hash<ordered_json>{}(ordered_json(0.0)));
hashes.insert(std::hash<ordered_json> {}(ordered_json(42.23))); hashes.insert(std::hash<ordered_json>{}(ordered_json(42.23)));
// array // array
hashes.insert(std::hash<ordered_json> {}(ordered_json::array())); hashes.insert(std::hash<ordered_json>{}(ordered_json::array()));
hashes.insert(std::hash<ordered_json> {}(ordered_json::array({1, 2, 3}))); hashes.insert(std::hash<ordered_json>{}(ordered_json::array({1, 2, 3})));
// object // object
hashes.insert(std::hash<ordered_json> {}(ordered_json::object())); hashes.insert(std::hash<ordered_json>{}(ordered_json::object()));
hashes.insert(std::hash<ordered_json> {}(ordered_json::object({{"foo", "bar"}}))); hashes.insert(std::hash<ordered_json>{}(ordered_json::object({{"foo", "bar"}})));
// binary // binary
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({}))); hashes.insert(std::hash<ordered_json>{}(ordered_json::binary({})));
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({}, 0))); hashes.insert(std::hash<ordered_json>{}(ordered_json::binary({}, 0)));
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({}, 42))); hashes.insert(std::hash<ordered_json>{}(ordered_json::binary({}, 42)));
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({1, 2, 3}))); hashes.insert(std::hash<ordered_json>{}(ordered_json::binary({1, 2, 3})));
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({1, 2, 3}, 0))); hashes.insert(std::hash<ordered_json>{}(ordered_json::binary({1, 2, 3}, 0)));
hashes.insert(std::hash<ordered_json> {}(ordered_json::binary({1, 2, 3}, 42))); hashes.insert(std::hash<ordered_json>{}(ordered_json::binary({1, 2, 3}, 42)));
// discarded // discarded
hashes.insert(std::hash<ordered_json> {}(ordered_json(ordered_json::value_t::discarded))); hashes.insert(std::hash<ordered_json>{}(ordered_json(ordered_json::value_t::discarded)));
CHECK(hashes.size() == 21); CHECK(hashes.size() == 21);
} }
+5 -6
View File
@@ -11,9 +11,9 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
#include "make_test_data_available.hpp"
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include "make_test_data_available.hpp"
TEST_CASE("object inspection") TEST_CASE("object inspection")
{ {
@@ -21,7 +21,7 @@ TEST_CASE("object inspection")
{ {
SECTION("object") SECTION("object")
{ {
json const j {{"foo", 1}, {"bar", false}}; json const j{{"foo", 1}, {"bar", false}};
CHECK(!j.is_null()); CHECK(!j.is_null());
CHECK(!j.is_boolean()); CHECK(!j.is_boolean());
CHECK(!j.is_number()); CHECK(!j.is_number());
@@ -39,7 +39,7 @@ TEST_CASE("object inspection")
SECTION("array") SECTION("array")
{ {
json const j {"foo", 1, 1u, 42.23, false}; json const j{"foo", 1, 1u, 42.23, false};
CHECK(!j.is_null()); CHECK(!j.is_null());
CHECK(!j.is_boolean()); CHECK(!j.is_boolean());
CHECK(!j.is_number()); CHECK(!j.is_number());
@@ -202,7 +202,7 @@ TEST_CASE("object inspection")
SECTION("serialization") SECTION("serialization")
{ {
json const j {{"object", json::object()}, {"array", {1, 2, 3, 4}}, {"number", 42}, {"boolean", false}, {"null", nullptr}, {"string", "Hello world"} }; json const j{{"object", json::object()}, {"array", {1, 2, 3, 4}}, {"number", 42}, {"boolean", false}, {"null", nullptr}, {"string", "Hello world"}};
SECTION("no indent / indent=-1") SECTION("no indent / indent=-1")
{ {
@@ -329,8 +329,7 @@ TEST_CASE("object inspection")
SECTION("round trips") SECTION("round trips")
{ {
for (const auto& s : for (const auto& s :
{"3.141592653589793", "1000000000000000010E5" {"3.141592653589793", "1000000000000000010E5"})
})
{ {
json const j1 = json::parse(s); json const j1 = json::parse(s);
std::string s1 = j1.dump(); std::string s1 = j1.dump();
+668 -670
View File
File diff suppressed because it is too large. Load diff
+80 -84
View File
@@ -59,14 +59,14 @@ TEST_CASE("iterators 2")
// comparison: not equal // comparison: not equal
{ {
// check definition // check definition
CHECK( (it1 != it1) == !(it1 == it1) ); CHECK((it1 != it1) == !(it1 == it1));
CHECK( (it1 != it2) == !(it1 == it2) ); CHECK((it1 != it2) == !(it1 == it2));
CHECK( (it1 != it3) == !(it1 == it3) ); CHECK((it1 != it3) == !(it1 == it3));
CHECK( (it2 != it3) == !(it2 == it3) ); CHECK((it2 != it3) == !(it2 == it3));
CHECK( (it1_c != it1_c) == !(it1_c == it1_c) ); CHECK((it1_c != it1_c) == !(it1_c == it1_c));
CHECK( (it1_c != it2_c) == !(it1_c == it2_c) ); CHECK((it1_c != it2_c) == !(it1_c == it2_c));
CHECK( (it1_c != it3_c) == !(it1_c == it3_c) ); CHECK((it1_c != it3_c) == !(it1_c == it3_c));
CHECK( (it2_c != it3_c) == !(it2_c == it3_c) ); CHECK((it2_c != it3_c) == !(it2_c == it3_c));
} }
// comparison: smaller // comparison: smaller
@@ -133,14 +133,14 @@ TEST_CASE("iterators 2")
else else
{ {
// check definition // check definition
CHECK( (it1 <= it1) == !(it1 < it1) ); CHECK((it1 <= it1) == !(it1 < it1));
CHECK( (it1 <= it2) == !(it2 < it1) ); CHECK((it1 <= it2) == !(it2 < it1));
CHECK( (it1 <= it3) == !(it3 < it1) ); CHECK((it1 <= it3) == !(it3 < it1));
CHECK( (it2 <= it3) == !(it3 < it2) ); CHECK((it2 <= it3) == !(it3 < it2));
CHECK( (it1_c <= it1_c) == !(it1_c < it1_c) ); CHECK((it1_c <= it1_c) == !(it1_c < it1_c));
CHECK( (it1_c <= it2_c) == !(it2_c < it1_c) ); CHECK((it1_c <= it2_c) == !(it2_c < it1_c));
CHECK( (it1_c <= it3_c) == !(it3_c < it1_c) ); CHECK((it1_c <= it3_c) == !(it3_c < it1_c));
CHECK( (it2_c <= it3_c) == !(it3_c < it2_c) ); CHECK((it2_c <= it3_c) == !(it3_c < it2_c));
} }
} }
@@ -171,14 +171,14 @@ TEST_CASE("iterators 2")
else else
{ {
// check definition // check definition
CHECK( (it1 > it1) == (it1 < it1) ); CHECK((it1 > it1) == (it1 < it1));
CHECK( (it1 > it2) == (it2 < it1) ); CHECK((it1 > it2) == (it2 < it1));
CHECK( (it1 > it3) == (it3 < it1) ); CHECK((it1 > it3) == (it3 < it1));
CHECK( (it2 > it3) == (it3 < it2) ); CHECK((it2 > it3) == (it3 < it2));
CHECK( (it1_c > it1_c) == (it1_c < it1_c) ); CHECK((it1_c > it1_c) == (it1_c < it1_c));
CHECK( (it1_c > it2_c) == (it2_c < it1_c) ); CHECK((it1_c > it2_c) == (it2_c < it1_c));
CHECK( (it1_c > it3_c) == (it3_c < it1_c) ); CHECK((it1_c > it3_c) == (it3_c < it1_c));
CHECK( (it2_c > it3_c) == (it3_c < it2_c) ); CHECK((it2_c > it3_c) == (it3_c < it2_c));
} }
} }
@@ -209,14 +209,14 @@ TEST_CASE("iterators 2")
else else
{ {
// check definition // check definition
CHECK( (it1 >= it1) == !(it1 < it1) ); CHECK((it1 >= it1) == !(it1 < it1));
CHECK( (it1 >= it2) == !(it1 < it2) ); CHECK((it1 >= it2) == !(it1 < it2));
CHECK( (it1 >= it3) == !(it1 < it3) ); CHECK((it1 >= it3) == !(it1 < it3));
CHECK( (it2 >= it3) == !(it2 < it3) ); CHECK((it2 >= it3) == !(it2 < it3));
CHECK( (it1_c >= it1_c) == !(it1_c < it1_c) ); CHECK((it1_c >= it1_c) == !(it1_c < it1_c));
CHECK( (it1_c >= it2_c) == !(it1_c < it2_c) ); CHECK((it1_c >= it2_c) == !(it1_c < it2_c));
CHECK( (it1_c >= it3_c) == !(it1_c < it3_c) ); CHECK((it1_c >= it3_c) == !(it1_c < it3_c));
CHECK( (it2_c >= it3_c) == !(it2_c < it3_c) ); CHECK((it2_c >= it3_c) == !(it2_c < it3_c));
} }
} }
} }
@@ -483,14 +483,14 @@ TEST_CASE("iterators 2")
// comparison: not equal // comparison: not equal
{ {
// check definition // check definition
CHECK( (it1 != it1) == !(it1 == it1) ); CHECK((it1 != it1) == !(it1 == it1));
CHECK( (it1 != it2) == !(it1 == it2) ); CHECK((it1 != it2) == !(it1 == it2));
CHECK( (it1 != it3) == !(it1 == it3) ); CHECK((it1 != it3) == !(it1 == it3));
CHECK( (it2 != it3) == !(it2 == it3) ); CHECK((it2 != it3) == !(it2 == it3));
CHECK( (it1_c != it1_c) == !(it1_c == it1_c) ); CHECK((it1_c != it1_c) == !(it1_c == it1_c));
CHECK( (it1_c != it2_c) == !(it1_c == it2_c) ); CHECK((it1_c != it2_c) == !(it1_c == it2_c));
CHECK( (it1_c != it3_c) == !(it1_c == it3_c) ); CHECK((it1_c != it3_c) == !(it1_c == it3_c));
CHECK( (it2_c != it3_c) == !(it2_c == it3_c) ); CHECK((it2_c != it3_c) == !(it2_c == it3_c));
} }
// comparison: smaller // comparison: smaller
@@ -557,14 +557,14 @@ TEST_CASE("iterators 2")
else else
{ {
// check definition // check definition
CHECK( (it1 <= it1) == !(it1 < it1) ); CHECK((it1 <= it1) == !(it1 < it1));
CHECK( (it1 <= it2) == !(it2 < it1) ); CHECK((it1 <= it2) == !(it2 < it1));
CHECK( (it1 <= it3) == !(it3 < it1) ); CHECK((it1 <= it3) == !(it3 < it1));
CHECK( (it2 <= it3) == !(it3 < it2) ); CHECK((it2 <= it3) == !(it3 < it2));
CHECK( (it1_c <= it1_c) == !(it1_c < it1_c) ); CHECK((it1_c <= it1_c) == !(it1_c < it1_c));
CHECK( (it1_c <= it2_c) == !(it2_c < it1_c) ); CHECK((it1_c <= it2_c) == !(it2_c < it1_c));
CHECK( (it1_c <= it3_c) == !(it3_c < it1_c) ); CHECK((it1_c <= it3_c) == !(it3_c < it1_c));
CHECK( (it2_c <= it3_c) == !(it3_c < it2_c) ); CHECK((it2_c <= it3_c) == !(it3_c < it2_c));
} }
} }
@@ -595,14 +595,14 @@ TEST_CASE("iterators 2")
else else
{ {
// check definition // check definition
CHECK( (it1 > it1) == (it1 < it1) ); CHECK((it1 > it1) == (it1 < it1));
CHECK( (it1 > it2) == (it2 < it1) ); CHECK((it1 > it2) == (it2 < it1));
CHECK( (it1 > it3) == (it3 < it1) ); CHECK((it1 > it3) == (it3 < it1));
CHECK( (it2 > it3) == (it3 < it2) ); CHECK((it2 > it3) == (it3 < it2));
CHECK( (it1_c > it1_c) == (it1_c < it1_c) ); CHECK((it1_c > it1_c) == (it1_c < it1_c));
CHECK( (it1_c > it2_c) == (it2_c < it1_c) ); CHECK((it1_c > it2_c) == (it2_c < it1_c));
CHECK( (it1_c > it3_c) == (it3_c < it1_c) ); CHECK((it1_c > it3_c) == (it3_c < it1_c));
CHECK( (it2_c > it3_c) == (it3_c < it2_c) ); CHECK((it2_c > it3_c) == (it3_c < it2_c));
} }
} }
@@ -633,14 +633,14 @@ TEST_CASE("iterators 2")
else else
{ {
// check definition // check definition
CHECK( (it1 >= it1) == !(it1 < it1) ); CHECK((it1 >= it1) == !(it1 < it1));
CHECK( (it1 >= it2) == !(it1 < it2) ); CHECK((it1 >= it2) == !(it1 < it2));
CHECK( (it1 >= it3) == !(it1 < it3) ); CHECK((it1 >= it3) == !(it1 < it3));
CHECK( (it2 >= it3) == !(it2 < it3) ); CHECK((it2 >= it3) == !(it2 < it3));
CHECK( (it1_c >= it1_c) == !(it1_c < it1_c) ); CHECK((it1_c >= it1_c) == !(it1_c < it1_c));
CHECK( (it1_c >= it2_c) == !(it1_c < it2_c) ); CHECK((it1_c >= it2_c) == !(it1_c < it2_c));
CHECK( (it1_c >= it3_c) == !(it1_c < it3_c) ); CHECK((it1_c >= it3_c) == !(it1_c < it3_c));
CHECK( (it2_c >= it3_c) == !(it2_c < it3_c) ); CHECK((it2_c >= it3_c) == !(it2_c < it3_c));
} }
} }
} }
@@ -894,7 +894,7 @@ TEST_CASE("iterators 2")
} }
// libstdc++ algorithms don't work with Clang 15 (04/2022) // libstdc++ algorithms don't work with Clang 15 (04/2022)
#if !DOCTEST_CLANG || (DOCTEST_CLANG && defined(__GLIBCXX__)) #if !DOCTEST_CLANG || (DOCTEST_CLANG && defined(__GLIBCXX__))
SECTION("algorithms") SECTION("algorithms")
{ {
SECTION("copy") SECTION("copy")
@@ -912,28 +912,26 @@ TEST_CASE("iterators 2")
json j{1, 3, 2, 4}; json j{1, 3, 2, 4};
auto j_even = json::array(); auto j_even = json::array();
#if JSON_USE_IMPLICIT_CONVERSIONS #if JSON_USE_IMPLICIT_CONVERSIONS
auto it = std::ranges::find_if(j, [](int v) noexcept auto it = std::ranges::find_if(j, [](int v) noexcept {
{
return (v % 2) == 0; return (v % 2) == 0;
}); });
#else #else
auto it = std::ranges::find_if(j, [](const json & j) noexcept auto it = std::ranges::find_if(j, [](const json& j) noexcept {
{
int v; int v;
j.get_to(v); j.get_to(v);
return (v % 2) == 0; return (v % 2) == 0;
}); });
#endif #endif
CHECK(*it == 2); CHECK(*it == 2);
} }
} }
#endif #endif
// libstdc++ views don't work with Clang 15 (04/2022) // libstdc++ views don't work with Clang 15 (04/2022)
// libc++ hides limited ranges implementation behind guard macro // libc++ hides limited ranges implementation behind guard macro
#if !(DOCTEST_CLANG && (defined(__GLIBCXX__) || defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES))) #if !(DOCTEST_CLANG && (defined(__GLIBCXX__) || defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)))
SECTION("views") SECTION("views")
{ {
SECTION("reverse") SECTION("reverse")
@@ -947,25 +945,23 @@ TEST_CASE("iterators 2")
SECTION("transform") SECTION("transform")
{ {
json j json j{
{ {"a_key", "a_value"},
{ "a_key", "a_value"}, {"b_key", "b_value"},
{ "b_key", "b_value"}, {"c_key", "c_value"},
{ "c_key", "c_value"},
}; };
json j_expected{"a_key", "b_key", "c_key"}; json j_expected{"a_key", "b_key", "c_key"};
auto transformed = j.items() | std::views::transform([](const auto & item) auto transformed = j.items() | std::views::transform([](const auto& item) {
{ return item.key();
return item.key(); });
});
auto j_transformed = json::array(); auto j_transformed = json::array();
std::ranges::copy(transformed, std::back_inserter(j_transformed)); std::ranges::copy(transformed, std::back_inserter(j_transformed));
CHECK(j_transformed == j_expected); CHECK(j_transformed == j_expected);
} }
} }
#endif #endif
} }
#endif #endif
} }
+18 -30
View File
@@ -11,11 +11,11 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
#ifdef JSON_TEST_NO_GLOBAL_UDLS #ifdef JSON_TEST_NO_GLOBAL_UDLS
using namespace nlohmann::literals; // NOLINT(google-build-using-namespace) using namespace nlohmann::literals; // NOLINT(google-build-using-namespace)
#endif #endif
#include <fstream>
#include "make_test_data_available.hpp" #include "make_test_data_available.hpp"
#include <fstream>
TEST_CASE("JSON patch") TEST_CASE("JSON patch")
{ {
@@ -634,7 +634,7 @@ TEST_CASE("JSON patch")
CHECK(target == R"({ "D": "Berlin", "F": "Paris", "GB": "London" })"_json); CHECK(target == R"({ "D": "Berlin", "F": "Paris", "GB": "London" })"_json);
// create a diff from two JSONs // create a diff from two JSONs
json p2 = json::diff(target, source); // NOLINT(readability-suspicious-call-argument) json p2 = json::diff(target, source); // NOLINT(readability-suspicious-call-argument)
// p2 = [{"op": "delete", "path": "/GB"}] // p2 = [{"op": "delete", "path": "/GB"}]
CHECK(p2 == R"([{"op":"remove","path":"/GB"}])"_json); CHECK(p2 == R"([{"op":"remove","path":"/GB"}])"_json);
} }
@@ -1217,76 +1217,64 @@ TEST_CASE("JSON patch")
SECTION("add") SECTION("add")
{ {
CHECK(R"( {} )"_json.patch( CHECK(R"( {} )"_json.patch(
R"( [{"op": "add", "path": "/foo", "value": "bar"}] )"_json R"( [{"op": "add", "path": "/foo", "value": "bar"}] )"_json) == R"( {"foo": "bar"} )"_json);
) == R"( {"foo": "bar"} )"_json);
CHECK(R"( {"foo": [1, 3]} )"_json.patch( CHECK(R"( {"foo": [1, 3]} )"_json.patch(
R"( [{"op": "add", "path": "/foo", "value": "bar"}] )"_json R"( [{"op": "add", "path": "/foo", "value": "bar"}] )"_json) == R"( {"foo": "bar"} )"_json);
) == R"( {"foo": "bar"} )"_json);
CHECK(R"( {"foo": [{}]} )"_json.patch( CHECK(R"( {"foo": [{}]} )"_json.patch(
R"( [{"op": "add", "path": "/foo/0/bar", "value": "baz"}] )"_json R"( [{"op": "add", "path": "/foo/0/bar", "value": "baz"}] )"_json) == R"( {"foo": [{"bar": "baz"}]} )"_json);
) == R"( {"foo": [{"bar": "baz"}]} )"_json);
} }
SECTION("remove") SECTION("remove")
{ {
CHECK(R"( {"foo": "bar"} )"_json.patch( CHECK(R"( {"foo": "bar"} )"_json.patch(
R"( [{"op": "remove", "path": "/foo"}] )"_json R"( [{"op": "remove", "path": "/foo"}] )"_json) == R"( {} )"_json);
) == R"( {} )"_json);
CHECK(R"( {"foo": [1, 2, 3]} )"_json.patch( CHECK(R"( {"foo": [1, 2, 3]} )"_json.patch(
R"( [{"op": "remove", "path": "/foo/1"}] )"_json R"( [{"op": "remove", "path": "/foo/1"}] )"_json) == R"( {"foo": [1, 3]} )"_json);
) == R"( {"foo": [1, 3]} )"_json);
CHECK(R"( {"foo": [{"bar": "baz"}]} )"_json.patch( CHECK(R"( {"foo": [{"bar": "baz"}]} )"_json.patch(
R"( [{"op": "remove", "path": "/foo/0/bar"}] )"_json R"( [{"op": "remove", "path": "/foo/0/bar"}] )"_json) == R"( {"foo": [{}]} )"_json);
) == R"( {"foo": [{}]} )"_json);
} }
SECTION("replace") SECTION("replace")
{ {
CHECK(R"( {"foo": "bar"} )"_json.patch( CHECK(R"( {"foo": "bar"} )"_json.patch(
R"( [{"op": "replace", "path": "/foo", "value": 1}] )"_json R"( [{"op": "replace", "path": "/foo", "value": 1}] )"_json) == R"( {"foo": 1} )"_json);
) == R"( {"foo": 1} )"_json);
CHECK(R"( {"foo": [1, 2, 3]} )"_json.patch( CHECK(R"( {"foo": [1, 2, 3]} )"_json.patch(
R"( [{"op": "replace", "path": "/foo/1", "value": 4}] )"_json R"( [{"op": "replace", "path": "/foo/1", "value": 4}] )"_json) == R"( {"foo": [1, 4, 3]} )"_json);
) == R"( {"foo": [1, 4, 3]} )"_json);
CHECK(R"( {"foo": [{"bar": "baz"}]} )"_json.patch( CHECK(R"( {"foo": [{"bar": "baz"}]} )"_json.patch(
R"( [{"op": "replace", "path": "/foo/0/bar", "value": 1}] )"_json R"( [{"op": "replace", "path": "/foo/0/bar", "value": 1}] )"_json) == R"( {"foo": [{"bar": 1}]} )"_json);
) == R"( {"foo": [{"bar": 1}]} )"_json);
} }
SECTION("move") SECTION("move")
{ {
CHECK(R"( {"foo": [1, 2, 3]} )"_json.patch( CHECK(R"( {"foo": [1, 2, 3]} )"_json.patch(
R"( [{"op": "move", "from": "/foo", "path": "/bar"}] )"_json R"( [{"op": "move", "from": "/foo", "path": "/bar"}] )"_json) == R"( {"bar": [1, 2, 3]} )"_json);
) == R"( {"bar": [1, 2, 3]} )"_json);
} }
SECTION("copy") SECTION("copy")
{ {
CHECK(R"( {"foo": [1, 2, 3]} )"_json.patch( CHECK(R"( {"foo": [1, 2, 3]} )"_json.patch(
R"( [{"op": "copy", "from": "/foo/1", "path": "/bar"}] )"_json R"( [{"op": "copy", "from": "/foo/1", "path": "/bar"}] )"_json) == R"( {"foo": [1, 2, 3], "bar": 2} )"_json);
) == R"( {"foo": [1, 2, 3], "bar": 2} )"_json);
} }
SECTION("copy") SECTION("copy")
{ {
CHECK_NOTHROW(R"( {"foo": "bar"} )"_json.patch( CHECK_NOTHROW(R"( {"foo": "bar"} )"_json.patch(
R"( [{"op": "test", "path": "/foo", "value": "bar"}] )"_json)); R"( [{"op": "test", "path": "/foo", "value": "bar"}] )"_json));
} }
} }
SECTION("Tests from github.com/json-patch/json-patch-tests") SECTION("Tests from github.com/json-patch/json-patch-tests")
{ {
for (const auto* filename : for (const auto* filename :
{ {
TEST_DATA_DIRECTORY "/json-patch-tests/spec_tests.json", TEST_DATA_DIRECTORY "/json-patch-tests/spec_tests.json",
TEST_DATA_DIRECTORY "/json-patch-tests/tests.json" TEST_DATA_DIRECTORY "/json-patch-tests/tests.json"})
})
{ {
CAPTURE(filename) CAPTURE(filename)
std::ifstream f(filename); std::ifstream f(filename);
+120 -125
View File
@@ -12,7 +12,7 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
#ifdef JSON_TEST_NO_GLOBAL_UDLS #ifdef JSON_TEST_NO_GLOBAL_UDLS
using namespace nlohmann::literals; // NOLINT(google-build-using-namespace) using namespace nlohmann::literals; // NOLINT(google-build-using-namespace)
#endif #endif
#include <map> #include <map>
@@ -23,26 +23,32 @@ TEST_CASE("JSON pointers")
SECTION("errors") SECTION("errors")
{ {
CHECK_THROWS_WITH_AS(json::json_pointer("foo"), CHECK_THROWS_WITH_AS(json::json_pointer("foo"),
"[json.exception.parse_error.107] parse error at byte 1: JSON pointer must be empty or begin with '/' - was: 'foo'", json::parse_error&); "[json.exception.parse_error.107] parse error at byte 1: JSON pointer must be empty or begin with '/' - was: 'foo'",
json::parse_error&);
CHECK_THROWS_WITH_AS(json::json_pointer("/~~"), CHECK_THROWS_WITH_AS(json::json_pointer("/~~"),
"[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'", json::parse_error&); "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'",
json::parse_error&);
CHECK_THROWS_WITH_AS(json::json_pointer("/~"), CHECK_THROWS_WITH_AS(json::json_pointer("/~"),
"[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'", json::parse_error&); "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'",
json::parse_error&);
json::json_pointer p; json::json_pointer p;
CHECK_THROWS_WITH_AS(p.top(), CHECK_THROWS_WITH_AS(p.top(),
"[json.exception.out_of_range.405] JSON pointer has no parent", json::out_of_range&); "[json.exception.out_of_range.405] JSON pointer has no parent",
json::out_of_range&);
CHECK_THROWS_WITH_AS(p.pop_back(), CHECK_THROWS_WITH_AS(p.pop_back(),
"[json.exception.out_of_range.405] JSON pointer has no parent", json::out_of_range&); "[json.exception.out_of_range.405] JSON pointer has no parent",
json::out_of_range&);
SECTION("array index error") SECTION("array index error")
{ {
json v = {1, 2, 3, 4}; json v = {1, 2, 3, 4};
json::json_pointer const ptr("/10e"); json::json_pointer const ptr("/10e");
CHECK_THROWS_WITH_AS(v[ptr], CHECK_THROWS_WITH_AS(v[ptr],
"[json.exception.out_of_range.404] unresolved reference token '10e'", json::out_of_range&); "[json.exception.out_of_range.404] unresolved reference token '10e'",
json::out_of_range&);
} }
} }
@@ -144,9 +150,11 @@ TEST_CASE("JSON pointers")
// unresolved access // unresolved access
json j_primitive = 1; json j_primitive = 1;
CHECK_THROWS_WITH_AS(j_primitive["/foo"_json_pointer], CHECK_THROWS_WITH_AS(j_primitive["/foo"_json_pointer],
"[json.exception.out_of_range.404] unresolved reference token 'foo'", json::out_of_range&); "[json.exception.out_of_range.404] unresolved reference token 'foo'",
json::out_of_range&);
CHECK_THROWS_WITH_AS(j_primitive.at("/foo"_json_pointer), CHECK_THROWS_WITH_AS(j_primitive.at("/foo"_json_pointer),
"[json.exception.out_of_range.404] unresolved reference token 'foo'", json::out_of_range&); "[json.exception.out_of_range.404] unresolved reference token 'foo'",
json::out_of_range&);
CHECK(!j_primitive.contains(json::json_pointer("/foo"))); CHECK(!j_primitive.contains(json::json_pointer("/foo")));
} }
@@ -206,14 +214,17 @@ TEST_CASE("JSON pointers")
// unescaped access // unescaped access
CHECK_THROWS_WITH_AS(j.at(json::json_pointer("/a/b")), CHECK_THROWS_WITH_AS(j.at(json::json_pointer("/a/b")),
"[json.exception.out_of_range.403] key 'a' not found", json::out_of_range&); "[json.exception.out_of_range.403] key 'a' not found",
json::out_of_range&);
// unresolved access // unresolved access
const json j_primitive = 1; const json j_primitive = 1;
CHECK_THROWS_WITH_AS(j_primitive["/foo"_json_pointer], CHECK_THROWS_WITH_AS(j_primitive["/foo"_json_pointer],
"[json.exception.out_of_range.404] unresolved reference token 'foo'", json::out_of_range&); "[json.exception.out_of_range.404] unresolved reference token 'foo'",
json::out_of_range&);
CHECK_THROWS_WITH_AS(j_primitive.at("/foo"_json_pointer), CHECK_THROWS_WITH_AS(j_primitive.at("/foo"_json_pointer),
"[json.exception.out_of_range.404] unresolved reference token 'foo'", json::out_of_range&); "[json.exception.out_of_range.404] unresolved reference token 'foo'",
json::out_of_range&);
} }
SECTION("user-defined string literal") SECTION("user-defined string literal")
@@ -274,13 +285,17 @@ TEST_CASE("JSON pointers")
// error with leading 0 // error with leading 0
CHECK_THROWS_WITH_AS(j["/01"_json_pointer], CHECK_THROWS_WITH_AS(j["/01"_json_pointer],
"[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'", json::parse_error&); "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'",
json::parse_error&);
CHECK_THROWS_WITH_AS(j_const["/01"_json_pointer], CHECK_THROWS_WITH_AS(j_const["/01"_json_pointer],
"[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'", json::parse_error&); "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'",
json::parse_error&);
CHECK_THROWS_WITH_AS(j.at("/01"_json_pointer), CHECK_THROWS_WITH_AS(j.at("/01"_json_pointer),
"[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'", json::parse_error&); "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'",
json::parse_error&);
CHECK_THROWS_WITH_AS(j_const.at("/01"_json_pointer), CHECK_THROWS_WITH_AS(j_const.at("/01"_json_pointer),
"[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'", json::parse_error&); "[json.exception.parse_error.106] parse error: array index '01' must not begin with '0'",
json::parse_error&);
CHECK(!j.contains("/01"_json_pointer)); CHECK(!j.contains("/01"_json_pointer));
CHECK(!j.contains("/01"_json_pointer)); CHECK(!j.contains("/01"_json_pointer));
@@ -289,24 +304,32 @@ TEST_CASE("JSON pointers")
// error with incorrect numbers // error with incorrect numbers
CHECK_THROWS_WITH_AS(j["/one"_json_pointer] = 1, CHECK_THROWS_WITH_AS(j["/one"_json_pointer] = 1,
"[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&); "[json.exception.parse_error.109] parse error: array index 'one' is not a number",
json::parse_error&);
CHECK_THROWS_WITH_AS(j_const["/one"_json_pointer] == 1, CHECK_THROWS_WITH_AS(j_const["/one"_json_pointer] == 1,
"[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&); "[json.exception.parse_error.109] parse error: array index 'one' is not a number",
json::parse_error&);
CHECK_THROWS_WITH_AS(j.at("/one"_json_pointer) = 1, CHECK_THROWS_WITH_AS(j.at("/one"_json_pointer) = 1,
"[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&); "[json.exception.parse_error.109] parse error: array index 'one' is not a number",
json::parse_error&);
CHECK_THROWS_WITH_AS(j_const.at("/one"_json_pointer) == 1, CHECK_THROWS_WITH_AS(j_const.at("/one"_json_pointer) == 1,
"[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&); "[json.exception.parse_error.109] parse error: array index 'one' is not a number",
json::parse_error&);
CHECK_THROWS_WITH_AS(j["/+1"_json_pointer] = 1, CHECK_THROWS_WITH_AS(j["/+1"_json_pointer] = 1,
"[json.exception.parse_error.109] parse error: array index '+1' is not a number", json::parse_error&); "[json.exception.parse_error.109] parse error: array index '+1' is not a number",
json::parse_error&);
CHECK_THROWS_WITH_AS(j_const["/+1"_json_pointer] == 1, CHECK_THROWS_WITH_AS(j_const["/+1"_json_pointer] == 1,
"[json.exception.parse_error.109] parse error: array index '+1' is not a number", json::parse_error&); "[json.exception.parse_error.109] parse error: array index '+1' is not a number",
json::parse_error&);
CHECK_THROWS_WITH_AS(j["/1+1"_json_pointer] = 1, CHECK_THROWS_WITH_AS(j["/1+1"_json_pointer] = 1,
"[json.exception.out_of_range.404] unresolved reference token '1+1'", json::out_of_range&); "[json.exception.out_of_range.404] unresolved reference token '1+1'",
json::out_of_range&);
CHECK_THROWS_WITH_AS(j_const["/1+1"_json_pointer] == 1, CHECK_THROWS_WITH_AS(j_const["/1+1"_json_pointer] == 1,
"[json.exception.out_of_range.404] unresolved reference token '1+1'", json::out_of_range&); "[json.exception.out_of_range.404] unresolved reference token '1+1'",
json::out_of_range&);
{ {
auto too_large_index = std::to_string((std::numeric_limits<unsigned long long>::max)()) + "1"; auto too_large_index = std::to_string((std::numeric_limits<unsigned long long>::max)()) + "1";
@@ -335,9 +358,11 @@ TEST_CASE("JSON pointers")
DOCTEST_MSVC_SUPPRESS_WARNING_POP DOCTEST_MSVC_SUPPRESS_WARNING_POP
CHECK_THROWS_WITH_AS(j.at("/one"_json_pointer) = 1, CHECK_THROWS_WITH_AS(j.at("/one"_json_pointer) = 1,
"[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&); "[json.exception.parse_error.109] parse error: array index 'one' is not a number",
json::parse_error&);
CHECK_THROWS_WITH_AS(j_const.at("/one"_json_pointer) == 1, CHECK_THROWS_WITH_AS(j_const.at("/one"_json_pointer) == 1,
"[json.exception.parse_error.109] parse error: array index 'one' is not a number", json::parse_error&); "[json.exception.parse_error.109] parse error: array index 'one' is not a number",
json::parse_error&);
CHECK(!j.contains("/one"_json_pointer)); CHECK(!j.contains("/one"_json_pointer));
CHECK(!j.contains("/one"_json_pointer)); CHECK(!j.contains("/one"_json_pointer));
@@ -345,7 +370,8 @@ TEST_CASE("JSON pointers")
CHECK(!j_const.contains("/one"_json_pointer)); CHECK(!j_const.contains("/one"_json_pointer));
CHECK_THROWS_WITH_AS(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(), CHECK_THROWS_WITH_AS(json({{"/list/0", 1}, {"/list/1", 2}, {"/list/three", 3}}).unflatten(),
"[json.exception.parse_error.109] parse error: array index 'three' is not a number", json::parse_error&); "[json.exception.parse_error.109] parse error: array index 'three' is not a number",
json::parse_error&);
// assign to "-" // assign to "-"
j["/-"_json_pointer] = 99; j["/-"_json_pointer] = 99;
@@ -353,14 +379,17 @@ TEST_CASE("JSON pointers")
// error when using "-" in const object // error when using "-" in const object
CHECK_THROWS_WITH_AS(j_const["/-"_json_pointer], CHECK_THROWS_WITH_AS(j_const["/-"_json_pointer],
"[json.exception.out_of_range.402] array index '-' (3) is out of range", json::out_of_range&); "[json.exception.out_of_range.402] array index '-' (3) is out of range",
json::out_of_range&);
CHECK(!j_const.contains("/-"_json_pointer)); CHECK(!j_const.contains("/-"_json_pointer));
// error when using "-" with at // error when using "-" with at
CHECK_THROWS_WITH_AS(j.at("/-"_json_pointer), CHECK_THROWS_WITH_AS(j.at("/-"_json_pointer),
"[json.exception.out_of_range.402] array index '-' (7) is out of range", json::out_of_range&); "[json.exception.out_of_range.402] array index '-' (7) is out of range",
json::out_of_range&);
CHECK_THROWS_WITH_AS(j_const.at("/-"_json_pointer), CHECK_THROWS_WITH_AS(j_const.at("/-"_json_pointer),
"[json.exception.out_of_range.402] array index '-' (3) is out of range", json::out_of_range&); "[json.exception.out_of_range.402] array index '-' (3) is out of range",
json::out_of_range&);
CHECK(!j_const.contains("/-"_json_pointer)); CHECK(!j_const.contains("/-"_json_pointer));
} }
@@ -375,19 +404,23 @@ TEST_CASE("JSON pointers")
// assign to nonexisting index // assign to nonexisting index
CHECK_THROWS_WITH_AS(j.at("/3"_json_pointer), CHECK_THROWS_WITH_AS(j.at("/3"_json_pointer),
"[json.exception.out_of_range.401] array index 3 is out of range", json::out_of_range&); "[json.exception.out_of_range.401] array index 3 is out of range",
json::out_of_range&);
CHECK(!j.contains("/3"_json_pointer)); CHECK(!j.contains("/3"_json_pointer));
// assign to nonexisting index (with gap) // assign to nonexisting index (with gap)
CHECK_THROWS_WITH_AS(j.at("/5"_json_pointer), CHECK_THROWS_WITH_AS(j.at("/5"_json_pointer),
"[json.exception.out_of_range.401] array index 5 is out of range", json::out_of_range&); "[json.exception.out_of_range.401] array index 5 is out of range",
json::out_of_range&);
CHECK(!j.contains("/5"_json_pointer)); CHECK(!j.contains("/5"_json_pointer));
// assign to "-" // assign to "-"
CHECK_THROWS_WITH_AS(j["/-"_json_pointer], CHECK_THROWS_WITH_AS(j["/-"_json_pointer],
"[json.exception.out_of_range.402] array index '-' (3) is out of range", json::out_of_range&); "[json.exception.out_of_range.402] array index '-' (3) is out of range",
json::out_of_range&);
CHECK_THROWS_WITH_AS(j.at("/-"_json_pointer), CHECK_THROWS_WITH_AS(j.at("/-"_json_pointer),
"[json.exception.out_of_range.402] array index '-' (3) is out of range", json::out_of_range&); "[json.exception.out_of_range.402] array index '-' (3) is out of range",
json::out_of_range&);
CHECK(!j.contains("/-"_json_pointer)); CHECK(!j.contains("/-"_json_pointer));
} }
} }
@@ -395,46 +428,31 @@ TEST_CASE("JSON pointers")
SECTION("flatten") SECTION("flatten")
{ {
json j = json j =
{
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{ {
"answer", { {"pi", 3.141},
{"everything", 42} {"happy", true},
} {"name", "Niels"},
}, {"nothing", nullptr},
{"list", {1, 0, 2}}, {"answer", {{"everything", 42}}},
{ {"list", {1, 0, 2}},
"object", { {"object", {{"currency", "USD"}, {"value", 42.99}, {"", "empty string"}, {"/", "slash"}, {"~", "tilde"}, {"~1", "tilde1"}}}};
{"currency", "USD"},
{"value", 42.99},
{"", "empty string"},
{"/", "slash"},
{"~", "tilde"},
{"~1", "tilde1"}
}
}
};
json j_flatten = json j_flatten =
{ {
{"/pi", 3.141}, {"/pi", 3.141},
{"/happy", true}, {"/happy", true},
{"/name", "Niels"}, {"/name", "Niels"},
{"/nothing", nullptr}, {"/nothing", nullptr},
{"/answer/everything", 42}, {"/answer/everything", 42},
{"/list/0", 1}, {"/list/0", 1},
{"/list/1", 0}, {"/list/1", 0},
{"/list/2", 2}, {"/list/2", 2},
{"/object/currency", "USD"}, {"/object/currency", "USD"},
{"/object/value", 42.99}, {"/object/value", 42.99},
{"/object/", "empty string"}, {"/object/", "empty string"},
{"/object/~1", "slash"}, {"/object/~1", "slash"},
{"/object/~0", "tilde"}, {"/object/~0", "tilde"},
{"/object/~01", "tilde1"} {"/object/~01", "tilde1"}};
};
// check if flattened result is as expected // check if flattened result is as expected
CHECK(j.flatten() == j_flatten); CHECK(j.flatten() == j_flatten);
@@ -444,7 +462,8 @@ TEST_CASE("JSON pointers")
// error for nonobjects // error for nonobjects
CHECK_THROWS_WITH_AS(json(1).unflatten(), CHECK_THROWS_WITH_AS(json(1).unflatten(),
"[json.exception.type_error.314] only objects can be unflattened", json::type_error&); "[json.exception.type_error.314] only objects can be unflattened",
json::type_error&);
// error for nonprimitve values // error for nonprimitve values
#if JSON_DIAGNOSTICS #if JSON_DIAGNOSTICS
@@ -456,7 +475,8 @@ TEST_CASE("JSON pointers")
// error for conflicting values // error for conflicting values
json const j_error = {{"", 42}, {"/foo", 17}}; json const j_error = {{"", 42}, {"/foo", 17}};
CHECK_THROWS_WITH_AS(j_error.unflatten(), CHECK_THROWS_WITH_AS(j_error.unflatten(),
"[json.exception.type_error.313] invalid value to unflatten", json::type_error&); "[json.exception.type_error.313] invalid value to unflatten",
json::type_error&);
// explicit roundtrip check // explicit roundtrip check
CHECK(j.flatten().unflatten() == j); CHECK(j.flatten().unflatten() == j);
@@ -481,8 +501,7 @@ TEST_CASE("JSON pointers")
SECTION("string representation") SECTION("string representation")
{ {
for (const auto* ptr_str : for (const auto* ptr_str :
{"", "/foo", "/foo/0", "/", "/a~1b", "/c%d", "/e^f", "/g|h", "/i\\j", "/k\"l", "/ ", "/m~0n" {"", "/foo", "/foo/0", "/", "/a~1b", "/c%d", "/e^f", "/g|h", "/i\\j", "/k\"l", "/ ", "/m~0n"})
})
{ {
json::json_pointer const ptr(ptr_str); json::json_pointer const ptr(ptr_str);
std::stringstream ss; std::stringstream ss;
@@ -515,29 +534,15 @@ TEST_CASE("JSON pointers")
SECTION("empty, push, pop and parent") SECTION("empty, push, pop and parent")
{ {
const json j = const json j =
{
{"", "Hello"},
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{ {
"answer", { {"", "Hello"},
{"everything", 42} {"pi", 3.141},
} {"happy", true},
}, {"name", "Niels"},
{"list", {1, 0, 2}}, {"nothing", nullptr},
{ {"answer", {{"everything", 42}}},
"object", { {"list", {1, 0, 2}},
{"currency", "USD"}, {"object", {{"currency", "USD"}, {"value", 42.99}, {"", "empty string"}, {"/", "slash"}, {"~", "tilde"}, {"~1", "tilde1"}}}};
{"value", 42.99},
{"", "empty string"},
{"/", "slash"},
{"~", "tilde"},
{"~1", "tilde1"}
}
}
};
// empty json_pointer returns the root JSON-object // empty json_pointer returns the root JSON-object
auto ptr = ""_json_pointer; auto ptr = ""_json_pointer;
@@ -591,29 +596,15 @@ TEST_CASE("JSON pointers")
SECTION("operators") SECTION("operators")
{ {
const json j = const json j =
{
{"", "Hello"},
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{ {
"answer", { {"", "Hello"},
{"everything", 42} {"pi", 3.141},
} {"happy", true},
}, {"name", "Niels"},
{"list", {1, 0, 2}}, {"nothing", nullptr},
{ {"answer", {{"everything", 42}}},
"object", { {"list", {1, 0, 2}},
{"currency", "USD"}, {"object", {{"currency", "USD"}, {"value", 42.99}, {"", "empty string"}, {"/", "slash"}, {"~", "tilde"}, {"~1", "tilde1"}}}};
{"value", 42.99},
{"", "empty string"},
{"/", "slash"},
{"~", "tilde"},
{"~1", "tilde1"}
}
}
};
// empty json_pointer returns the root JSON-object // empty json_pointer returns the root JSON-object
auto ptr = ""_json_pointer; auto ptr = ""_json_pointer;
@@ -652,7 +643,7 @@ TEST_CASE("JSON pointers")
SECTION("equality comparison") SECTION("equality comparison")
{ {
const char* ptr_cpstring = "/foo/bar"; const char* ptr_cpstring = "/foo/bar";
const char ptr_castring[] = "/foo/bar"; // NOLINT(hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays) const char ptr_castring[] = "/foo/bar"; // NOLINT(hicpp-avoid-c-arrays,modernize-avoid-c-arrays,cppcoreguidelines-avoid-c-arrays)
std::string ptr_string{"/foo/bar"}; std::string ptr_string{"/foo/bar"};
auto ptr1 = json::json_pointer(ptr_string); auto ptr1 = json::json_pointer(ptr_string);
auto ptr2 = json::json_pointer(ptr_string); auto ptr2 = json::json_pointer(ptr_string);
@@ -687,13 +678,17 @@ TEST_CASE("JSON pointers")
SECTION("exceptions") SECTION("exceptions")
{ {
CHECK_THROWS_WITH_AS(ptr1 == "foo", CHECK_THROWS_WITH_AS(ptr1 == "foo",
"[json.exception.parse_error.107] parse error at byte 1: JSON pointer must be empty or begin with '/' - was: 'foo'", json::parse_error&); "[json.exception.parse_error.107] parse error at byte 1: JSON pointer must be empty or begin with '/' - was: 'foo'",
json::parse_error&);
CHECK_THROWS_WITH_AS("foo" == ptr1, CHECK_THROWS_WITH_AS("foo" == ptr1,
"[json.exception.parse_error.107] parse error at byte 1: JSON pointer must be empty or begin with '/' - was: 'foo'", json::parse_error&); "[json.exception.parse_error.107] parse error at byte 1: JSON pointer must be empty or begin with '/' - was: 'foo'",
json::parse_error&);
CHECK_THROWS_WITH_AS(ptr1 == "/~~", CHECK_THROWS_WITH_AS(ptr1 == "/~~",
"[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'", json::parse_error&); "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'",
json::parse_error&);
CHECK_THROWS_WITH_AS("/~~" == ptr1, CHECK_THROWS_WITH_AS("/~~" == ptr1,
"[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'", json::parse_error&); "[json.exception.parse_error.108] parse error: escape character '~' must be followed with '0' or '1'",
json::parse_error&);
} }
} }
@@ -708,7 +703,7 @@ TEST_CASE("JSON pointers")
// build with C++20 // build with C++20
// JSON_HAS_CPP_20 // JSON_HAS_CPP_20
#if JSON_HAS_THREE_WAY_COMPARISON #if JSON_HAS_THREE_WAY_COMPARISON
CHECK((ptr1 <=> ptr2) == std::strong_ordering::less); // *NOPAD* CHECK((ptr1 <= > ptr2) == std::strong_ordering::less); // *NOPAD*
CHECK(ptr2 > ptr1); CHECK(ptr2 > ptr1);
#endif #endif
} }
-1
View File
@@ -26,4 +26,3 @@ TEST_CASE("tests on very large JSONs")
CHECK_NOTHROW(_ = nlohmann::json::parse(s)); CHECK_NOTHROW(_ = nlohmann::json::parse(s));
} }
} }
+1 -1
View File
@@ -11,7 +11,7 @@
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using nlohmann::json; using nlohmann::json;
#ifdef JSON_TEST_NO_GLOBAL_UDLS #ifdef JSON_TEST_NO_GLOBAL_UDLS
using namespace nlohmann::literals; // NOLINT(google-build-using-namespace) using namespace nlohmann::literals; // NOLINT(google-build-using-namespace)
#endif #endif
TEST_CASE("JSON Merge Patch") TEST_CASE("JSON Merge Patch")
+4 -6
View File
@@ -21,12 +21,10 @@ TEST_CASE("version information")
CHECK(j["copyright"] == "(C) 2013-2023 Niels Lohmann"); CHECK(j["copyright"] == "(C) 2013-2023 Niels Lohmann");
CHECK(j["url"] == "https://github.com/nlohmann/json"); CHECK(j["url"] == "https://github.com/nlohmann/json");
CHECK(j["version"] == json( CHECK(j["version"] == json(
{ {{"string", "3.11.3"},
{"string", "3.11.3"}, {"major", 3},
{"major", 3}, {"minor", 11},
{"minor", 11}, {"patch", 3}}));
{"patch", 3}
}));
CHECK(j.find("platform") != j.end()); CHECK(j.find("platform") != j.end());
CHECK(j.at("compiler").find("family") != j.at("compiler").end()); CHECK(j.at("compiler").find("family") != j.at("compiler").end());
+2 -4
View File
@@ -637,10 +637,8 @@ TEST_CASE("modifiers")
{ {
json j_other_array2 = {"first", "second"}; json j_other_array2 = {"first", "second"};
CHECK_THROWS_WITH_AS(j_array.insert(j_array.end(), j_array.begin(), j_array.end()), "[json.exception.invalid_iterator.211] passed iterators may not belong to container", CHECK_THROWS_WITH_AS(j_array.insert(j_array.end(), j_array.begin(), j_array.end()), "[json.exception.invalid_iterator.211] passed iterators may not belong to container", json::invalid_iterator&);
json::invalid_iterator&); CHECK_THROWS_WITH_AS(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()), "[json.exception.invalid_iterator.210] iterators do not fit", json::invalid_iterator&);
CHECK_THROWS_WITH_AS(j_array.insert(j_array.end(), j_other_array.begin(), j_other_array2.end()), "[json.exception.invalid_iterator.210] iterators do not fit",
json::invalid_iterator&);
} }
} }
Loaded 100 of 123 files, more files were not shown because too many files have changed in this diff. Show more