Merge branch 'develop' into doctest

This commit is contained in:
Viktor Kirilov 2019-03-18 16:59:36 +02:00 committed by GitHub
commit 365944b0bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
60 changed files with 15683 additions and 7958 deletions

23
.clang-tidy Normal file
View file

@ -0,0 +1,23 @@
Checks: '-*,
bugprone-*,
cert-*,
clang-analyzer-*,
google-*,
-google-runtime-references,
hicpp-*,
-hicpp-no-array-decay,
-hicpp-uppercase-literal-suffix,
misc-*,
-misc-non-private-member-variables-in-classes,
llvm-*,
-llvm-header-guard,
modernize-*,
performance-*,
portability-*,
readability-*,
-readability-magic-numbers,
-readability-uppercase-literal-suffix'
CheckOptions:
- key: hicpp-special-member-functions.AllowSoleDefaultDtor
value: 1

View file

@ -128,21 +128,6 @@ matrix:
# OSX / Clang # OSX / Clang
- os: osx
osx_image: xcode6.4
- os: osx
osx_image: xcode7.3
- os: osx
osx_image: xcode8
- os: osx
osx_image: xcode8.1
- os: osx
osx_image: xcode8.2
- os: osx - os: osx
osx_image: xcode8.3 osx_image: xcode8.3
@ -164,6 +149,9 @@ matrix:
- os: osx - os: osx
osx_image: xcode10 osx_image: xcode10
- os: osx
osx_image: xcode10.1
# Linux / GCC # Linux / GCC
- os: linux - os: linux
@ -290,15 +278,23 @@ matrix:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0'] sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0']
packages: ['g++-6', 'clang-6.0', 'ninja-build'] packages: ['g++-6', 'clang-6.0', 'ninja-build']
- os: linux
compiler: clang
env: COMPILER=clang++-7
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-7']
packages: ['g++-6', 'clang-7', 'ninja-build']
- os: linux - os: linux
compiler: clang compiler: clang
env: env:
- COMPILER=clang++-6.0 - COMPILER=clang++-7
- CXXFLAGS=-std=c++1z - CXXFLAGS=-std=c++1z
addons: addons:
apt: apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0'] sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-7']
packages: ['g++-6', 'clang-6.0', 'ninja-build'] packages: ['g++-6', 'clang-7', 'ninja-build']
################ ################
# build script # # build script #

View file

@ -16,6 +16,7 @@ include(ExternalProject)
## OPTIONS ## OPTIONS
## ##
option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ON) option(JSON_BuildTests "Build the unit tests when BUILD_TESTING is enabled." ON)
option(JSON_Install "Install CMake targets during install step." ON)
option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OFF) option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OFF)
## ##
@ -46,7 +47,11 @@ endif()
## ##
add_library(${NLOHMANN_JSON_TARGET_NAME} INTERFACE) add_library(${NLOHMANN_JSON_TARGET_NAME} INTERFACE)
add_library(${PROJECT_NAME}::${NLOHMANN_JSON_TARGET_NAME} ALIAS ${NLOHMANN_JSON_TARGET_NAME}) add_library(${PROJECT_NAME}::${NLOHMANN_JSON_TARGET_NAME} ALIAS ${NLOHMANN_JSON_TARGET_NAME})
target_compile_features(${NLOHMANN_JSON_TARGET_NAME} INTERFACE cxx_std_11) if (${CMAKE_VERSION} VERSION_LESS "3.8.0")
target_compile_features(${NLOHMANN_JSON_TARGET_NAME} INTERFACE cxx_range_for)
else()
target_compile_features(${NLOHMANN_JSON_TARGET_NAME} INTERFACE cxx_std_11)
endif()
target_include_directories( target_include_directories(
${NLOHMANN_JSON_TARGET_NAME} ${NLOHMANN_JSON_TARGET_NAME}
@ -92,32 +97,34 @@ configure_file(
@ONLY @ONLY
) )
install( if(JSON_Install)
DIRECTORY ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}
DESTINATION ${NLOHMANN_JSON_INCLUDE_INSTALL_DIR}
)
install(
FILES ${NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE} ${NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE}
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
)
if (NLOHMANN_ADD_NATVIS)
install( install(
FILES ${NLOHMANN_NATVIS_FILE} DIRECTORY ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}
DESTINATION . DESTINATION ${NLOHMANN_JSON_INCLUDE_INSTALL_DIR}
) )
install(
FILES ${NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE} ${NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE}
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
)
if (NLOHMANN_ADD_NATVIS)
install(
FILES ${NLOHMANN_NATVIS_FILE}
DESTINATION .
)
endif()
export(
TARGETS ${NLOHMANN_JSON_TARGET_NAME}
NAMESPACE ${PROJECT_NAME}::
FILE ${NLOHMANN_JSON_CMAKE_PROJECT_TARGETS_FILE}
)
install(
TARGETS ${NLOHMANN_JSON_TARGET_NAME}
EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}
INCLUDES DESTINATION ${NLOHMANN_JSON_INCLUDE_INSTALL_DIR}
)
install(
EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}
NAMESPACE ${PROJECT_NAME}::
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
)
endif() endif()
export(
TARGETS ${NLOHMANN_JSON_TARGET_NAME}
NAMESPACE ${PROJECT_NAME}::
FILE ${NLOHMANN_JSON_CMAKE_PROJECT_TARGETS_FILE}
)
install(
TARGETS ${NLOHMANN_JSON_TARGET_NAME}
EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}
INCLUDES DESTINATION ${NLOHMANN_JSON_INCLUDE_INSTALL_DIR}
)
install(
EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}
NAMESPACE ${PROJECT_NAME}::
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
)

214
Makefile
View file

@ -49,6 +49,9 @@ all:
@echo "clean - remove built files" @echo "clean - remove built files"
@echo "coverage - create coverage information with lcov" @echo "coverage - create coverage information with lcov"
@echo "cppcheck - analyze code with cppcheck" @echo "cppcheck - analyze code with cppcheck"
@echo "cpplint - analyze code with cpplint"
@echo "clang_tidy - analyze code with Clang-Tidy"
@echo "clang_analyze - analyze code with Clang-Analyzer"
@echo "doctest - compile example files and check their output" @echo "doctest - compile example files and check their output"
@echo "fuzz_testing - prepare fuzz testing of the JSON parser" @echo "fuzz_testing - prepare fuzz testing of the JSON parser"
@echo "fuzz_testing_bson - prepare fuzz testing of the BSON parser" @echo "fuzz_testing_bson - prepare fuzz testing of the BSON parser"
@ -122,7 +125,7 @@ doctest:
# -Wno-c++2a-compat: u8 literals will behave differently in C++20... # -Wno-c++2a-compat: u8 literals will behave differently in C++20...
# -Wno-padded: padding is nothing to warn about # -Wno-padded: padding is nothing to warn about
pedantic_clang: pedantic_clang:
$(MAKE) json_unit CXX=$(COMPILER_DIR)/clang++ CXXFLAGS="\ $(MAKE) json_unit CXX=$(COMPILER_DIR)/clang++ CXXFLAGS=" \
-std=c++11 -Wno-c++98-compat -Wno-c++98-compat-pedantic \ -std=c++11 -Wno-c++98-compat -Wno-c++98-compat-pedantic \
-Werror \ -Werror \
-Weverything \ -Weverything \
@ -134,72 +137,233 @@ pedantic_clang:
-Wno-float-equal \ -Wno-float-equal \
-Wno-switch-enum -Wno-covered-switch-default \ -Wno-switch-enum -Wno-covered-switch-default \
-Wno-c++2a-compat \ -Wno-c++2a-compat \
-Wno-c++17-extensions \
-Wno-padded" -Wno-padded"
# calling GCC with most warnings # calling GCC with most warnings
pedantic_gcc: pedantic_gcc:
$(MAKE) json_unit CXX=$(COMPILER_DIR)/g++ CXXFLAGS="\ $(MAKE) json_unit CXX=$(COMPILER_DIR)/g++ CXXFLAGS=" \
-std=c++11 \ -std=c++11 \
-Wno-deprecated-declarations \ -Waddress \
-Werror \ -Waddress-of-packed-member \
-Wall -Wpedantic -Wextra \ -Waggressive-loop-optimizations \
-Waligned-new=all \
-Wall \
-Walloc-zero \
-Walloca \ -Walloca \
-Warray-bounds \
-Warray-bounds=2 \ -Warray-bounds=2 \
-Wcast-qual -Wcast-align \ -Wattribute-alias=2 \
-Wattribute-warning \
-Wattributes \
-Wbool-compare \
-Wbool-operation \
-Wbuiltin-declaration-mismatch \
-Wbuiltin-macro-redefined \
-Wcannot-profile \
-Wcast-align \
-Wcast-function-type \
-Wcast-qual \
-Wcatch-value=3 \
-Wchar-subscripts \ -Wchar-subscripts \
-Wclass-conversion \
-Wclass-memaccess \
-Wclobbered \
-Wcomment \
-Wcomments \
-Wconditionally-supported \ -Wconditionally-supported \
-Wconversion \ -Wconversion \
-Wconversion-null \
-Wcoverage-mismatch \
-Wcpp \
-Wctor-dtor-privacy \
-Wdangling-else \
-Wdate-time \ -Wdate-time \
-Wdelete-incomplete \
-Wdelete-non-virtual-dtor \
-Wdeprecated \ -Wdeprecated \
-Wdeprecated-copy \
-Wdeprecated-copy-dtor \
-Wdeprecated-declarations \
-Wdisabled-optimization \ -Wdisabled-optimization \
-Wdiv-by-zero \
-Wdouble-promotion \ -Wdouble-promotion \
-Wduplicated-branches \ -Wduplicated-branches \
-Wduplicated-cond \ -Wduplicated-cond \
-Weffc++ \
-Wempty-body \
-Wendif-labels \
-Wenum-compare \
-Wexpansion-to-defined \
-Werror \
-Wextra \
-Wextra-semi \
-Wfloat-conversion \
-Wfloat-equal \
-Wformat \
-Wformat-contains-nul \
-Wformat-extra-args \
-Wformat-nonliteral \
-Wformat-overflow=2 \ -Wformat-overflow=2 \
-Wformat-security \
-Wformat-signedness \ -Wformat-signedness \
-Wformat-truncation=2 \ -Wformat-truncation=2 \
-Wformat-y2k \
-Wformat-zero-length \
-Wformat=2 \ -Wformat=2 \
-Wno-ignored-qualifiers \ -Wframe-address \
-Wfree-nonheap-object \
-Whsa \
-Wif-not-aligned \
-Wignored-attributes \
-Wignored-qualifiers \
-Wimplicit-fallthrough=5 \ -Wimplicit-fallthrough=5 \
-Winherited-variadic-ctor \
-Winit-list-lifetime \
-Winit-self \
-Winline \
-Wint-in-bool-context \
-Wint-to-pointer-cast \
-Winvalid-memory-model \
-Winvalid-offsetof \
-Winvalid-pch \
-Wliteral-suffix \
-Wlogical-not-parentheses \
-Wlogical-op \ -Wlogical-op \
-Wlto-type-mismatch \
-Wmain \
-Wmaybe-uninitialized \
-Wmemset-elt-size \
-Wmemset-transposed-args \
-Wmisleading-indentation \
-Wmissing-attributes \
-Wmissing-braces \
-Wmissing-declarations \ -Wmissing-declarations \
-Wmissing-field-initializers \
-Wmissing-format-attribute \ -Wmissing-format-attribute \
-Wmissing-include-dirs \ -Wmissing-include-dirs \
-Wmissing-noreturn \
-Wmissing-profile \
-Wmultichar \
-Wmultiple-inheritance \
-Wmultistatement-macros \
-Wnarrowing \
-Wno-deprecated-declarations \
-Wno-long-long \
-Wno-namespaces \
-Wno-padded \
-Wno-switch-enum \
-Wno-system-headers \
-Wno-templates \
-Wno-undef \
-Wnoexcept \ -Wnoexcept \
-Wnoexcept-type \
-Wnon-template-friend \
-Wnon-virtual-dtor \
-Wnonnull \ -Wnonnull \
-Wnonnull-compare \
-Wnonportable-cfstrings \
-Wnormalized \
-Wnull-dereference \ -Wnull-dereference \
-Wodr \
-Wold-style-cast \ -Wold-style-cast \
-Wopenmp-simd \
-Woverflow \
-Woverlength-strings \
-Woverloaded-virtual \ -Woverloaded-virtual \
-Wpacked \
-Wpacked-bitfield-compat \
-Wpacked-not-aligned \
-Wparentheses \ -Wparentheses \
-Wpedantic \
-Wpessimizing-move \
-Wplacement-new=2 \ -Wplacement-new=2 \
-Wpmf-conversions \
-Wpointer-arith \
-Wpointer-compare \
-Wpragmas \
-Wprio-ctor-dtor \
-Wpsabi \
-Wredundant-decls \ -Wredundant-decls \
-Wredundant-move \
-Wregister \
-Wreorder \ -Wreorder \
-Wrestrict \ -Wrestrict \
-Wreturn-local-addr \
-Wreturn-type \
-Wscalar-storage-order \
-Wsequence-point \
-Wshadow \
-Wshadow-compatible-local \
-Wshadow-local \
-Wshadow=compatible-local \
-Wshadow=global \ -Wshadow=global \
-Wshadow=local \
-Wshift-count-negative \
-Wshift-count-overflow \
-Wshift-negative-value \
-Wshift-overflow=2 \ -Wshift-overflow=2 \
-Wsign-compare \
-Wsign-conversion \ -Wsign-conversion \
-Wsign-promo \ -Wsign-promo \
-Wsized-deallocation \ -Wsized-deallocation \
-Wsizeof-array-argument \
-Wsizeof-pointer-div \
-Wsizeof-pointer-memaccess \
-Wstack-protector \
-Wstrict-aliasing=3 \
-Wstrict-null-sentinel \
-Wstrict-overflow=5 \ -Wstrict-overflow=5 \
-Wstringop-overflow=4 \
-Wstringop-truncation \
-Wsubobject-linkage \
-Wsuggest-attribute=cold \
-Wsuggest-attribute=const \ -Wsuggest-attribute=const \
-Wsuggest-attribute=format \ -Wsuggest-attribute=format \
-Wsuggest-attribute=malloc \
-Wsuggest-attribute=noreturn \ -Wsuggest-attribute=noreturn \
-Wsuggest-attribute=pure \ -Wsuggest-attribute=pure \
-Wsuggest-final-methods \ -Wsuggest-final-methods \
-Wsuggest-final-types \ -Wsuggest-final-types \
-Wsuggest-override \ -Wsuggest-override \
-Wswitch \
-Wswitch-bool \
-Wswitch-default \
-Wswitch-unreachable \
-Wsync-nand \
-Wsynth \
-Wtautological-compare \
-Wterminate \
-Wtrampolines \
-Wtrigraphs \ -Wtrigraphs \
-Wundef \ -Wtype-limits \
-Wuninitialized -Wunknown-pragmas \ -Wuninitialized \
-Wunknown-pragmas \
-Wunreachable-code \
-Wunsafe-loop-optimizations \
-Wunused \ -Wunused \
-Wunused-but-set-parameter \
-Wunused-but-set-variable \
-Wunused-const-variable=2 \ -Wunused-const-variable=2 \
-Wunused-function \
-Wunused-label \
-Wunused-local-typedefs \
-Wunused-macros \ -Wunused-macros \
-Wunused-parameter \ -Wunused-parameter \
-Wunused-result \
-Wunused-value \
-Wunused-variable \
-Wuseless-cast \ -Wuseless-cast \
-Wvarargs \
-Wvariadic-macros \ -Wvariadic-macros \
-Wctor-dtor-privacy \ -Wvector-operation-performance \
-Winit-self \ -Wvirtual-inheritance \
-Wstrict-null-sentinel" -Wvirtual-move-assign \
-Wvla \
-Wvolatile-register-var \
-Wwrite-strings \
-Wzero-as-null-pointer-constant \
"
########################################################################## ##########################################################################
# benchmarks # benchmarks
@ -276,7 +440,7 @@ fuzzing-stop:
# call cppcheck on the main header file # call cppcheck on the main header file
cppcheck: cppcheck:
cppcheck --enable=warning --inconclusive --force --std=c++11 $(AMALGAMATED_FILE) --error-exitcode=1 cppcheck --enable=warning --inconclusive --force --std=c++11 $(SRCS) --error-exitcode=1
# compile and check with Clang Static Analyzer # compile and check with Clang Static Analyzer
clang_analyze: clang_analyze:
@ -285,6 +449,30 @@ clang_analyze:
cd clang_analyze_build ; CCC_CXX=$(COMPILER_DIR)/clang++ CXX=$(COMPILER_DIR)/clang++ $(COMPILER_DIR)/scan-build cmake .. -GNinja cd clang_analyze_build ; CCC_CXX=$(COMPILER_DIR)/clang++ CXX=$(COMPILER_DIR)/clang++ $(COMPILER_DIR)/scan-build cmake .. -GNinja
cd clang_analyze_build ; $(COMPILER_DIR)/scan-build -enable-checker alpha.core.BoolAssignment,alpha.core.CallAndMessageUnInitRefArg,alpha.core.CastSize,alpha.core.CastToStruct,alpha.core.Conversion,alpha.core.DynamicTypeChecker,alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,alpha.core.SizeofPtr,alpha.core.StackAddressAsyncEscape,alpha.core.TestAfterDivZero,alpha.deadcode.UnreachableCode,core.builtin.BuiltinFunctions,core.builtin.NoReturnFunctions,core.CallAndMessage,core.DivideZero,core.DynamicTypePropagation,core.NonnilStringConstants,core.NonNullParamChecker,core.NullDereference,core.StackAddressEscape,core.UndefinedBinaryOperatorResult,core.uninitialized.ArraySubscript,core.uninitialized.Assign,core.uninitialized.Branch,core.uninitialized.CapturedBlockVariable,core.uninitialized.UndefReturn,core.VLASize,cplusplus.InnerPointer,cplusplus.Move,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,cplusplus.SelfAssignment,deadcode.DeadStores,nullability.NullableDereferenced,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull --use-c++=$(COMPILER_DIR)/clang++ --view -analyze-headers -o clang_analyze_build/report.html ninja cd clang_analyze_build ; $(COMPILER_DIR)/scan-build -enable-checker alpha.core.BoolAssignment,alpha.core.CallAndMessageUnInitRefArg,alpha.core.CastSize,alpha.core.CastToStruct,alpha.core.Conversion,alpha.core.DynamicTypeChecker,alpha.core.FixedAddr,alpha.core.PointerArithm,alpha.core.PointerSub,alpha.core.SizeofPtr,alpha.core.StackAddressAsyncEscape,alpha.core.TestAfterDivZero,alpha.deadcode.UnreachableCode,core.builtin.BuiltinFunctions,core.builtin.NoReturnFunctions,core.CallAndMessage,core.DivideZero,core.DynamicTypePropagation,core.NonnilStringConstants,core.NonNullParamChecker,core.NullDereference,core.StackAddressEscape,core.UndefinedBinaryOperatorResult,core.uninitialized.ArraySubscript,core.uninitialized.Assign,core.uninitialized.Branch,core.uninitialized.CapturedBlockVariable,core.uninitialized.UndefReturn,core.VLASize,cplusplus.InnerPointer,cplusplus.Move,cplusplus.NewDelete,cplusplus.NewDeleteLeaks,cplusplus.SelfAssignment,deadcode.DeadStores,nullability.NullableDereferenced,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull --use-c++=$(COMPILER_DIR)/clang++ --view -analyze-headers -o clang_analyze_build/report.html ninja
# call cpplint (some errors expected due to false positives)
cpplint:
third_party/cpplint/cpplint.py --filter=-whitespace,-legal,-readability/alt_tokens,-runtime/references,-runtime/explicit --quiet --recursive include
clang_tidy:
$(COMPILER_DIR)/clang-tidy $(SRCS) -- -Iinclude -std=c++11
pvs_studio:
rm -fr pvs_studio_build
mkdir pvs_studio_build
cd pvs_studio_build ; cmake .. -DCMAKE_EXPORT_COMPILE_COMMANDS=On
cd pvs_studio_build ; pvs-studio-analyzer analyze -j 10
cd pvs_studio_build ; plog-converter -a'GA:1,2;64:1;CS' -t fullhtml PVS-Studio.log -o pvs
open pvs_studio_build/pvs/index.html
infer:
rm -fr infer_build
mkdir infer_build
cd infer_build ; infer compile -- cmake .. ; infer run -- make -j 4
oclint:
oclint $(SRCS) -report-type html -enable-global-analysis -o oclint_report.html -max-priority-1=10000 -max-priority-2=10000 -max-priority-3=10000 -- -std=c++11 -Iinclude
open oclint_report.html
########################################################################## ##########################################################################
# maintainer targets # maintainer targets
########################################################################## ##########################################################################

View file

@ -100,6 +100,10 @@ To embed the library directly into an existing CMake project, place the entire s
# run from your own project's code. # run from your own project's code.
set(JSON_BuildTests OFF CACHE INTERNAL "") set(JSON_BuildTests OFF CACHE INTERNAL "")
# If you only include this third party in PRIVATE source files, you do not
# need to install it when your main project gets installed.
# set(JSON_Install OFF CACHE INTERNAL "")
# Don't use include(nlohmann_json/CMakeLists.txt) since that carries with it # Don't use include(nlohmann_json/CMakeLists.txt) since that carries with it
# unintended consequences that will break the build. It's generally # unintended consequences that will break the build. It's generally
# discouraged (although not necessarily well documented as such) to use # discouraged (although not necessarily well documented as such) to use
@ -155,7 +159,7 @@ If you are using [Spack](https://www.spack.io/) to manage your dependencies, you
If you are using [hunter](https://github.com/ruslo/hunter/) on your project for external dependencies, then you can use the [nlohmann_json package](https://docs.hunter.sh/en/latest/packages/pkg/nlohmann_json.html). Please see the hunter project for any issues regarding the packaging. If you are using [hunter](https://github.com/ruslo/hunter/) on your project for external dependencies, then you can use the [nlohmann_json package](https://docs.hunter.sh/en/latest/packages/pkg/nlohmann_json.html). Please see the hunter project for any issues regarding the packaging.
If you are using [Buckaroo](https://buckaroo.pm), you can install this library's module with `buckaroo install nlohmann/json`. Please file issues [here](https://github.com/LoopPerfect/buckaroo-recipes/issues/new?title=nlohmann/nlohmann/json). If you are using [Buckaroo](https://buckaroo.pm), you can install this library's module with `buckaroo add github.com/buckaroo-pm/nlohmann-json`. Please file issues [here](https://github.com/buckaroo-pm/nlohmann-json). There is a demo repo [here](https://github.com/njlr/buckaroo-nholmann-json-example).
If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can use the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json). Please see the vcpkg project for any issues regarding the packaging. If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can use the [nlohmann-json package](https://github.com/Microsoft/vcpkg/tree/master/ports/nlohmann-json). Please see the vcpkg project for any issues regarding the packaging.
@ -165,6 +169,8 @@ If you are using [CocoaPods](https://cocoapods.org), you can use the library by
If you are using [NuGet](https://www.nuget.org), you can use the package [nlohmann.json](https://www.nuget.org/packages/nlohmann.json/). Please check [this extensive description](https://github.com/nlohmann/json/issues/1132#issuecomment-452250255) on how to use the package. Please files issues [here](https://github.com/hnkb/nlohmann-json-nuget/issues). If you are using [NuGet](https://www.nuget.org), you can use the package [nlohmann.json](https://www.nuget.org/packages/nlohmann.json/). Please check [this extensive description](https://github.com/nlohmann/json/issues/1132#issuecomment-452250255) on how to use the package. Please files issues [here](https://github.com/hnkb/nlohmann-json-nuget/issues).
If you are using [conda](https://conda.io/), you can use the package [nlohmann_json](https://github.com/conda-forge/nlohmann_json-feedstock) from [conda-forge](https://conda-forge.org) executing `conda install -c conda-forge nlohmann_json`. Please file issues [here](https://github.com/conda-forge/nlohmann_json-feedstock/issues).
## Examples ## Examples
Beside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5338e282d1d02bed389d852dd670d98d.html#a5338e282d1d02bed389d852dd670d98d)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)). Beside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5338e282d1d02bed389d852dd670d98d.html#a5338e282d1d02bed389d852dd670d98d)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)).
@ -615,7 +621,7 @@ json j_patch = R"({
})"_json; })"_json;
// apply the patch // apply the patch
j_original.merge_patch(j_patch); j_document.merge_patch(j_patch);
// { // {
// "a": "z", // "a": "z",
// "c": { // "c": {
@ -747,7 +753,7 @@ Likewise, when calling `get<your_type>()` or `get_to(your_type&)`, the `from_jso
Some important things: Some important things:
* Those methods **MUST** be in your type's namespace (which can be the global namespace), or the library will not be able to locate them (in this example, they are in namespace `ns`, where `person` is defined). * Those methods **MUST** be in your type's namespace (which can be the global namespace), or the library will not be able to locate them (in this example, they are in namespace `ns`, where `person` is defined).
* Those methods **MUST** be available (e.g., properly headers must be included) everywhere you use these conversions. Look at [issue 1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise. * Those methods **MUST** be available (e.g., proper headers must be included) everywhere you use these conversions. Look at [issue 1108](https://github.com/nlohmann/json/issues/1108) for errors that may occur otherwise.
* When using `get<your_type>()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.) * When using `get<your_type>()`, `your_type` **MUST** be [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible). (There is a way to bypass this requirement described later.)
* In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a93403e803947b86f4da2d1fb3345cf2c.html#a93403e803947b86f4da2d1fb3345cf2c) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior. * In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a93403e803947b86f4da2d1fb3345cf2c.html#a93403e803947b86f4da2d1fb3345cf2c) to access the object values rather than `operator[]`. In case a key does not exist, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior.
* You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these. * You do not need to add serializers or deserializers for STL types like `std::vector`: the library already implements these.
@ -915,7 +921,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM( TaskState, {
{TS_STOPPED, "stopped"}, {TS_STOPPED, "stopped"},
{TS_RUNNING, "running"}, {TS_RUNNING, "running"},
{TS_COMPLETED, "completed"}, {TS_COMPLETED, "completed"},
}); })
``` ```
The `NLOHMANN_JSON_SERIALIZE_ENUM()` macro declares a set of `to_json()` / `from_json()` functions for type `TaskState` while avoiding repetition and boilerplate serilization code. The `NLOHMANN_JSON_SERIALIZE_ENUM()` macro declares a set of `to_json()` / `from_json()` functions for type `TaskState` while avoiding repetition and boilerplate serilization code.
@ -1034,17 +1040,14 @@ The following compilers are currently used in continuous integration at [Travis]
| Clang 4.0.1 | Ubuntu 14.04.1 LTS | clang version 4.0.1-svn305264-1~exp1 (branches/release_40) | | Clang 4.0.1 | Ubuntu 14.04.1 LTS | clang version 4.0.1-svn305264-1~exp1 (branches/release_40) |
| Clang 5.0.2 | Ubuntu 14.04.1 LTS | clang version 5.0.2-svn328729-1~exp1~20180509123505.100 (branches/release_50) | | Clang 5.0.2 | Ubuntu 14.04.1 LTS | clang version 5.0.2-svn328729-1~exp1~20180509123505.100 (branches/release_50) |
| Clang 6.0.1 | Ubuntu 14.04.1 LTS | clang version 6.0.1-svn334776-1~exp1~20180726133705.85 (branches/release_60) | | Clang 6.0.1 | Ubuntu 14.04.1 LTS | clang version 6.0.1-svn334776-1~exp1~20180726133705.85 (branches/release_60) |
| Clang Xcode 6.4 | OSX 10.10.5 | Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn) | | Clang 7.0.1 | Ubuntu 14.04.1 LTS | clang version 7.0.1-svn348686-1~exp1~20181213084532.54 (branches/release_70) |
| Clang Xcode 7.3 | OSX 10.11.6 | Apple LLVM version 7.3.0 (clang-703.0.31) |
| Clang Xcode 8.0 | OSX 10.11.6 | Apple LLVM version 8.0.0 (clang-800.0.38) |
| Clang Xcode 8.1 | OSX 10.12.6 | Apple LLVM version 8.0.0 (clang-800.0.42.1) |
| Clang Xcode 8.2 | OSX 10.12.6 | Apple LLVM version 8.0.0 (clang-800.0.42.1) |
| Clang Xcode 8.3 | OSX 10.11.6 | Apple LLVM version 8.1.0 (clang-802.0.38) | | Clang Xcode 8.3 | OSX 10.11.6 | Apple LLVM version 8.1.0 (clang-802.0.38) |
| Clang Xcode 9.0 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.37) | | Clang Xcode 9.0 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.37) |
| Clang Xcode 9.1 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.38) | | Clang Xcode 9.1 | OSX 10.12.6 | Apple LLVM version 9.0.0 (clang-900.0.38) |
| Clang Xcode 9.2 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.1) | | Clang Xcode 9.2 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.1) |
| Clang Xcode 9.3 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.2) | | Clang Xcode 9.3 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.2) |
| Clang Xcode 10.0 | OSX 10.13.3 | Apple LLVM version 10.0.0 (clang-1000.11.45.2) | | Clang Xcode 10.0 | OSX 10.13.3 | Apple LLVM version 10.0.0 (clang-1000.11.45.2) |
| Clang Xcode 10.1 | OSX 10.13.3 | Apple LLVM version 10.0.0 (clang-1000.11.45.5) |
| Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25420.1, MSVC 19.0.24215.1 | | Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25420.1, MSVC 19.0.24215.1 |
| Visual Studio 2017 | Windows Server 2016 | Microsoft (R) Build Engine version 15.7.180.61344, MSVC 19.14.26433.0 | | Visual Studio 2017 | Windows Server 2016 | Microsoft (R) Build Engine version 15.7.180.61344, MSVC 19.14.26433.0 |

View file

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.1) cmake_minimum_required(VERSION 3.8)
project(JSON_Benchmarks LANGUAGES CXX) project(JSON_Benchmarks LANGUAGES CXX)
# set compiler flags # set compiler flags

View file

@ -1,4 +1,4 @@
# Doxyfile 1.8.15 # Doxyfile 1.8.16
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Project related configuration options # Project related configuration options
@ -38,6 +38,7 @@ OPTIMIZE_OUTPUT_FOR_C = NO
OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_OUTPUT_JAVA = NO
OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_FOR_FORTRAN = NO
OPTIMIZE_OUTPUT_VHDL = NO OPTIMIZE_OUTPUT_VHDL = NO
OPTIMIZE_OUTPUT_SLICE = NO
EXTENSION_MAPPING = EXTENSION_MAPPING =
MARKDOWN_SUPPORT = YES MARKDOWN_SUPPORT = YES
TOC_INCLUDE_HEADINGS = 0 TOC_INCLUDE_HEADINGS = 0
@ -141,7 +142,7 @@ USE_HTAGS = NO
VERBATIM_HEADERS = NO VERBATIM_HEADERS = NO
CLANG_ASSISTED_PARSING = YES CLANG_ASSISTED_PARSING = YES
CLANG_OPTIONS = -std=c++11 CLANG_OPTIONS = -std=c++11
CLANG_COMPILATION_DATABASE_PATH = 0 CLANG_DATABASE_PATH =
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index # Configuration options related to the alphabetical class index
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@ -214,6 +215,7 @@ GENERATE_LATEX = NO
LATEX_OUTPUT = latex LATEX_OUTPUT = latex
LATEX_CMD_NAME = latex LATEX_CMD_NAME = latex
MAKEINDEX_CMD_NAME = makeindex MAKEINDEX_CMD_NAME = makeindex
LATEX_MAKEINDEX_CMD = \makeindex
COMPACT_LATEX = NO COMPACT_LATEX = NO
PAPER_TYPE = a4 PAPER_TYPE = a4
EXTRA_PACKAGES = EXTRA_PACKAGES =
@ -228,6 +230,7 @@ LATEX_HIDE_INDICES = NO
LATEX_SOURCE_CODE = NO LATEX_SOURCE_CODE = NO
LATEX_BIB_STYLE = plain LATEX_BIB_STYLE = plain
LATEX_TIMESTAMP = NO LATEX_TIMESTAMP = NO
LATEX_EMOJI_DIRECTORY =
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the RTF output # Configuration options related to the RTF output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
@ -252,6 +255,7 @@ MAN_LINKS = NO
GENERATE_XML = YES GENERATE_XML = YES
XML_OUTPUT = xml XML_OUTPUT = xml
XML_PROGRAMLISTING = YES XML_PROGRAMLISTING = YES
XML_NS_MEMB_FILE_SCOPE = NO
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
# Configuration options related to the DOCBOOK output # Configuration options related to the DOCBOOK output
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------

17
doc/examples/contains.cpp Normal file
View file

@ -0,0 +1,17 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// create some JSON values
json j_object = R"( {"key": "value"} )"_json;
json j_array = R"( [1, 2, 3] )"_json;
// call contains
std::cout << std::boolalpha <<
"j_object contains 'key': " << j_object.contains("key") << '\n' <<
"j_object contains 'another': " << j_object.contains("another") << '\n' <<
"j_array contains 'key': " << j_array.contains("key") << std::endl;
}

View file

@ -0,0 +1 @@
<a target="_blank" href="https://wandbox.org/permlink/iHSlXjtjhgO9Q1Tw"><b>online</b></a>

View file

@ -0,0 +1,3 @@
j_object contains 'key': true
j_object contains 'another': false
j_array contains 'key': false

View file

@ -0,0 +1,20 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// different JSON Pointers
json::json_pointer ptr0;
json::json_pointer ptr1("");
json::json_pointer ptr2("/foo");
json::json_pointer ptr3("/foo/0");
// call empty()
std::cout << std::boolalpha
<< ptr0 << ": " << ptr0.empty() << '\n'
<< ptr1 << ": " << ptr1.empty() << '\n'
<< ptr2 << ": " << ptr2.empty() << '\n'
<< ptr3 << ": " << ptr3.empty() << std::endl;
}

View file

@ -0,0 +1 @@
<a target="_blank" href="https://wandbox.org/permlink/pqG2Q8bmj9SvSX0i"><b>online</b></a>

View file

@ -0,0 +1,4 @@
"": true
"": true
"/foo": false
"/foo/0": false

View file

@ -0,0 +1,18 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// different JSON Pointers
json::json_pointer ptr1("");
json::json_pointer ptr2("/foo");
json::json_pointer ptr3("/foo/0");
// call parent_pointer()
std::cout << std::boolalpha
<< "parent of " << ptr1 << " is " << ptr1.parent_pointer() << '\n'
<< "parent of " << ptr2 << " is " << ptr2.parent_pointer() << '\n'
<< "parent of " << ptr3 << " is " << ptr3.parent_pointer() << std::endl;
}

View file

@ -0,0 +1 @@
<a target="_blank" href="https://wandbox.org/permlink/yweqBQ8bAC6pcn68"><b>online</b></a>

View file

@ -0,0 +1,3 @@
parent of "" is ""
parent of "/foo" is ""
parent of "/foo/0" is "/foo"

View file

@ -0,0 +1,21 @@
#include <iostream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
int main()
{
// create empty JSON Pointer
json::json_pointer ptr;
std::cout << ptr << '\n';
// call push_back()
ptr.push_back("foo");
std::cout << ptr << '\n';
ptr.push_back("0");
std::cout << ptr << '\n';
ptr.push_back("bar");
std::cout << ptr << '\n';
}

View file

@ -0,0 +1 @@
<a target="_blank" href="https://wandbox.org/permlink/kLC7IUvqQ6XJCeG9"><b>online</b></a>

View file

@ -0,0 +1,4 @@
""
"/foo"
"/foo/0"
"/foo/0/bar"

View file

@ -57,6 +57,7 @@ These pages contain the API documentation of JSON for Modern C++, a C++11 header
- @link nlohmann::basic_json::number_integer_t signed integers @endlink - @link nlohmann::basic_json::number_integer_t signed integers @endlink
- @link nlohmann::basic_json::number_unsigned_t unsigned integers @endlink - @link nlohmann::basic_json::number_unsigned_t unsigned integers @endlink
- @link nlohmann::basic_json::number_float_t floating-point @endlink - @link nlohmann::basic_json::number_float_t floating-point @endlink
- @link nlohmann::json_pointer JSON Pointer @endlink
# Container function overview # Container function overview

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include <array> // array
#include <cassert> // assert #include <cassert> // assert
#include <ciso646> // or, and, not #include <ciso646> // or, and, not
#include <cmath> // signbit, isfinite #include <cmath> // signbit, isfinite
@ -49,10 +50,10 @@ struct diyfp // f * 2^e
{ {
static constexpr int kPrecision = 64; // = q static constexpr int kPrecision = 64; // = q
uint64_t f = 0; std::uint64_t f = 0;
int e = 0; int e = 0;
constexpr diyfp(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
@ -97,23 +98,23 @@ struct diyfp // f * 2^e
// //
// = p_lo + 2^64 p_hi // = p_lo + 2^64 p_hi
const uint64_t u_lo = x.f & 0xFFFFFFFF; const std::uint64_t u_lo = x.f & 0xFFFFFFFFu;
const uint64_t u_hi = x.f >> 32; const std::uint64_t u_hi = x.f >> 32u;
const uint64_t v_lo = y.f & 0xFFFFFFFF; const std::uint64_t v_lo = y.f & 0xFFFFFFFFu;
const uint64_t v_hi = y.f >> 32; const std::uint64_t v_hi = y.f >> 32u;
const uint64_t p0 = u_lo * v_lo; const std::uint64_t p0 = u_lo * v_lo;
const uint64_t p1 = u_lo * v_hi; const std::uint64_t p1 = u_lo * v_hi;
const uint64_t p2 = u_hi * v_lo; const std::uint64_t p2 = u_hi * v_lo;
const uint64_t p3 = u_hi * v_hi; const std::uint64_t p3 = u_hi * v_hi;
const uint64_t p0_hi = p0 >> 32; const std::uint64_t p0_hi = p0 >> 32u;
const uint64_t p1_lo = p1 & 0xFFFFFFFF; const std::uint64_t p1_lo = p1 & 0xFFFFFFFFu;
const uint64_t p1_hi = p1 >> 32; const std::uint64_t p1_hi = p1 >> 32u;
const uint64_t p2_lo = p2 & 0xFFFFFFFF; const std::uint64_t p2_lo = p2 & 0xFFFFFFFFu;
const uint64_t p2_hi = p2 >> 32; const std::uint64_t p2_hi = p2 >> 32u;
uint64_t Q = p0_hi + p1_lo + p2_lo; std::uint64_t Q = p0_hi + p1_lo + p2_lo;
// The full product might now be computed as // The full product might now be computed as
// //
@ -124,9 +125,9 @@ 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 += uint64_t{1} << (64 - 32 - 1); // round, ties up Q += std::uint64_t{1} << (64u - 32u - 1u); // round, ties up
const uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32); const std::uint64_t h = p3 + p2_hi + p1_hi + (Q >> 32u);
return {h, x.e + y.e + 64}; return {h, x.e + y.e + 64};
} }
@ -139,9 +140,9 @@ struct diyfp // f * 2^e
{ {
assert(x.f != 0); assert(x.f != 0);
while ((x.f >> 63) == 0) while ((x.f >> 63u) == 0)
{ {
x.f <<= 1; x.f <<= 1u;
x.e--; x.e--;
} }
@ -195,15 +196,15 @@ boundaries compute_boundaries(FloatType value)
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 uint64_t kHiddenBit = 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, uint32_t, uint64_t >::type; using bits_type = typename std::conditional<kPrecision == 24, std::uint32_t, std::uint64_t >::type;
const uint64_t bits = reinterpret_bits<bits_type>(value); const std::uint64_t bits = reinterpret_bits<bits_type>(value);
const uint64_t E = bits >> (kPrecision - 1); const std::uint64_t E = bits >> (kPrecision - 1);
const uint64_t F = bits & (kHiddenBit - 1); const std::uint64_t F = bits & (kHiddenBit - 1);
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);
@ -229,7 +230,7 @@ boundaries compute_boundaries(FloatType value)
// -----------------+------+------+-------------+-------------+--- (B) // -----------------+------+------+-------------+-------------+--- (B)
// v- m- v m+ v+ // v- m- v m+ v+
const bool lower_boundary_is_closer = (F == 0 and E > 1); const bool lower_boundary_is_closer = F == 0 and 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)
@ -304,7 +305,7 @@ constexpr int kGamma = -32;
struct cached_power // c = f * 2^e ~= 10^k struct cached_power // c = f * 2^e ~= 10^k
{ {
uint64_t f; std::uint64_t f;
int e; int e;
int k; int k;
}; };
@ -368,91 +369,92 @@ inline cached_power get_cached_power_for_binary_exponent(int e)
// NB: // NB:
// Actually this function returns c, such that -60 <= e_c + e + 64 <= -34. // Actually this function returns c, such that -60 <= e_c + e + 64 <= -34.
constexpr int kCachedPowersSize = 79;
constexpr int kCachedPowersMinDecExp = -300; constexpr int kCachedPowersMinDecExp = -300;
constexpr int kCachedPowersDecStep = 8; constexpr int kCachedPowersDecStep = 8;
static constexpr cached_power 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
@ -466,10 +468,9 @@ inline cached_power get_cached_power_for_binary_exponent(int e)
const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep; const int index = (-kCachedPowersMinDecExp + k + (kCachedPowersDecStep - 1)) / kCachedPowersDecStep;
assert(index >= 0); assert(index >= 0);
assert(index < kCachedPowersSize); assert(static_cast<std::size_t>(index) < kCachedPowers.size());
static_cast<void>(kCachedPowersSize); // Fix warning.
const cached_power cached = kCachedPowers[index]; const cached_power cached = kCachedPowers[static_cast<std::size_t>(index)];
assert(kAlpha <= cached.e + e + 64); assert(kAlpha <= cached.e + e + 64);
assert(kGamma >= cached.e + e + 64); assert(kGamma >= cached.e + e + 64);
@ -480,7 +481,7 @@ inline cached_power get_cached_power_for_binary_exponent(int e)
For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k. For n != 0, returns k, such that pow10 := 10^(k-1) <= n < 10^k.
For n == 0, returns 1 and sets pow10 := 1. For n == 0, returns 1 and sets pow10 := 1.
*/ */
inline int find_largest_pow10(const uint32_t n, uint32_t& pow10) inline int find_largest_pow10(const std::uint32_t n, std::uint32_t& pow10)
{ {
// LCOV_EXCL_START // LCOV_EXCL_START
if (n >= 1000000000) if (n >= 1000000000)
@ -536,8 +537,8 @@ inline int find_largest_pow10(const uint32_t n, uint32_t& pow10)
} }
} }
inline void grisu2_round(char* buf, int len, uint64_t dist, uint64_t delta, inline void grisu2_round(char* buf, int len, std::uint64_t dist, std::uint64_t delta,
uint64_t rest, uint64_t ten_k) std::uint64_t rest, std::uint64_t ten_k)
{ {
assert(len >= 1); assert(len >= 1);
assert(dist <= delta); assert(dist <= delta);
@ -598,8 +599,8 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
assert(M_plus.e >= kAlpha); assert(M_plus.e >= kAlpha);
assert(M_plus.e <= kGamma); assert(M_plus.e <= kGamma);
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)
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):
// //
@ -608,10 +609,10 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// = ((p1 ) * 2^-e + (p2 )) * 2^e // = ((p1 ) * 2^-e + (p2 )) * 2^e
// = p1 + p2 * 2^e // = p1 + p2 * 2^e
const diyfp one(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<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.)
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)
// //
@ -619,7 +620,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
assert(p1 > 0); assert(p1 > 0);
uint32_t pow10; std::uint32_t pow10;
const int k = find_largest_pow10(p1, pow10); const int k = find_largest_pow10(p1, pow10);
// 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1) // 10^(k-1) <= p1 < 10^k, pow10 = 10^(k-1)
@ -647,8 +648,8 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k) // M+ = buffer * 10^n + (p1 + p2 * 2^e) (buffer = 0 for n = k)
// pow10 = 10^(n-1) <= p1 < 10^n // pow10 = 10^(n-1) <= p1 < 10^n
// //
const uint32_t d = p1 / pow10; // d = p1 div 10^(n-1) const std::uint32_t d = p1 / pow10; // d = p1 div 10^(n-1)
const uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1) const std::uint32_t r = p1 % pow10; // r = p1 mod 10^(n-1)
// //
// M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e // M+ = buffer * 10^n + (d * 10^(n-1) + r) + p2 * 2^e
// = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e) // = (buffer * 10 + d) * 10^(n-1) + (r + p2 * 2^e)
@ -673,7 +674,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// Note: // Note:
// Since rest and delta share the same exponent e, it suffices to // Since rest and delta share the same exponent e, it suffices to
// compare the significands. // compare the significands.
const uint64_t rest = (uint64_t{p1} << -one.e) + p2; const std::uint64_t rest = (std::uint64_t{p1} << -one.e) + p2;
if (rest <= delta) if (rest <= delta)
{ {
// V = buffer * 10^n, with M- <= V <= M+. // V = buffer * 10^n, with M- <= V <= M+.
@ -689,7 +690,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// //
// 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e // 10^n = (10^n * 2^-e) * 2^e = ulp * 2^e
// //
const uint64_t ten_n = uint64_t{pow10} << -one.e; const std::uint64_t ten_n = std::uint64_t{pow10} << -one.e;
grisu2_round(buffer, length, dist, delta, rest, ten_n); grisu2_round(buffer, length, dist, delta, rest, ten_n);
return; return;
@ -751,10 +752,10 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e // = buffer * 10^-m + 10^-m * (1/10 * (10 * p2) ) * 2^e
// = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e // = buffer * 10^-m + 10^-m * (1/10 * ((10*p2 div 2^-e) * 2^-e + (10*p2 mod 2^-e)) * 2^e
// //
assert(p2 <= UINT64_MAX / 10); assert(p2 <= std::numeric_limits<std::uint64_t>::max() / 10);
p2 *= 10; p2 *= 10;
const 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 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))
@ -794,7 +795,7 @@ inline void grisu2_digit_gen(char* buffer, int& length, int& decimal_exponent,
// //
// 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e // 10^m * 10^-m = 1 = 2^-e * 2^e = ten_m * 2^e
// //
const uint64_t ten_m = one.f; const std::uint64_t ten_m = one.f;
grisu2_round(buffer, length, dist, delta, p2, ten_m); grisu2_round(buffer, length, dist, delta, p2, ten_m);
// By construction this algorithm generates the shortest possible decimal // By construction this algorithm generates the shortest possible decimal
@ -929,7 +930,7 @@ inline char* append_exponent(char* buf, int e)
*buf++ = '+'; *buf++ = '+';
} }
auto k = static_cast<uint32_t>(e); auto k = static_cast<std::uint32_t>(e);
if (k < 10) if (k < 10)
{ {
// Always print at least two digits in the exponent. // Always print at least two digits in the exponent.

View file

@ -1,17 +1,19 @@
#pragma once #pragma once
#include <algorithm> // copy
#include <ciso646> // or, and, not #include <ciso646> // or, and, not
#include <iterator> // begin, end #include <iterator> // begin, end
#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/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/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
#include <nlohmann/detail/iterators/iteration_proxy.hpp>
namespace nlohmann namespace nlohmann
{ {

View file

@ -102,12 +102,12 @@ json.exception.parse_error.114 | parse error: Unsupported BSON record type 0x0F
@liveexample{The following code shows how a `parse_error` exception can be @liveexample{The following code shows how a `parse_error` exception can be
caught.,parse_error} caught.,parse_error}
@sa @ref exception for the base class of the library exceptions @sa - @ref exception for the base class of the library exceptions
@sa @ref invalid_iterator for exceptions indicating errors with iterators @sa - @ref invalid_iterator for exceptions indicating errors with iterators
@sa @ref type_error for exceptions indicating executing a member function with @sa - @ref type_error for exceptions indicating executing a member function with
a wrong type a wrong type
@sa @ref out_of_range for exceptions indicating access out of the defined range @sa - @ref out_of_range for exceptions indicating access out of the defined range
@sa @ref other_error for exceptions indicating other library errors @sa - @ref other_error for exceptions indicating other library errors
@since version 3.0.0 @since version 3.0.0
*/ */
@ -117,7 +117,7 @@ class parse_error : public exception
/*! /*!
@brief create a parse error exception @brief create a parse error exception
@param[in] id_ the id of the exception @param[in] id_ the id of the exception
@param[in] position the position where the error occurred (or with @param[in] pos the position where the error occurred (or with
chars_read_total=0 if the position cannot be chars_read_total=0 if the position cannot be
determined) determined)
@param[in] what_arg the explanatory string @param[in] what_arg the explanatory string
@ -188,12 +188,12 @@ json.exception.invalid_iterator.214 | cannot get value | Cannot get value for it
@liveexample{The following code shows how an `invalid_iterator` exception can be @liveexample{The following code shows how an `invalid_iterator` exception can be
caught.,invalid_iterator} caught.,invalid_iterator}
@sa @ref exception for the base class of the library exceptions @sa - @ref exception for the base class of the library exceptions
@sa @ref parse_error for exceptions indicating a parse error @sa - @ref parse_error for exceptions indicating a parse error
@sa @ref type_error for exceptions indicating executing a member function with @sa - @ref type_error for exceptions indicating executing a member function with
a wrong type a wrong type
@sa @ref out_of_range for exceptions indicating access out of the defined range @sa - @ref out_of_range for exceptions indicating access out of the defined range
@sa @ref other_error for exceptions indicating other library errors @sa - @ref other_error for exceptions indicating other library errors
@since version 3.0.0 @since version 3.0.0
*/ */
@ -223,7 +223,7 @@ name / id | example message | description
----------------------------- | --------------- | ------------------------- ----------------------------- | --------------- | -------------------------
json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead. json.exception.type_error.301 | cannot create object from initializer list | To create an object from an initializer list, the initializer list must consist only of a list of pairs whose first element is a string. When this constraint is violated, an array is created instead.
json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types. json.exception.type_error.302 | type must be object, but is array | During implicit or explicit value conversion, the JSON type must be compatible to the target type. For instance, a JSON string can only be converted into string types, but not into numbers or boolean types.
json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t&. json.exception.type_error.303 | incompatible ReferenceType for get_ref, actual type is object | To retrieve a reference to a value stored in a @ref basic_json object with @ref get_ref, the type of the reference must match the value type. For instance, for a JSON array, the @a ReferenceType must be @ref array_t &.
json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types. json.exception.type_error.304 | cannot use at() with string | The @ref at() member functions can only be executed for certain JSON types.
json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types. json.exception.type_error.305 | cannot use operator[] with string | The @ref operator[] member functions can only be executed for certain JSON types.
json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types. json.exception.type_error.306 | cannot use value() with string | The @ref value() member functions can only be executed for certain JSON types.
@ -242,11 +242,11 @@ json.exception.type_error.317 | JSON value cannot be serialized to requested for
@liveexample{The following code shows how a `type_error` exception can be @liveexample{The following code shows how a `type_error` exception can be
caught.,type_error} caught.,type_error}
@sa @ref exception for the base class of the library exceptions @sa - @ref exception for the base class of the library exceptions
@sa @ref parse_error for exceptions indicating a parse error @sa - @ref parse_error for exceptions indicating a parse error
@sa @ref invalid_iterator for exceptions indicating errors with iterators @sa - @ref invalid_iterator for exceptions indicating errors with iterators
@sa @ref out_of_range for exceptions indicating access out of the defined range @sa - @ref out_of_range for exceptions indicating access out of the defined range
@sa @ref other_error for exceptions indicating other library errors @sa - @ref other_error for exceptions indicating other library errors
@since version 3.0.0 @since version 3.0.0
*/ */
@ -287,12 +287,12 @@ json.exception.out_of_range.409 | BSON key cannot contain code point U+0000 (at
@liveexample{The following code shows how an `out_of_range` exception can be @liveexample{The following code shows how an `out_of_range` exception can be
caught.,out_of_range} caught.,out_of_range}
@sa @ref exception for the base class of the library exceptions @sa - @ref exception for the base class of the library exceptions
@sa @ref parse_error for exceptions indicating a parse error @sa - @ref parse_error for exceptions indicating a parse error
@sa @ref invalid_iterator for exceptions indicating errors with iterators @sa - @ref invalid_iterator for exceptions indicating errors with iterators
@sa @ref type_error for exceptions indicating executing a member function with @sa - @ref type_error for exceptions indicating executing a member function with
a wrong type a wrong type
@sa @ref other_error for exceptions indicating other library errors @sa - @ref other_error for exceptions indicating other library errors
@since version 3.0.0 @since version 3.0.0
*/ */
@ -321,12 +321,12 @@ name / id | example message | description
------------------------------ | --------------- | ------------------------- ------------------------------ | --------------- | -------------------------
json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed.
@sa @ref exception for the base class of the library exceptions @sa - @ref exception for the base class of the library exceptions
@sa @ref parse_error for exceptions indicating a parse error @sa - @ref parse_error for exceptions indicating a parse error
@sa @ref invalid_iterator for exceptions indicating errors with iterators @sa - @ref invalid_iterator for exceptions indicating errors with iterators
@sa @ref type_error for exceptions indicating executing a member function with @sa - @ref type_error for exceptions indicating executing a member function with
a wrong type a wrong type
@sa @ref out_of_range for exceptions indicating access out of the defined range @sa - @ref out_of_range for exceptions indicating access out of the defined range
@liveexample{The following code shows how an `other_error` exception can be @liveexample{The following code shows how an `other_error` exception can be
caught.,other_error} caught.,other_error}

View file

@ -13,9 +13,9 @@
#include <string> // char_traits, string #include <string> // char_traits, string
#include <utility> // make_pair, move #include <utility> // make_pair, move
#include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/input/input_adapters.hpp> #include <nlohmann/detail/input/input_adapters.hpp>
#include <nlohmann/detail/input/json_sax.hpp> #include <nlohmann/detail/input/json_sax.hpp>
#include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/is_sax.hpp> #include <nlohmann/detail/meta/is_sax.hpp>
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
@ -52,6 +52,13 @@ class binary_reader
assert(ia); assert(ia);
} }
// make class move-only
binary_reader(const binary_reader&) = delete;
binary_reader(binary_reader&&) = default;
binary_reader& operator=(const binary_reader&) = delete;
binary_reader& operator=(binary_reader&&) = default;
~binary_reader() = default;
/*! /*!
@param[in] format the binary format to parse @param[in] format the binary format to parse
@param[in] sax_ a SAX event processor @param[in] sax_ a SAX event processor
@ -84,10 +91,8 @@ class binary_reader
result = parse_ubjson_internal(); result = parse_ubjson_internal();
break; break;
// LCOV_EXCL_START default: // LCOV_EXCL_LINE
default: assert(false); // LCOV_EXCL_LINE
assert(false);
// LCOV_EXCL_STOP
} }
// strict mode: next byte must be EOF // strict mode: next byte must be EOF
@ -121,7 +126,7 @@ class binary_reader
*/ */
static constexpr bool little_endianess(int num = 1) noexcept static constexpr bool little_endianess(int num = 1) noexcept
{ {
return (*reinterpret_cast<char*>(&num) == 1); return *reinterpret_cast<char*>(&num) == 1;
} }
private: private:
@ -263,9 +268,9 @@ class binary_reader
default: // anything else not supported (yet) default: // anything else not supported (yet)
{ {
char cr[3]; std::array<char, 3> cr{};
(std::snprintf)(cr, sizeof(cr), "%.2hhX", static_cast<unsigned char>(element_type)); (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(element_type));
return sax->parse_error(element_type_parse_position, std::string(cr), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr))); return sax->parse_error(element_type_parse_position, std::string(cr.data()), parse_error::create(114, element_type_parse_position, "Unsupported BSON record type 0x" + std::string(cr.data())));
} }
} }
} }
@ -298,12 +303,9 @@ class binary_reader
return false; return false;
} }
if (not is_array) if (not is_array and not sax->key(key))
{ {
if (not sax->key(key)) return false;
{
return false;
}
} }
if (JSON_UNLIKELY(not parse_bson_element_internal(element_type, element_type_parse_position))) if (JSON_UNLIKELY(not parse_bson_element_internal(element_type, element_type_parse_position)))
@ -388,25 +390,25 @@ class binary_reader
case 0x18: // Unsigned integer (one-byte uint8_t follows) case 0x18: // Unsigned integer (one-byte uint8_t follows)
{ {
uint8_t number; std::uint8_t number;
return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
} }
case 0x19: // Unsigned integer (two-byte uint16_t follows) case 0x19: // Unsigned integer (two-byte uint16_t follows)
{ {
uint16_t number; std::uint16_t number;
return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
} }
case 0x1A: // Unsigned integer (four-byte uint32_t follows) case 0x1A: // Unsigned integer (four-byte uint32_t follows)
{ {
uint32_t number; std::uint32_t number;
return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
} }
case 0x1B: // Unsigned integer (eight-byte uint64_t follows) case 0x1B: // Unsigned integer (eight-byte uint64_t follows)
{ {
uint64_t number; std::uint64_t number;
return get_number(input_format_t::cbor, number) and sax->number_unsigned(number); return get_number(input_format_t::cbor, number) and sax->number_unsigned(number);
} }
@ -435,29 +437,29 @@ class binary_reader
case 0x35: case 0x35:
case 0x36: case 0x36:
case 0x37: case 0x37:
return sax->number_integer(static_cast<int8_t>(0x20 - 1 - current)); return sax->number_integer(static_cast<std::int8_t>(0x20 - 1 - current));
case 0x38: // Negative integer (one-byte uint8_t follows) case 0x38: // Negative integer (one-byte uint8_t follows)
{ {
uint8_t number; std::uint8_t number;
return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number); return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
} }
case 0x39: // Negative integer -1-n (two-byte uint16_t follows) case 0x39: // Negative integer -1-n (two-byte uint16_t follows)
{ {
uint16_t number; std::uint16_t number;
return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number); return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
} }
case 0x3A: // Negative integer -1-n (four-byte uint32_t follows) case 0x3A: // Negative integer -1-n (four-byte uint32_t follows)
{ {
uint32_t number; std::uint32_t number;
return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number); return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) - number);
} }
case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows) case 0x3B: // Negative integer -1-n (eight-byte uint64_t follows)
{ {
uint64_t number; std::uint64_t number;
return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1) return get_number(input_format_t::cbor, number) and sax->number_integer(static_cast<number_integer_t>(-1)
- static_cast<number_integer_t>(number)); - static_cast<number_integer_t>(number));
} }
@ -522,29 +524,29 @@ class binary_reader
case 0x95: case 0x95:
case 0x96: case 0x96:
case 0x97: case 0x97:
return get_cbor_array(static_cast<std::size_t>(current & 0x1F)); return get_cbor_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
case 0x98: // array (one-byte uint8_t for n follows) case 0x98: // array (one-byte uint8_t for n follows)
{ {
uint8_t len; std::uint8_t len;
return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len)); return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
} }
case 0x99: // array (two-byte uint16_t for n follow) case 0x99: // array (two-byte uint16_t for n follow)
{ {
uint16_t len; std::uint16_t len;
return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len)); return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
} }
case 0x9A: // array (four-byte uint32_t for n follow) case 0x9A: // array (four-byte uint32_t for n follow)
{ {
uint32_t len; std::uint32_t len;
return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len)); return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
} }
case 0x9B: // array (eight-byte uint64_t for n follow) case 0x9B: // array (eight-byte uint64_t for n follow)
{ {
uint64_t len; std::uint64_t len;
return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len)); return get_number(input_format_t::cbor, len) and get_cbor_array(static_cast<std::size_t>(len));
} }
@ -576,29 +578,29 @@ class binary_reader
case 0xB5: case 0xB5:
case 0xB6: case 0xB6:
case 0xB7: case 0xB7:
return get_cbor_object(static_cast<std::size_t>(current & 0x1F)); return get_cbor_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x1Fu));
case 0xB8: // map (one-byte uint8_t for n follows) case 0xB8: // map (one-byte uint8_t for n follows)
{ {
uint8_t len; std::uint8_t len;
return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len)); return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
} }
case 0xB9: // map (two-byte uint16_t for n follow) case 0xB9: // map (two-byte uint16_t for n follow)
{ {
uint16_t len; std::uint16_t len;
return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len)); return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
} }
case 0xBA: // map (four-byte uint32_t for n follow) case 0xBA: // map (four-byte uint32_t for n follow)
{ {
uint32_t len; std::uint32_t len;
return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len)); return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
} }
case 0xBB: // map (eight-byte uint64_t for n follow) case 0xBB: // map (eight-byte uint64_t for n follow)
{ {
uint64_t len; std::uint64_t len;
return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len)); return get_number(input_format_t::cbor, len) and get_cbor_object(static_cast<std::size_t>(len));
} }
@ -638,11 +640,11 @@ class binary_reader
// without such support. An example of a small decoder for // without such support. An example of a small decoder for
// half-precision floating-point numbers in the C language // half-precision floating-point numbers in the C language
// is shown in Fig. 3. // is shown in Fig. 3.
const int half = (byte1 << 8) + byte2; const auto half = static_cast<unsigned int>((byte1 << 8u) + byte2);
const double val = [&half] const double val = [&half]
{ {
const int exp = (half >> 10) & 0x1F; const int exp = (half >> 10u) & 0x1Fu;
const int mant = half & 0x3FF; const unsigned int mant = half & 0x3FFu;
assert(0 <= exp and exp <= 32); assert(0 <= exp and exp <= 32);
assert(0 <= mant and mant <= 1024); assert(0 <= mant and mant <= 1024);
switch (exp) switch (exp)
@ -657,7 +659,7 @@ class binary_reader
return std::ldexp(mant + 1024, exp - 25); return std::ldexp(mant + 1024, exp - 25);
} }
}(); }();
return sax->number_float((half & 0x8000) != 0 return sax->number_float((half & 0x8000u) != 0
? static_cast<number_float_t>(-val) ? static_cast<number_float_t>(-val)
: static_cast<number_float_t>(val), ""); : static_cast<number_float_t>(val), "");
} }
@ -728,30 +730,30 @@ class binary_reader
case 0x76: case 0x76:
case 0x77: case 0x77:
{ {
return get_string(input_format_t::cbor, current & 0x1F, result); return get_string(input_format_t::cbor, static_cast<unsigned int>(current) & 0x1Fu, result);
} }
case 0x78: // UTF-8 string (one-byte uint8_t for n follows) case 0x78: // UTF-8 string (one-byte uint8_t for n follows)
{ {
uint8_t len; std::uint8_t len;
return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result); return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
} }
case 0x79: // UTF-8 string (two-byte uint16_t for n follow) case 0x79: // UTF-8 string (two-byte uint16_t for n follow)
{ {
uint16_t len; std::uint16_t len;
return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result); return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
} }
case 0x7A: // UTF-8 string (four-byte uint32_t for n follow) case 0x7A: // UTF-8 string (four-byte uint32_t for n follow)
{ {
uint32_t len; std::uint32_t len;
return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result); return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
} }
case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow) case 0x7B: // UTF-8 string (eight-byte uint64_t for n follow)
{ {
uint64_t len; std::uint64_t len;
return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result); return get_number(input_format_t::cbor, len) and get_string(input_format_t::cbor, len, result);
} }
@ -1026,7 +1028,7 @@ class binary_reader
case 0x8D: case 0x8D:
case 0x8E: case 0x8E:
case 0x8F: case 0x8F:
return get_msgpack_object(static_cast<std::size_t>(current & 0x0F)); return get_msgpack_object(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
// fixarray // fixarray
case 0x90: case 0x90:
@ -1045,7 +1047,7 @@ class binary_reader
case 0x9D: case 0x9D:
case 0x9E: case 0x9E:
case 0x9F: case 0x9F:
return get_msgpack_array(static_cast<std::size_t>(current & 0x0F)); return get_msgpack_array(static_cast<std::size_t>(static_cast<unsigned int>(current) & 0x0Fu));
// fixstr // fixstr
case 0xA0: case 0xA0:
@ -1108,49 +1110,49 @@ class binary_reader
case 0xCC: // uint 8 case 0xCC: // uint 8
{ {
uint8_t number; std::uint8_t number;
return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
} }
case 0xCD: // uint 16 case 0xCD: // uint 16
{ {
uint16_t number; std::uint16_t number;
return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
} }
case 0xCE: // uint 32 case 0xCE: // uint 32
{ {
uint32_t number; std::uint32_t number;
return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
} }
case 0xCF: // uint 64 case 0xCF: // uint 64
{ {
uint64_t number; std::uint64_t number;
return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number); return get_number(input_format_t::msgpack, number) and sax->number_unsigned(number);
} }
case 0xD0: // int 8 case 0xD0: // int 8
{ {
int8_t number; std::int8_t number;
return get_number(input_format_t::msgpack, number) and sax->number_integer(number); return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
} }
case 0xD1: // int 16 case 0xD1: // int 16
{ {
int16_t number; std::int16_t number;
return get_number(input_format_t::msgpack, number) and sax->number_integer(number); return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
} }
case 0xD2: // int 32 case 0xD2: // int 32
{ {
int32_t number; std::int32_t number;
return get_number(input_format_t::msgpack, number) and sax->number_integer(number); return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
} }
case 0xD3: // int 64 case 0xD3: // int 64
{ {
int64_t number; std::int64_t number;
return get_number(input_format_t::msgpack, number) and sax->number_integer(number); return get_number(input_format_t::msgpack, number) and sax->number_integer(number);
} }
@ -1164,25 +1166,25 @@ class binary_reader
case 0xDC: // array 16 case 0xDC: // array 16
{ {
uint16_t len; std::uint16_t len;
return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len)); return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len));
} }
case 0xDD: // array 32 case 0xDD: // array 32
{ {
uint32_t len; std::uint32_t len;
return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len)); return get_number(input_format_t::msgpack, len) and get_msgpack_array(static_cast<std::size_t>(len));
} }
case 0xDE: // map 16 case 0xDE: // map 16
{ {
uint16_t len; std::uint16_t len;
return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len)); return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len));
} }
case 0xDF: // map 32 case 0xDF: // map 32
{ {
uint32_t len; std::uint32_t len;
return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len)); return get_number(input_format_t::msgpack, len) and get_msgpack_object(static_cast<std::size_t>(len));
} }
@ -1219,7 +1221,7 @@ class binary_reader
case 0xFD: case 0xFD:
case 0xFE: case 0xFE:
case 0xFF: case 0xFF:
return sax->number_integer(static_cast<int8_t>(current)); return sax->number_integer(static_cast<std::int8_t>(current));
default: // anything else default: // anything else
{ {
@ -1282,24 +1284,24 @@ class binary_reader
case 0xBE: case 0xBE:
case 0xBF: case 0xBF:
{ {
return get_string(input_format_t::msgpack, current & 0x1F, result); return get_string(input_format_t::msgpack, static_cast<unsigned int>(current) & 0x1Fu, result);
} }
case 0xD9: // str 8 case 0xD9: // str 8
{ {
uint8_t len; std::uint8_t len;
return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result); return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);
} }
case 0xDA: // str 16 case 0xDA: // str 16
{ {
uint16_t len; std::uint16_t len;
return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result); return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);
} }
case 0xDB: // str 32 case 0xDB: // str 32
{ {
uint32_t len; std::uint32_t len;
return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result); return get_number(input_format_t::msgpack, len) and get_string(input_format_t::msgpack, len, result);
} }
@ -1397,7 +1399,7 @@ class binary_reader
{ {
if (get_char) if (get_char)
{ {
get(); // TODO: may we ignore N here? get(); // TODO(niels): may we ignore N here?
} }
if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value"))) if (JSON_UNLIKELY(not unexpect_eof(input_format_t::ubjson, "value")))
@ -1409,31 +1411,31 @@ class binary_reader
{ {
case 'U': case 'U':
{ {
uint8_t len; std::uint8_t len;
return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
} }
case 'i': case 'i':
{ {
int8_t len; std::int8_t len;
return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
} }
case 'I': case 'I':
{ {
int16_t len; std::int16_t len;
return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
} }
case 'l': case 'l':
{ {
int32_t len; std::int32_t len;
return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
} }
case 'L': case 'L':
{ {
int64_t len; std::int64_t len;
return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result); return get_number(input_format_t::ubjson, len) and get_string(input_format_t::ubjson, len, result);
} }
@ -1453,7 +1455,7 @@ class binary_reader
{ {
case 'U': case 'U':
{ {
uint8_t number; std::uint8_t number;
if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))
{ {
return false; return false;
@ -1464,7 +1466,7 @@ class binary_reader
case 'i': case 'i':
{ {
int8_t number; std::int8_t number;
if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))
{ {
return false; return false;
@ -1475,7 +1477,7 @@ class binary_reader
case 'I': case 'I':
{ {
int16_t number; std::int16_t number;
if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))
{ {
return false; return false;
@ -1486,7 +1488,7 @@ class binary_reader
case 'l': case 'l':
{ {
int32_t number; std::int32_t number;
if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))
{ {
return false; return false;
@ -1497,7 +1499,7 @@ class binary_reader
case 'L': case 'L':
{ {
int64_t number; std::int64_t number;
if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number))) if (JSON_UNLIKELY(not get_number(input_format_t::ubjson, number)))
{ {
return false; return false;
@ -1552,10 +1554,12 @@ class binary_reader
return get_ubjson_size_value(result.first); return get_ubjson_size_value(result.first);
} }
else if (current == '#')
if (current == '#')
{ {
return get_ubjson_size_value(result.first); return get_ubjson_size_value(result.first);
} }
return true; return true;
} }
@ -1580,31 +1584,31 @@ class binary_reader
case 'U': case 'U':
{ {
uint8_t number; std::uint8_t number;
return get_number(input_format_t::ubjson, number) and sax->number_unsigned(number); return get_number(input_format_t::ubjson, number) and sax->number_unsigned(number);
} }
case 'i': case 'i':
{ {
int8_t number; std::int8_t number;
return get_number(input_format_t::ubjson, number) and sax->number_integer(number); return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
} }
case 'I': case 'I':
{ {
int16_t number; std::int16_t number;
return get_number(input_format_t::ubjson, number) and sax->number_integer(number); return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
} }
case 'l': case 'l':
{ {
int32_t number; std::int32_t number;
return get_number(input_format_t::ubjson, number) and sax->number_integer(number); return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
} }
case 'L': case 'L':
{ {
int64_t number; std::int64_t number;
return get_number(input_format_t::ubjson, number) and sax->number_integer(number); return get_number(input_format_t::ubjson, number) and sax->number_integer(number);
} }
@ -1809,7 +1813,7 @@ class binary_reader
int get() int get()
{ {
++chars_read; ++chars_read;
return (current = ia->get_character()); return current = ia->get_character();
} }
/*! /*!
@ -1843,7 +1847,7 @@ class binary_reader
bool get_number(const input_format_t format, NumberType& result) bool get_number(const input_format_t format, NumberType& result)
{ {
// step 1: read input into array with system's byte order // step 1: read input into array with system's byte order
std::array<uint8_t, sizeof(NumberType)> vec; std::array<std::uint8_t, sizeof(NumberType)> vec;
for (std::size_t i = 0; i < sizeof(NumberType); ++i) for (std::size_t i = 0; i < sizeof(NumberType); ++i)
{ {
get(); get();
@ -1853,13 +1857,13 @@ class binary_reader
} }
// reverse byte order prior to conversion if necessary // reverse byte order prior to conversion if necessary
if (is_little_endian && !InputIsLittleEndian) if (is_little_endian != InputIsLittleEndian)
{ {
vec[sizeof(NumberType) - i - 1] = static_cast<uint8_t>(current); vec[sizeof(NumberType) - i - 1] = static_cast<std::uint8_t>(current);
} }
else else
{ {
vec[i] = static_cast<uint8_t>(current); // LCOV_EXCL_LINE vec[i] = static_cast<std::uint8_t>(current); // LCOV_EXCL_LINE
} }
} }
@ -1920,9 +1924,9 @@ class binary_reader
*/ */
std::string get_token_string() const std::string get_token_string() const
{ {
char cr[3]; std::array<char, 3> cr{};
(std::snprintf)(cr, 3, "%.2hhX", static_cast<unsigned char>(current)); (std::snprintf)(cr.data(), cr.size(), "%.2hhX", static_cast<unsigned char>(current));
return std::string{cr}; return std::string{cr.data()};
} }
/*! /*!
@ -1955,10 +1959,8 @@ class binary_reader
error_msg += "BSON"; error_msg += "BSON";
break; break;
// LCOV_EXCL_START default: // LCOV_EXCL_LINE
default: assert(false); // LCOV_EXCL_LINE
assert(false);
// LCOV_EXCL_STOP
} }
return error_msg + " " + context + ": " + detail; return error_msg + " " + context + ": " + detail;

View file

@ -1,7 +1,9 @@
#pragma once #pragma once
#include <array> // array
#include <cassert> // assert #include <cassert> // assert
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdio> //FILE *
#include <cstring> // strlen #include <cstring> // strlen
#include <istream> // istream #include <istream> // istream
#include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next #include <iterator> // begin, end, iterator_traits, random_access_iterator_tag, distance, next
@ -10,7 +12,6 @@
#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
#include <cstdio> //FILE *
#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>
@ -58,10 +59,18 @@ class file_input_adapter : public input_adapter_protocol
: m_file(f) : m_file(f)
{} {}
// make class move-only
file_input_adapter(const file_input_adapter&) = delete;
file_input_adapter(file_input_adapter&&) = default;
file_input_adapter& operator=(const file_input_adapter&) = delete;
file_input_adapter& operator=(file_input_adapter&&) = default;
~file_input_adapter() override = default;
std::char_traits<char>::int_type get_character() noexcept override std::char_traits<char>::int_type get_character() noexcept override
{ {
return std::fgetc(m_file); return std::fgetc(m_file);
} }
private: private:
/// the file pointer to read from /// the file pointer to read from
std::FILE* m_file; std::FILE* m_file;
@ -153,7 +162,11 @@ template<typename WideStringType, size_t T>
struct wide_string_input_helper struct wide_string_input_helper
{ {
// UTF-32 // UTF-32
static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) static void fill_buffer(const WideStringType& str,
size_t& current_wchar,
std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
size_t& utf8_bytes_index,
size_t& utf8_bytes_filled)
{ {
utf8_bytes_index = 0; utf8_bytes_index = 0;
@ -165,39 +178,39 @@ struct wide_string_input_helper
else else
{ {
// get the current character // get the current character
const auto wc = static_cast<int>(str[current_wchar++]); const auto wc = static_cast<unsigned int>(str[current_wchar++]);
// UTF-32 to UTF-8 encoding // UTF-32 to UTF-8 encoding
if (wc < 0x80) if (wc < 0x80)
{ {
utf8_bytes[0] = wc; utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
utf8_bytes_filled = 1; utf8_bytes_filled = 1;
} }
else if (wc <= 0x7FF) else if (wc <= 0x7FF)
{ {
utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F); utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((wc >> 6u) & 0x1Fu));
utf8_bytes[1] = 0x80 | (wc & 0x3F); utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
utf8_bytes_filled = 2; utf8_bytes_filled = 2;
} }
else if (wc <= 0xFFFF) else if (wc <= 0xFFFF)
{ {
utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F); utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((wc >> 12u) & 0x0Fu));
utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 6u) & 0x3Fu));
utf8_bytes[2] = 0x80 | (wc & 0x3F); utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
utf8_bytes_filled = 3; utf8_bytes_filled = 3;
} }
else if (wc <= 0x10FFFF) else if (wc <= 0x10FFFF)
{ {
utf8_bytes[0] = 0xF0 | ((wc >> 18) & 0x07); utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | ((wc >> 18u) & 0x07u));
utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F); utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 12u) & 0x3Fu));
utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F); utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 6u) & 0x3Fu));
utf8_bytes[3] = 0x80 | (wc & 0x3F); utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
utf8_bytes_filled = 4; utf8_bytes_filled = 4;
} }
else else
{ {
// unknown character // unknown character
utf8_bytes[0] = wc; utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
utf8_bytes_filled = 1; utf8_bytes_filled = 1;
} }
} }
@ -208,7 +221,11 @@ template<typename WideStringType>
struct wide_string_input_helper<WideStringType, 2> struct wide_string_input_helper<WideStringType, 2>
{ {
// UTF-16 // UTF-16
static void fill_buffer(const WideStringType& str, size_t& current_wchar, std::array<std::char_traits<char>::int_type, 4>& utf8_bytes, size_t& utf8_bytes_index, size_t& utf8_bytes_filled) static void fill_buffer(const WideStringType& str,
size_t& current_wchar,
std::array<std::char_traits<char>::int_type, 4>& utf8_bytes,
size_t& utf8_bytes_index,
size_t& utf8_bytes_filled)
{ {
utf8_bytes_index = 0; utf8_bytes_index = 0;
@ -220,44 +237,44 @@ struct wide_string_input_helper<WideStringType, 2>
else else
{ {
// get the current character // get the current character
const auto wc = static_cast<int>(str[current_wchar++]); const auto wc = static_cast<unsigned int>(str[current_wchar++]);
// UTF-16 to UTF-8 encoding // UTF-16 to UTF-8 encoding
if (wc < 0x80) if (wc < 0x80)
{ {
utf8_bytes[0] = wc; utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
utf8_bytes_filled = 1; utf8_bytes_filled = 1;
} }
else if (wc <= 0x7FF) else if (wc <= 0x7FF)
{ {
utf8_bytes[0] = 0xC0 | ((wc >> 6)); utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xC0u | ((wc >> 6u)));
utf8_bytes[1] = 0x80 | (wc & 0x3F); utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
utf8_bytes_filled = 2; utf8_bytes_filled = 2;
} }
else if (0xD800 > wc or wc >= 0xE000) else if (0xD800 > wc or wc >= 0xE000)
{ {
utf8_bytes[0] = 0xE0 | ((wc >> 12)); utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xE0u | ((wc >> 12u)));
utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F); utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((wc >> 6u) & 0x3Fu));
utf8_bytes[2] = 0x80 | (wc & 0x3F); utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | (wc & 0x3Fu));
utf8_bytes_filled = 3; utf8_bytes_filled = 3;
} }
else else
{ {
if (current_wchar < str.size()) if (current_wchar < str.size())
{ {
const auto wc2 = static_cast<int>(str[current_wchar++]); const auto wc2 = static_cast<unsigned int>(str[current_wchar++]);
const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF)); const auto charcode = 0x10000u + (((wc & 0x3FFu) << 10u) | (wc2 & 0x3FFu));
utf8_bytes[0] = 0xf0 | (charcode >> 18); utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(0xF0u | (charcode >> 18u));
utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F); utf8_bytes[1] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 12u) & 0x3Fu));
utf8_bytes[2] = 0x80 | ((charcode >> 6) & 0x3F); utf8_bytes[2] = static_cast<std::char_traits<char>::int_type>(0x80u | ((charcode >> 6u) & 0x3Fu));
utf8_bytes[3] = 0x80 | (charcode & 0x3F); utf8_bytes[3] = static_cast<std::char_traits<char>::int_type>(0x80u | (charcode & 0x3Fu));
utf8_bytes_filled = 4; utf8_bytes_filled = 4;
} }
else else
{ {
// unknown character // unknown character
++current_wchar; ++current_wchar;
utf8_bytes[0] = wc; utf8_bytes[0] = static_cast<std::char_traits<char>::int_type>(wc);
utf8_bytes_filled = 1; utf8_bytes_filled = 1;
} }
} }
@ -269,7 +286,7 @@ template<typename WideStringType>
class wide_string_input_adapter : public input_adapter_protocol class wide_string_input_adapter : public input_adapter_protocol
{ {
public: public:
explicit wide_string_input_adapter(const WideStringType& w) noexcept explicit wide_string_input_adapter(const WideStringType& w) noexcept
: str(w) : str(w)
{} {}

View file

@ -1,9 +1,10 @@
#pragma once #pragma once
#include <cassert> #include <cassert> // assert
#include <cstddef> #include <cstddef>
#include <string> #include <string> // string
#include <vector> #include <utility> // move
#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>
@ -158,6 +159,13 @@ class json_sax_dom_parser
: root(r), allow_exceptions(allow_exceptions_) : root(r), allow_exceptions(allow_exceptions_)
{} {}
// make class move-only
json_sax_dom_parser(const json_sax_dom_parser&) = delete;
json_sax_dom_parser(json_sax_dom_parser&&) = default;
json_sax_dom_parser& operator=(const json_sax_dom_parser&) = delete;
json_sax_dom_parser& operator=(json_sax_dom_parser&&) = default;
~json_sax_dom_parser() = default;
bool null() bool null()
{ {
handle_value(nullptr); handle_value(nullptr);
@ -249,16 +257,16 @@ class json_sax_dom_parser
switch ((ex.id / 100) % 100) switch ((ex.id / 100) % 100)
{ {
case 1: case 1:
JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex)); JSON_THROW(*static_cast<const detail::parse_error*>(&ex));
case 4: case 4:
JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex)); JSON_THROW(*static_cast<const detail::out_of_range*>(&ex));
// LCOV_EXCL_START // LCOV_EXCL_START
case 2: case 2:
JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex)); JSON_THROW(*static_cast<const detail::invalid_iterator*>(&ex));
case 3: case 3:
JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex)); JSON_THROW(*static_cast<const detail::type_error*>(&ex));
case 5: case 5:
JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex)); JSON_THROW(*static_cast<const detail::other_error*>(&ex));
default: default:
assert(false); assert(false);
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
@ -295,18 +303,17 @@ class json_sax_dom_parser
ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v)); ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
return &(ref_stack.back()->m_value.array->back()); return &(ref_stack.back()->m_value.array->back());
} }
else
{ assert(ref_stack.back()->is_object())
assert(object_element); assert(object_element);
*object_element = BasicJsonType(std::forward<Value>(v)); *object_element = BasicJsonType(std::forward<Value>(v));
return object_element; return object_element;
}
} }
/// 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
@ -334,6 +341,13 @@ class json_sax_dom_callback_parser
keep_stack.push_back(true); keep_stack.push_back(true);
} }
// make class move-only
json_sax_dom_callback_parser(const json_sax_dom_callback_parser&) = delete;
json_sax_dom_callback_parser(json_sax_dom_callback_parser&&) = default;
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;
~json_sax_dom_callback_parser() = default;
bool null() bool null()
{ {
handle_value(nullptr); handle_value(nullptr);
@ -380,13 +394,9 @@ class json_sax_dom_callback_parser
ref_stack.push_back(val.second); ref_stack.push_back(val.second);
// check object limit // check object limit
if (ref_stack.back()) if (ref_stack.back() and JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
{ {
if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size())) JSON_THROW(out_of_range::create(408, "excessive object size: " + std::to_string(len)));
{
JSON_THROW(out_of_range::create(408,
"excessive object size: " + std::to_string(len)));
}
} }
return true; return true;
@ -411,13 +421,10 @@ class json_sax_dom_callback_parser
bool end_object() bool end_object()
{ {
if (ref_stack.back()) if (ref_stack.back() and not callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back()))
{ {
if (not callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::object_end, *ref_stack.back())) // discard object
{ *ref_stack.back() = discarded;
// discard object
*ref_stack.back() = discarded;
}
} }
assert(not ref_stack.empty()); assert(not ref_stack.empty());
@ -425,18 +432,15 @@ class json_sax_dom_callback_parser
ref_stack.pop_back(); ref_stack.pop_back();
keep_stack.pop_back(); keep_stack.pop_back();
if (not ref_stack.empty() and ref_stack.back()) if (not ref_stack.empty() and ref_stack.back() and ref_stack.back()->is_object())
{ {
// remove discarded value // remove discarded value
if (ref_stack.back()->is_object()) for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)
{ {
for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it) if (it->is_discarded())
{ {
if (it->is_discarded()) ref_stack.back()->erase(it);
{ break;
ref_stack.back()->erase(it);
break;
}
} }
} }
} }
@ -453,13 +457,9 @@ class json_sax_dom_callback_parser
ref_stack.push_back(val.second); ref_stack.push_back(val.second);
// check array limit // check array limit
if (ref_stack.back()) if (ref_stack.back() and JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size()))
{ {
if (JSON_UNLIKELY(len != std::size_t(-1) and len > ref_stack.back()->max_size())) JSON_THROW(out_of_range::create(408, "excessive array size: " + std::to_string(len)));
{
JSON_THROW(out_of_range::create(408,
"excessive array size: " + std::to_string(len)));
}
} }
return true; return true;
@ -485,12 +485,9 @@ class json_sax_dom_callback_parser
keep_stack.pop_back(); keep_stack.pop_back();
// remove discarded value // remove discarded value
if (not keep and not ref_stack.empty()) if (not keep and not ref_stack.empty() and ref_stack.back()->is_array())
{ {
if (ref_stack.back()->is_array()) ref_stack.back()->m_value.array->pop_back();
{
ref_stack.back()->m_value.array->pop_back();
}
} }
return true; return true;
@ -506,16 +503,16 @@ class json_sax_dom_callback_parser
switch ((ex.id / 100) % 100) switch ((ex.id / 100) % 100)
{ {
case 1: case 1:
JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex)); JSON_THROW(*static_cast<const detail::parse_error*>(&ex));
case 4: case 4:
JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex)); JSON_THROW(*static_cast<const detail::out_of_range*>(&ex));
// LCOV_EXCL_START // LCOV_EXCL_START
case 2: case 2:
JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex)); JSON_THROW(*static_cast<const detail::invalid_iterator*>(&ex));
case 3: case 3:
JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex)); JSON_THROW(*static_cast<const detail::type_error*>(&ex));
case 5: case 5:
JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex)); JSON_THROW(*static_cast<const detail::other_error*>(&ex));
default: default:
assert(false); assert(false);
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
@ -585,37 +582,38 @@ class json_sax_dom_callback_parser
// we now only expect arrays and objects // we now only expect arrays and objects
assert(ref_stack.back()->is_array() or ref_stack.back()->is_object()); assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
// array
if (ref_stack.back()->is_array()) if (ref_stack.back()->is_array())
{ {
ref_stack.back()->m_value.array->push_back(std::move(value)); ref_stack.back()->m_value.array->push_back(std::move(value));
return {true, &(ref_stack.back()->m_value.array->back())}; return {true, &(ref_stack.back()->m_value.array->back())};
} }
else
// object
assert(ref_stack.back()->is_object())
// check if we should store an element for the current key
assert(not key_keep_stack.empty());
const bool store_element = key_keep_stack.back();
key_keep_stack.pop_back();
if (not store_element)
{ {
// check if we should store an element for the current key return {false, nullptr};
assert(not key_keep_stack.empty());
const bool store_element = key_keep_stack.back();
key_keep_stack.pop_back();
if (not store_element)
{
return {false, nullptr};
}
assert(object_element);
*object_element = std::move(value);
return {true, object_element};
} }
assert(object_element);
*object_element = std::move(value);
return {true, object_element};
} }
/// 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

View file

@ -1,16 +1,18 @@
#pragma once #pragma once
#include <array> // array
#include <clocale> // localeconv #include <clocale> // localeconv
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
#include <cstdio> // snprintf #include <cstdio> // snprintf
#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 <vector> // vector #include <vector> // vector
#include <nlohmann/detail/macro_scope.hpp>
#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>
#include <nlohmann/detail/macro_scope.hpp>
namespace nlohmann namespace nlohmann
{ {
@ -148,22 +150,22 @@ class lexer
assert(current == 'u'); assert(current == 'u');
int codepoint = 0; int codepoint = 0;
const auto factors = { 12, 8, 4, 0 }; const auto factors = { 12u, 8u, 4u, 0u };
for (const auto factor : factors) for (const auto factor : factors)
{ {
get(); get();
if (current >= '0' and current <= '9') if (current >= '0' and current <= '9')
{ {
codepoint += ((current - 0x30) << factor); codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x30u) << factor);
} }
else if (current >= 'A' and current <= 'F') else if (current >= 'A' and current <= 'F')
{ {
codepoint += ((current - 0x37) << factor); codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x37u) << factor);
} }
else if (current >= 'a' and current <= 'f') else if (current >= 'a' and current <= 'f')
{ {
codepoint += ((current - 0x57) << factor); codepoint += static_cast<int>((static_cast<unsigned int>(current) - 0x57u) << factor);
} }
else else
{ {
@ -321,15 +323,15 @@ class lexer
if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF)) if (JSON_LIKELY(0xDC00 <= codepoint2 and codepoint2 <= 0xDFFF))
{ {
// overwrite codepoint // overwrite codepoint
codepoint = codepoint = static_cast<int>(
// high surrogate occupies the most significant 22 bits // high surrogate occupies the most significant 22 bits
(codepoint1 << 10) (static_cast<unsigned int>(codepoint1) << 10u)
// low surrogate occupies the least significant 15 bits // low surrogate occupies the least significant 15 bits
+ 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
- 0x35FDC00; - 0x35FDC00u);
} }
else else
{ {
@ -364,23 +366,23 @@ class lexer
else if (codepoint <= 0x7FF) else if (codepoint <= 0x7FF)
{ {
// 2-byte characters: 110xxxxx 10xxxxxx // 2-byte characters: 110xxxxx 10xxxxxx
add(0xC0 | (codepoint >> 6)); add(static_cast<int>(0xC0u | (static_cast<unsigned int>(codepoint) >> 6u)));
add(0x80 | (codepoint & 0x3F)); add(static_cast<int>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
} }
else if (codepoint <= 0xFFFF) else if (codepoint <= 0xFFFF)
{ {
// 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx // 3-byte characters: 1110xxxx 10xxxxxx 10xxxxxx
add(0xE0 | (codepoint >> 12)); add(static_cast<int>(0xE0u | (static_cast<unsigned int>(codepoint) >> 12u)));
add(0x80 | ((codepoint >> 6) & 0x3F)); add(static_cast<int>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));
add(0x80 | (codepoint & 0x3F)); add(static_cast<int>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
} }
else else
{ {
// 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx // 4-byte characters: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
add(0xF0 | (codepoint >> 18)); add(static_cast<int>(0xF0u | (static_cast<unsigned int>(codepoint) >> 18u)));
add(0x80 | ((codepoint >> 12) & 0x3F)); add(static_cast<int>(0x80u | ((static_cast<unsigned int>(codepoint) >> 12u) & 0x3Fu)));
add(0x80 | ((codepoint >> 6) & 0x3F)); add(static_cast<int>(0x80u | ((static_cast<unsigned int>(codepoint) >> 6u) & 0x3Fu)));
add(0x80 | (codepoint & 0x3F)); add(static_cast<int>(0x80u | (static_cast<unsigned int>(codepoint) & 0x3Fu)));
} }
break; break;
@ -906,13 +908,9 @@ class lexer
goto scan_number_any1; goto scan_number_any1;
} }
// LCOV_EXCL_START // all other characters are rejected outside scan_number()
default: default: // LCOV_EXCL_LINE
{ assert(false); // LCOV_EXCL_LINE
// all other characters are rejected outside scan_number()
assert(false);
}
// LCOV_EXCL_STOP
} }
scan_number_minus: scan_number_minus:
@ -1297,7 +1295,7 @@ scan_number_done:
if (JSON_LIKELY(current != std::char_traits<char>::eof())) if (JSON_LIKELY(current != std::char_traits<char>::eof()))
{ {
assert(token_string.size() != 0); assert(not token_string.empty());
token_string.pop_back(); token_string.pop_back();
} }
} }
@ -1359,9 +1357,9 @@ scan_number_done:
if ('\x00' <= c and c <= '\x1F') if ('\x00' <= c and c <= '\x1F')
{ {
// escape control characters // escape control characters
char cs[9]; std::array<char, 9> cs{};
(std::snprintf)(cs, 9, "<U+%.4X>", static_cast<unsigned char>(c)); (std::snprintf)(cs.data(), cs.size(), "<U+%.4X>", static_cast<unsigned char>(c));
result += cs; result += cs.data();
} }
else else
{ {
@ -1483,7 +1481,7 @@ 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> token_string {}; std::vector<char> token_string {};

View file

@ -6,13 +6,14 @@
#include <functional> // function #include <functional> // function
#include <string> // string #include <string> // string
#include <utility> // move #include <utility> // move
#include <vector> // vector
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/is_sax.hpp>
#include <nlohmann/detail/input/input_adapters.hpp> #include <nlohmann/detail/input/input_adapters.hpp>
#include <nlohmann/detail/input/json_sax.hpp> #include <nlohmann/detail/input/json_sax.hpp>
#include <nlohmann/detail/input/lexer.hpp> #include <nlohmann/detail/input/lexer.hpp>
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/is_sax.hpp>
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
namespace nlohmann namespace nlohmann
@ -458,7 +459,7 @@ class parser
/// get next token from lexer /// get next token from lexer
token_type get_token() token_type get_token()
{ {
return (last_token = m_lexer.scan()); return last_token = m_lexer.scan();
} }
std::string exception_message(const token_type expected, const std::string& context) std::string exception_message(const token_type expected, const std::string& context)

View file

@ -23,5 +23,5 @@ struct position_t
} }
}; };
} } // namespace detail
} } // namespace nlohmann

View file

@ -607,7 +607,7 @@ class iter_impl
/// 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
} // namespace nlohmann } // namespace nlohmann

View file

@ -1,12 +1,12 @@
#pragma once #pragma once
#include <cstddef> // size_t #include <cstddef> // size_t
#include <string> // string, to_string
#include <iterator> // input_iterator_tag #include <iterator> // input_iterator_tag
#include <string> // string, to_string
#include <tuple> // tuple_size, get, tuple_element #include <tuple> // tuple_size, get, tuple_element
#include <nlohmann/detail/value_t.hpp>
#include <nlohmann/detail/meta/type_traits.hpp> #include <nlohmann/detail/meta/type_traits.hpp>
#include <nlohmann/detail/value_t.hpp>
namespace nlohmann namespace nlohmann
{ {
@ -147,6 +147,11 @@ auto get(const nlohmann::detail::iteration_proxy_value<IteratorType>& i) -> decl
// 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__)
// Fix: https://github.com/nlohmann/json/issues/1401
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmismatched-tags"
#endif
template <typename IteratorType> template <typename IteratorType>
class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>> class tuple_size<::nlohmann::detail::iteration_proxy_value<IteratorType>>
: public std::integral_constant<std::size_t, 2> {}; : public std::integral_constant<std::size_t, 2> {};
@ -159,4 +164,7 @@ class tuple_element<N, ::nlohmann::detail::iteration_proxy_value<IteratorType >>
get<N>(std::declval < get<N>(std::declval <
::nlohmann::detail::iteration_proxy_value<IteratorType >> ())); ::nlohmann::detail::iteration_proxy_value<IteratorType >> ()));
}; };
} #if defined(__clang__)
#pragma clang diagnostic pop
#endif
} // namespace std

View file

@ -45,5 +45,5 @@ struct iterator_traits<T*, enable_if_t<std::is_object<T>::value>> {
using pointer = T*; using pointer = T*;
using reference = T&; using reference = T&;
}; };
} } // namespace detail
} } // namespace nlohmann

View file

@ -4,10 +4,11 @@
#include <cassert> // assert #include <cassert> // assert
#include <numeric> // accumulate #include <numeric> // accumulate
#include <string> // string #include <string> // string
#include <utility> // move
#include <vector> // vector #include <vector> // vector
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
namespace nlohmann namespace nlohmann
@ -76,6 +77,139 @@ class json_pointer
return to_string(); return to_string();
} }
/*!
@brief append another JSON pointer at the end of this JSON pointer
*/
json_pointer& operator/=(const json_pointer& ptr)
{
reference_tokens.insert(reference_tokens.end(),
ptr.reference_tokens.begin(),
ptr.reference_tokens.end());
return *this;
}
/// @copydoc push_back(std::string&&)
json_pointer& operator/=(std::string token)
{
push_back(std::move(token));
return *this;
}
/// @copydoc operator/=(std::string)
json_pointer& operator/=(std::size_t array_index)
{
return *this /= std::to_string(array_index);
}
/*!
@brief create a new JSON pointer by appending the right JSON pointer at the end of the left JSON pointer
*/
friend json_pointer operator/(const json_pointer& left_ptr,
const json_pointer& right_ptr)
{
return json_pointer(left_ptr) /= right_ptr;
}
/*!
@brief create a new JSON pointer by appending the unescaped token at the end of the JSON pointer
*/
friend json_pointer operator/(const json_pointer& ptr, std::string token)
{
return json_pointer(ptr) /= std::move(token);
}
/*!
@brief create a new JSON pointer by appending the array-index-token at the end of the JSON pointer
*/
friend json_pointer operator/(const json_pointer& lhs, std::size_t array_index)
{
return json_pointer(lhs) /= array_index;
}
/*!
@brief returns the parent of this JSON pointer
@return parent of this JSON pointer; in case this JSON pointer is the root,
the root itself is returned
@complexity Constant.
@liveexample{The example shows the result of `parent_pointer` for different
JSON Pointers.,json_pointer__parent_pointer}
@since version 3.6.0
*/
json_pointer parent_pointer() const
{
if (empty())
{
return *this;
}
json_pointer res = *this;
res.pop_back();
return res;
}
/*!
@brief remove and return last reference token
@throw out_of_range.405 if JSON pointer has no parent
*/
std::string pop_back()
{
if (JSON_UNLIKELY(empty()))
{
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent"));
}
auto last = reference_tokens.back();
reference_tokens.pop_back();
return last;
}
/*!
@brief append an unescaped token at the end of the reference pointer
@param[in] token token to add
@complexity Amortized constant.
@liveexample{The example shows the result of `push_back` for different
JSON Pointers.,json_pointer__push_back}
@since version 0.6.0
*/
void push_back(const std::string& token)
{
reference_tokens.push_back(token);
}
/// @copydoc push_back(const std::string&)
void push_back(std::string&& token)
{
reference_tokens.push_back(std::move(token));
}
/*!
@brief return whether pointer points to the root document
@return true iff the JSON pointer points to the root document
@complexity Constant.
@exceptionsafety No-throw guarantee: this function never throws exceptions.
@liveexample{The example shows the result of `empty` for different JSON
Pointers.,json_pointer__empty}
@since version 3.6.0
*/
bool empty() const noexcept
{
return reference_tokens.empty();
}
private:
/*! /*!
@param[in] s reference token to be converted into an array index @param[in] s reference token to be converted into an array index
@ -97,32 +231,9 @@ class json_pointer
return res; return res;
} }
private:
/*!
@brief remove and return last reference pointer
@throw out_of_range.405 if JSON pointer has no parent
*/
std::string pop_back()
{
if (JSON_UNLIKELY(is_root()))
{
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent"));
}
auto last = reference_tokens.back();
reference_tokens.pop_back();
return last;
}
/// return whether pointer points to the root document
bool is_root() const noexcept
{
return reference_tokens.empty();
}
json_pointer top() const json_pointer top() const
{ {
if (JSON_UNLIKELY(is_root())) if (JSON_UNLIKELY(empty()))
{ {
JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent")); JSON_THROW(detail::out_of_range::create(405, "JSON pointer has no parent"));
} }
@ -233,7 +344,7 @@ class json_pointer
std::all_of(reference_token.begin(), reference_token.end(), std::all_of(reference_token.begin(), reference_token.end(),
[](const char x) [](const char x)
{ {
return (x >= '0' and x <= '9'); return x >= '0' and x <= '9';
}); });
// change value to array for numbers or "-" or to object otherwise // change value to array for numbers or "-" or to object otherwise
@ -682,7 +793,7 @@ class json_pointer
friend bool operator==(json_pointer const& lhs, friend bool operator==(json_pointer const& lhs,
json_pointer const& rhs) noexcept json_pointer const& rhs) noexcept
{ {
return (lhs.reference_tokens == rhs.reference_tokens); return lhs.reference_tokens == rhs.reference_tokens;
} }
friend bool operator!=(json_pointer const& lhs, friend bool operator!=(json_pointer const& lhs,

View file

@ -1,5 +1,7 @@
#pragma once #pragma once
#include <utility> // pair
// This file contains all internal macro definitions // This file contains all internal macro definitions
// 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,6 +39,19 @@
#define JSON_DEPRECATED #define JSON_DEPRECATED
#endif #endif
// allow for portable nodiscard warnings
#if defined(__has_cpp_attribute)
#if __has_cpp_attribute(nodiscard)
#define JSON_NODISCARD [[nodiscard]]
#elif __has_cpp_attribute(gnu::warn_unused_result)
#define JSON_NODISCARD [[gnu::warn_unused_result]]
#else
#define JSON_NODISCARD
#endif
#else
#define JSON_NODISCARD
#endif
// allow to disable exceptions // allow to disable exceptions
#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
@ -44,6 +59,7 @@
#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>
#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)
@ -72,8 +88,8 @@
// manual branch prediction // manual branch prediction
#if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__) #if defined(__clang__) || defined(__GNUC__) || defined(__GNUG__)
#define JSON_LIKELY(x) __builtin_expect(!!(x), 1) #define JSON_LIKELY(x) __builtin_expect(static_cast<bool>(x), 1)
#define JSON_UNLIKELY(x) __builtin_expect(!!(x), 0) #define JSON_UNLIKELY(x) __builtin_expect(static_cast<bool>(x), 0)
#else #else
#define JSON_LIKELY(x) x #define JSON_LIKELY(x) x
#define JSON_UNLIKELY(x) x #define JSON_UNLIKELY(x) x

View file

@ -16,6 +16,7 @@
#undef JSON_LIKELY #undef JSON_LIKELY
#undef JSON_UNLIKELY #undef JSON_UNLIKELY
#undef JSON_DEPRECATED #undef JSON_DEPRECATED
#undef JSON_NODISCARD
#undef JSON_HAS_CPP_14 #undef JSON_HAS_CPP_14
#undef JSON_HAS_CPP_17 #undef JSON_HAS_CPP_17
#undef NLOHMANN_BASIC_JSON_TPL_DECLARATION #undef NLOHMANN_BASIC_JSON_TPL_DECLARATION

View file

@ -14,7 +14,9 @@ struct nonesuch
nonesuch() = delete; nonesuch() = delete;
~nonesuch() = delete; ~nonesuch() = delete;
nonesuch(nonesuch const&) = delete; nonesuch(nonesuch const&) = delete;
nonesuch(nonesuch const&&) = delete;
void operator=(nonesuch const&) = delete; void operator=(nonesuch const&) = delete;
void operator=(nonesuch&&) = delete;
}; };
template <class Default, template <class Default,

View file

@ -2,6 +2,7 @@
#include <cstdint> // size_t #include <cstdint> // size_t
#include <utility> // declval #include <utility> // declval
#include <string> // string
#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>

View file

@ -5,11 +5,11 @@
#include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type #include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
#include <utility> // declval #include <utility> // declval
#include <nlohmann/json_fwd.hpp>
#include <nlohmann/detail/iterators/iterator_traits.hpp> #include <nlohmann/detail/iterators/iterator_traits.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/detected.hpp> #include <nlohmann/detail/meta/detected.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/json_fwd.hpp>
namespace nlohmann namespace nlohmann
{ {

View file

@ -5,6 +5,7 @@
#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 <string> // string
#include <nlohmann/detail/input/binary_reader.hpp> #include <nlohmann/detail/input/binary_reader.hpp>
#include <nlohmann/detail/output/output_adapters.hpp> #include <nlohmann/detail/output/output_adapters.hpp>
@ -87,27 +88,27 @@ class binary_writer
// code from the value_t::number_unsigned case here. // code from the value_t::number_unsigned case here.
if (j.m_value.number_integer <= 0x17) if (j.m_value.number_integer <= 0x17)
{ {
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)()) else if (j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0x18)); oa->write_character(to_char_type(0x18));
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer <= (std::numeric_limits<uint16_t>::max)()) else if (j.m_value.number_integer <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0x19)); oa->write_character(to_char_type(0x19));
write_number(static_cast<uint16_t>(j.m_value.number_integer)); write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer <= (std::numeric_limits<uint32_t>::max)()) else if (j.m_value.number_integer <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0x1A)); oa->write_character(to_char_type(0x1A));
write_number(static_cast<uint32_t>(j.m_value.number_integer)); write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
} }
else else
{ {
oa->write_character(to_char_type(0x1B)); oa->write_character(to_char_type(0x1B));
write_number(static_cast<uint64_t>(j.m_value.number_integer)); write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
} }
} }
else else
@ -117,27 +118,27 @@ class binary_writer
const auto positive_number = -1 - j.m_value.number_integer; const auto positive_number = -1 - j.m_value.number_integer;
if (j.m_value.number_integer >= -24) if (j.m_value.number_integer >= -24)
{ {
write_number(static_cast<uint8_t>(0x20 + positive_number)); write_number(static_cast<std::uint8_t>(0x20 + positive_number));
} }
else if (positive_number <= (std::numeric_limits<uint8_t>::max)()) else if (positive_number <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0x38)); oa->write_character(to_char_type(0x38));
write_number(static_cast<uint8_t>(positive_number)); write_number(static_cast<std::uint8_t>(positive_number));
} }
else if (positive_number <= (std::numeric_limits<uint16_t>::max)()) else if (positive_number <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0x39)); oa->write_character(to_char_type(0x39));
write_number(static_cast<uint16_t>(positive_number)); write_number(static_cast<std::uint16_t>(positive_number));
} }
else if (positive_number <= (std::numeric_limits<uint32_t>::max)()) else if (positive_number <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0x3A)); oa->write_character(to_char_type(0x3A));
write_number(static_cast<uint32_t>(positive_number)); write_number(static_cast<std::uint32_t>(positive_number));
} }
else else
{ {
oa->write_character(to_char_type(0x3B)); oa->write_character(to_char_type(0x3B));
write_number(static_cast<uint64_t>(positive_number)); write_number(static_cast<std::uint64_t>(positive_number));
} }
} }
break; break;
@ -147,27 +148,27 @@ class binary_writer
{ {
if (j.m_value.number_unsigned <= 0x17) if (j.m_value.number_unsigned <= 0x17)
{ {
write_number(static_cast<uint8_t>(j.m_value.number_unsigned)); write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0x18)); oa->write_character(to_char_type(0x18));
write_number(static_cast<uint8_t>(j.m_value.number_unsigned)); write_number(static_cast<std::uint8_t>(j.m_value.number_unsigned));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0x19)); oa->write_character(to_char_type(0x19));
write_number(static_cast<uint16_t>(j.m_value.number_unsigned)); write_number(static_cast<std::uint16_t>(j.m_value.number_unsigned));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0x1A)); oa->write_character(to_char_type(0x1A));
write_number(static_cast<uint32_t>(j.m_value.number_unsigned)); write_number(static_cast<std::uint32_t>(j.m_value.number_unsigned));
} }
else else
{ {
oa->write_character(to_char_type(0x1B)); oa->write_character(to_char_type(0x1B));
write_number(static_cast<uint64_t>(j.m_value.number_unsigned)); write_number(static_cast<std::uint64_t>(j.m_value.number_unsigned));
} }
break; break;
} }
@ -185,28 +186,28 @@ class binary_writer
const auto N = j.m_value.string->size(); const auto N = j.m_value.string->size();
if (N <= 0x17) if (N <= 0x17)
{ {
write_number(static_cast<uint8_t>(0x60 + N)); write_number(static_cast<std::uint8_t>(0x60 + N));
} }
else if (N <= (std::numeric_limits<uint8_t>::max)()) else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0x78)); oa->write_character(to_char_type(0x78));
write_number(static_cast<uint8_t>(N)); write_number(static_cast<std::uint8_t>(N));
} }
else if (N <= (std::numeric_limits<uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0x79)); oa->write_character(to_char_type(0x79));
write_number(static_cast<uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0x7A)); oa->write_character(to_char_type(0x7A));
write_number(static_cast<uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
// LCOV_EXCL_START // LCOV_EXCL_START
else if (N <= (std::numeric_limits<uint64_t>::max)()) else if (N <= (std::numeric_limits<std::uint64_t>::max)())
{ {
oa->write_character(to_char_type(0x7B)); oa->write_character(to_char_type(0x7B));
write_number(static_cast<uint64_t>(N)); write_number(static_cast<std::uint64_t>(N));
} }
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
@ -223,28 +224,28 @@ class binary_writer
const auto N = j.m_value.array->size(); const auto N = j.m_value.array->size();
if (N <= 0x17) if (N <= 0x17)
{ {
write_number(static_cast<uint8_t>(0x80 + N)); write_number(static_cast<std::uint8_t>(0x80 + N));
} }
else if (N <= (std::numeric_limits<uint8_t>::max)()) else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0x98)); oa->write_character(to_char_type(0x98));
write_number(static_cast<uint8_t>(N)); write_number(static_cast<std::uint8_t>(N));
} }
else if (N <= (std::numeric_limits<uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0x99)); oa->write_character(to_char_type(0x99));
write_number(static_cast<uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0x9A)); oa->write_character(to_char_type(0x9A));
write_number(static_cast<uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
// LCOV_EXCL_START // LCOV_EXCL_START
else if (N <= (std::numeric_limits<uint64_t>::max)()) else if (N <= (std::numeric_limits<std::uint64_t>::max)())
{ {
oa->write_character(to_char_type(0x9B)); oa->write_character(to_char_type(0x9B));
write_number(static_cast<uint64_t>(N)); write_number(static_cast<std::uint64_t>(N));
} }
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
@ -262,28 +263,28 @@ class binary_writer
const auto N = j.m_value.object->size(); const auto N = j.m_value.object->size();
if (N <= 0x17) if (N <= 0x17)
{ {
write_number(static_cast<uint8_t>(0xA0 + N)); write_number(static_cast<std::uint8_t>(0xA0 + N));
} }
else if (N <= (std::numeric_limits<uint8_t>::max)()) else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{ {
oa->write_character(to_char_type(0xB8)); oa->write_character(to_char_type(0xB8));
write_number(static_cast<uint8_t>(N)); write_number(static_cast<std::uint8_t>(N));
} }
else if (N <= (std::numeric_limits<uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
oa->write_character(to_char_type(0xB9)); oa->write_character(to_char_type(0xB9));
write_number(static_cast<uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
oa->write_character(to_char_type(0xBA)); oa->write_character(to_char_type(0xBA));
write_number(static_cast<uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
// LCOV_EXCL_START // LCOV_EXCL_START
else if (N <= (std::numeric_limits<uint64_t>::max)()) else if (N <= (std::numeric_limits<std::uint64_t>::max)())
{ {
oa->write_character(to_char_type(0xBB)); oa->write_character(to_char_type(0xBB));
write_number(static_cast<uint64_t>(N)); write_number(static_cast<std::uint64_t>(N));
} }
// LCOV_EXCL_STOP // LCOV_EXCL_STOP
@ -332,31 +333,31 @@ class binary_writer
if (j.m_value.number_unsigned < 128) if (j.m_value.number_unsigned < 128)
{ {
// positive fixnum // positive fixnum
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
{ {
// uint 8 // uint 8
oa->write_character(to_char_type(0xCC)); oa->write_character(to_char_type(0xCC));
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
{ {
// uint 16 // uint 16
oa->write_character(to_char_type(0xCD)); oa->write_character(to_char_type(0xCD));
write_number(static_cast<uint16_t>(j.m_value.number_integer)); write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
{ {
// uint 32 // uint 32
oa->write_character(to_char_type(0xCE)); oa->write_character(to_char_type(0xCE));
write_number(static_cast<uint32_t>(j.m_value.number_integer)); write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
{ {
// uint 64 // uint 64
oa->write_character(to_char_type(0xCF)); oa->write_character(to_char_type(0xCF));
write_number(static_cast<uint64_t>(j.m_value.number_integer)); write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
} }
} }
else else
@ -364,35 +365,35 @@ class binary_writer
if (j.m_value.number_integer >= -32) if (j.m_value.number_integer >= -32)
{ {
// negative fixnum // negative fixnum
write_number(static_cast<int8_t>(j.m_value.number_integer)); write_number(static_cast<std::int8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= (std::numeric_limits<int8_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int8_t>::min)() and
j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)()) j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
{ {
// int 8 // int 8
oa->write_character(to_char_type(0xD0)); oa->write_character(to_char_type(0xD0));
write_number(static_cast<int8_t>(j.m_value.number_integer)); write_number(static_cast<std::int8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= (std::numeric_limits<int16_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int16_t>::min)() and
j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)()) j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
{ {
// int 16 // int 16
oa->write_character(to_char_type(0xD1)); oa->write_character(to_char_type(0xD1));
write_number(static_cast<int16_t>(j.m_value.number_integer)); write_number(static_cast<std::int16_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= (std::numeric_limits<int32_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int32_t>::min)() and
j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)()) j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
{ {
// int 32 // int 32
oa->write_character(to_char_type(0xD2)); oa->write_character(to_char_type(0xD2));
write_number(static_cast<int32_t>(j.m_value.number_integer)); write_number(static_cast<std::int32_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_integer >= (std::numeric_limits<int64_t>::min)() and else if (j.m_value.number_integer >= (std::numeric_limits<std::int64_t>::min)() and
j.m_value.number_integer <= (std::numeric_limits<int64_t>::max)()) j.m_value.number_integer <= (std::numeric_limits<std::int64_t>::max)())
{ {
// int 64 // int 64
oa->write_character(to_char_type(0xD3)); oa->write_character(to_char_type(0xD3));
write_number(static_cast<int64_t>(j.m_value.number_integer)); write_number(static_cast<std::int64_t>(j.m_value.number_integer));
} }
} }
break; break;
@ -403,31 +404,31 @@ class binary_writer
if (j.m_value.number_unsigned < 128) if (j.m_value.number_unsigned < 128)
{ {
// positive fixnum // positive fixnum
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
{ {
// uint 8 // uint 8
oa->write_character(to_char_type(0xCC)); oa->write_character(to_char_type(0xCC));
write_number(static_cast<uint8_t>(j.m_value.number_integer)); write_number(static_cast<std::uint8_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint16_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint16_t>::max)())
{ {
// uint 16 // uint 16
oa->write_character(to_char_type(0xCD)); oa->write_character(to_char_type(0xCD));
write_number(static_cast<uint16_t>(j.m_value.number_integer)); write_number(static_cast<std::uint16_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint32_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint32_t>::max)())
{ {
// uint 32 // uint 32
oa->write_character(to_char_type(0xCE)); oa->write_character(to_char_type(0xCE));
write_number(static_cast<uint32_t>(j.m_value.number_integer)); write_number(static_cast<std::uint32_t>(j.m_value.number_integer));
} }
else if (j.m_value.number_unsigned <= (std::numeric_limits<uint64_t>::max)()) else if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint64_t>::max)())
{ {
// uint 64 // uint 64
oa->write_character(to_char_type(0xCF)); oa->write_character(to_char_type(0xCF));
write_number(static_cast<uint64_t>(j.m_value.number_integer)); write_number(static_cast<std::uint64_t>(j.m_value.number_integer));
} }
break; break;
} }
@ -446,25 +447,25 @@ class binary_writer
if (N <= 31) if (N <= 31)
{ {
// fixstr // fixstr
write_number(static_cast<uint8_t>(0xA0 | N)); write_number(static_cast<std::uint8_t>(0xA0 | N));
} }
else if (N <= (std::numeric_limits<uint8_t>::max)()) else if (N <= (std::numeric_limits<std::uint8_t>::max)())
{ {
// str 8 // str 8
oa->write_character(to_char_type(0xD9)); oa->write_character(to_char_type(0xD9));
write_number(static_cast<uint8_t>(N)); write_number(static_cast<std::uint8_t>(N));
} }
else if (N <= (std::numeric_limits<uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
// str 16 // str 16
oa->write_character(to_char_type(0xDA)); oa->write_character(to_char_type(0xDA));
write_number(static_cast<uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
// str 32 // str 32
oa->write_character(to_char_type(0xDB)); oa->write_character(to_char_type(0xDB));
write_number(static_cast<uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
// step 2: write the string // step 2: write the string
@ -481,19 +482,19 @@ class binary_writer
if (N <= 15) if (N <= 15)
{ {
// fixarray // fixarray
write_number(static_cast<uint8_t>(0x90 | N)); write_number(static_cast<std::uint8_t>(0x90 | N));
} }
else if (N <= (std::numeric_limits<uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
// array 16 // array 16
oa->write_character(to_char_type(0xDC)); oa->write_character(to_char_type(0xDC));
write_number(static_cast<uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
// array 32 // array 32
oa->write_character(to_char_type(0xDD)); oa->write_character(to_char_type(0xDD));
write_number(static_cast<uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
// step 2: write each element // step 2: write each element
@ -511,19 +512,19 @@ class binary_writer
if (N <= 15) if (N <= 15)
{ {
// fixmap // fixmap
write_number(static_cast<uint8_t>(0x80 | (N & 0xF))); write_number(static_cast<std::uint8_t>(0x80 | (N & 0xF)));
} }
else if (N <= (std::numeric_limits<uint16_t>::max)()) else if (N <= (std::numeric_limits<std::uint16_t>::max)())
{ {
// map 16 // map 16
oa->write_character(to_char_type(0xDE)); oa->write_character(to_char_type(0xDE));
write_number(static_cast<uint16_t>(N)); write_number(static_cast<std::uint16_t>(N));
} }
else if (N <= (std::numeric_limits<uint32_t>::max)()) else if (N <= (std::numeric_limits<std::uint32_t>::max)())
{ {
// map 32 // map 32
oa->write_character(to_char_type(0xDF)); oa->write_character(to_char_type(0xDF));
write_number(static_cast<uint32_t>(N)); write_number(static_cast<std::uint32_t>(N));
} }
// step 2: write each element // step 2: write each element
@ -789,14 +790,9 @@ 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)
{ {
if ((std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)()) return (std::numeric_limits<std::int32_t>::min)() <= value and value <= (std::numeric_limits<std::int32_t>::max)()
{ ? sizeof(std::int32_t)
return sizeof(std::int32_t); : sizeof(std::int64_t);
}
else
{
return sizeof(std::int64_t);
}
} }
/*! /*!
@ -1064,45 +1060,45 @@ class binary_writer
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)
{ {
if (n <= static_cast<uint64_t>((std::numeric_limits<int8_t>::max)())) if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int8_t>::max)()))
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('i')); // int8 oa->write_character(to_char_type('i')); // int8
} }
write_number(static_cast<uint8_t>(n)); write_number(static_cast<std::uint8_t>(n));
} }
else if (n <= (std::numeric_limits<uint8_t>::max)()) else if (n <= (std::numeric_limits<std::uint8_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('U')); // uint8 oa->write_character(to_char_type('U')); // uint8
} }
write_number(static_cast<uint8_t>(n)); write_number(static_cast<std::uint8_t>(n));
} }
else if (n <= static_cast<uint64_t>((std::numeric_limits<int16_t>::max)())) else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int16_t>::max)()))
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('I')); // int16 oa->write_character(to_char_type('I')); // int16
} }
write_number(static_cast<int16_t>(n)); write_number(static_cast<std::int16_t>(n));
} }
else if (n <= static_cast<uint64_t>((std::numeric_limits<int32_t>::max)())) else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int32_t>::max)()))
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('l')); // int32 oa->write_character(to_char_type('l')); // int32
} }
write_number(static_cast<int32_t>(n)); write_number(static_cast<std::int32_t>(n));
} }
else if (n <= static_cast<uint64_t>((std::numeric_limits<int64_t>::max)())) else if (n <= static_cast<std::uint64_t>((std::numeric_limits<std::int64_t>::max)()))
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('L')); // int64 oa->write_character(to_char_type('L')); // int64
} }
write_number(static_cast<int64_t>(n)); write_number(static_cast<std::int64_t>(n));
} }
else else
{ {
@ -1117,45 +1113,45 @@ class binary_writer
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)
{ {
if ((std::numeric_limits<int8_t>::min)() <= n and n <= (std::numeric_limits<int8_t>::max)()) if ((std::numeric_limits<std::int8_t>::min)() <= n and n <= (std::numeric_limits<std::int8_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('i')); // int8 oa->write_character(to_char_type('i')); // int8
} }
write_number(static_cast<int8_t>(n)); write_number(static_cast<std::int8_t>(n));
} }
else if (static_cast<int64_t>((std::numeric_limits<uint8_t>::min)()) <= n and n <= static_cast<int64_t>((std::numeric_limits<uint8_t>::max)())) else if (static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::min)()) <= n and n <= static_cast<std::int64_t>((std::numeric_limits<std::uint8_t>::max)()))
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('U')); // uint8 oa->write_character(to_char_type('U')); // uint8
} }
write_number(static_cast<uint8_t>(n)); write_number(static_cast<std::uint8_t>(n));
} }
else if ((std::numeric_limits<int16_t>::min)() <= n and n <= (std::numeric_limits<int16_t>::max)()) else if ((std::numeric_limits<std::int16_t>::min)() <= n and n <= (std::numeric_limits<std::int16_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('I')); // int16 oa->write_character(to_char_type('I')); // int16
} }
write_number(static_cast<int16_t>(n)); write_number(static_cast<std::int16_t>(n));
} }
else if ((std::numeric_limits<int32_t>::min)() <= n and n <= (std::numeric_limits<int32_t>::max)()) else if ((std::numeric_limits<std::int32_t>::min)() <= n and n <= (std::numeric_limits<std::int32_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('l')); // int32 oa->write_character(to_char_type('l')); // int32
} }
write_number(static_cast<int32_t>(n)); write_number(static_cast<std::int32_t>(n));
} }
else if ((std::numeric_limits<int64_t>::min)() <= n and n <= (std::numeric_limits<int64_t>::max)()) else if ((std::numeric_limits<std::int64_t>::min)() <= n and n <= (std::numeric_limits<std::int64_t>::max)())
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(to_char_type('L')); // int64 oa->write_character(to_char_type('L')); // int64
} }
write_number(static_cast<int64_t>(n)); write_number(static_cast<std::int64_t>(n));
} }
// LCOV_EXCL_START // LCOV_EXCL_START
else else
@ -1186,19 +1182,19 @@ class binary_writer
case value_t::number_integer: case value_t::number_integer:
{ {
if ((std::numeric_limits<int8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int8_t>::max)()) if ((std::numeric_limits<std::int8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int8_t>::max)())
{ {
return 'i'; return 'i';
} }
if ((std::numeric_limits<uint8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<uint8_t>::max)()) if ((std::numeric_limits<std::uint8_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::uint8_t>::max)())
{ {
return 'U'; return 'U';
} }
if ((std::numeric_limits<int16_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int16_t>::max)()) if ((std::numeric_limits<std::int16_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int16_t>::max)())
{ {
return 'I'; return 'I';
} }
if ((std::numeric_limits<int32_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<int32_t>::max)()) if ((std::numeric_limits<std::int32_t>::min)() <= j.m_value.number_integer and j.m_value.number_integer <= (std::numeric_limits<std::int32_t>::max)())
{ {
return 'l'; return 'l';
} }
@ -1208,19 +1204,19 @@ class binary_writer
case value_t::number_unsigned: case value_t::number_unsigned:
{ {
if (j.m_value.number_unsigned <= (std::numeric_limits<int8_t>::max)()) if (j.m_value.number_unsigned <= (std::numeric_limits<std::int8_t>::max)())
{ {
return 'i'; return 'i';
} }
if (j.m_value.number_unsigned <= (std::numeric_limits<uint8_t>::max)()) if (j.m_value.number_unsigned <= (std::numeric_limits<std::uint8_t>::max)())
{ {
return 'U'; return 'U';
} }
if (j.m_value.number_unsigned <= (std::numeric_limits<int16_t>::max)()) if (j.m_value.number_unsigned <= (std::numeric_limits<std::int16_t>::max)())
{ {
return 'I'; return 'I';
} }
if (j.m_value.number_unsigned <= (std::numeric_limits<int32_t>::max)()) if (j.m_value.number_unsigned <= (std::numeric_limits<std::int32_t>::max)())
{ {
return 'l'; return 'l';
} }
@ -1278,7 +1274,7 @@ class binary_writer
std::memcpy(vec.data(), &n, sizeof(NumberType)); std::memcpy(vec.data(), &n, sizeof(NumberType));
// step 2: write array to output (with possible reordering) // step 2: write array to output (with possible reordering)
if (is_little_endian and not OutputIsLittleEndian) if (is_little_endian != OutputIsLittleEndian)
{ {
// reverse byte order prior to conversion if necessary // reverse byte order prior to conversion if necessary
std::reverse(vec.begin(), vec.end()); std::reverse(vec.begin(), vec.end());

View file

@ -12,9 +12,10 @@
#include <limits> // numeric_limits #include <limits> // numeric_limits
#include <string> // string #include <string> // string
#include <type_traits> // is_same #include <type_traits> // is_same
#include <utility> // move
#include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/conversions/to_chars.hpp> #include <nlohmann/detail/conversions/to_chars.hpp>
#include <nlohmann/detail/exceptions.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/output/binary_writer.hpp> #include <nlohmann/detail/output/binary_writer.hpp>
@ -44,8 +45,8 @@ class serializer
using number_float_t = typename BasicJsonType::number_float_t; using number_float_t = typename BasicJsonType::number_float_t;
using number_integer_t = typename BasicJsonType::number_integer_t; using number_integer_t = typename BasicJsonType::number_integer_t;
using number_unsigned_t = typename BasicJsonType::number_unsigned_t; using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
static constexpr uint8_t UTF8_ACCEPT = 0; static constexpr std::uint8_t UTF8_ACCEPT = 0;
static constexpr uint8_t UTF8_REJECT = 1; static constexpr std::uint8_t UTF8_REJECT = 1;
public: public:
/*! /*!
@ -277,6 +278,9 @@ class serializer
o->write_characters("null", 4); o->write_characters("null", 4);
return; return;
} }
default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE
} }
} }
@ -297,8 +301,8 @@ class serializer
*/ */
void dump_escaped(const string_t& s, const bool ensure_ascii) void dump_escaped(const string_t& s, const bool ensure_ascii)
{ {
uint32_t codepoint; std::uint32_t codepoint;
uint8_t state = UTF8_ACCEPT; std::uint8_t state = UTF8_ACCEPT;
std::size_t bytes = 0; // number of bytes written to string_buffer std::size_t bytes = 0; // number of bytes written to string_buffer
// number of bytes written at the point of the last valid byte // number of bytes written at the point of the last valid byte
@ -373,14 +377,14 @@ class serializer
if (codepoint <= 0xFFFF) if (codepoint <= 0xFFFF)
{ {
(std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x", (std::snprintf)(string_buffer.data() + bytes, 7, "\\u%04x",
static_cast<uint16_t>(codepoint)); static_cast<std::uint16_t>(codepoint));
bytes += 6; bytes += 6;
} }
else else
{ {
(std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x", (std::snprintf)(string_buffer.data() + bytes, 13, "\\u%04x\\u%04x",
static_cast<uint16_t>(0xD7C0 + (codepoint >> 10)), static_cast<std::uint16_t>(0xD7C0u + (codepoint >> 10u)),
static_cast<uint16_t>(0xDC00 + (codepoint & 0x3FF))); static_cast<std::uint16_t>(0xDC00u + (codepoint & 0x3FFu)));
bytes += 12; bytes += 12;
} }
} }
@ -454,6 +458,16 @@ class serializer
string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBF'); string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBF');
string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBD'); string_buffer[bytes++] = detail::binary_writer<BasicJsonType, char>::to_char_type('\xBD');
} }
// write buffer and reset index; there must be 13 bytes
// left, as this is the maximal number of bytes to be
// written ("\uxxxx\uxxxx\0") for one code point
if (string_buffer.size() - bytes < 13)
{
o->write_characters(string_buffer.data(), bytes);
bytes = 0;
}
bytes_after_last_accept = bytes; bytes_after_last_accept = bytes;
} }
@ -463,6 +477,9 @@ class serializer
state = UTF8_ACCEPT; state = UTF8_ACCEPT;
break; break;
} }
default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE
} }
break; break;
} }
@ -497,7 +514,7 @@ class serializer
case error_handler_t::strict: case error_handler_t::strict:
{ {
std::string sn(3, '\0'); std::string sn(3, '\0');
(std::snprintf)(&sn[0], sn.size(), "%.2X", static_cast<uint8_t>(s.back())); (std::snprintf)(&sn[0], sn.size(), "%.2X", static_cast<std::uint8_t>(s.back()));
JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn)); JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn));
} }
@ -523,6 +540,9 @@ class serializer
} }
break; break;
} }
default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE
} }
} }
} }
@ -579,16 +599,16 @@ class serializer
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'}}, {{'0', '1'}}, {{'0', '2'}}, {{'0', '3'}}, {{'0', '4'}}, {{'0', '5'}}, {{'0', '6'}}, {{'0', '7'}}, {{'0', '8'}}, {{'0', '9'}},
{'1', '0'}, {'1', '1'}, {'1', '2'}, {'1', '3'}, {'1', '4'}, {'1', '5'}, {'1', '6'}, {'1', '7'}, {'1', '8'}, {'1', '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'}, {{'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'}, {{'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'}, {{'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'}, {{'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'}, {{'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'}, {{'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'}, {{'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'}, {{'9', '0'}}, {{'9', '1'}}, {{'9', '2'}}, {{'9', '3'}}, {{'9', '4'}}, {{'9', '5'}}, {{'9', '6'}}, {{'9', '7'}}, {{'9', '8'}}, {{'9', '9'}},
} }
}; };
@ -600,7 +620,7 @@ class serializer
} }
// use a pointer to fill the buffer // use a pointer to fill the buffer
auto buffer_ptr = begin(number_buffer); auto buffer_ptr = number_buffer.begin();
const bool is_negative = std::is_same<NumberType, number_integer_t>::value and not(x >= 0); // see issue #755 const bool is_negative = std::is_same<NumberType, number_integer_t>::value and not(x >= 0); // see issue #755
number_unsigned_t abs_value; number_unsigned_t abs_value;
@ -610,7 +630,7 @@ class serializer
if (is_negative) if (is_negative)
{ {
*buffer_ptr = '-'; *buffer_ptr = '-';
abs_value = static_cast<number_unsigned_t>(0 - x); abs_value = static_cast<number_unsigned_t>(std::abs(static_cast<std::intmax_t>(x)));
// account one more byte for the minus sign // account one more byte for the minus sign
n_chars = 1 + count_digits(abs_value); n_chars = 1 + count_digits(abs_value);
@ -630,7 +650,6 @@ class serializer
// Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu // Fast int2ascii implementation inspired by "Fastware" talk by Andrei Alexandrescu
// See: https://www.youtube.com/watch?v=o4-CwDo2zpg // See: https://www.youtube.com/watch?v=o4-CwDo2zpg
const auto buffer_end = buffer_ptr;
while (abs_value >= 100) while (abs_value >= 100)
{ {
const auto digits_index = static_cast<unsigned>((abs_value % 100)); const auto digits_index = static_cast<unsigned>((abs_value % 100));
@ -730,7 +749,7 @@ class serializer
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 == '.' or c == 'e'); return c == '.' or c == 'e';
}); });
if (value_is_int_like) if (value_is_int_like)
@ -760,9 +779,9 @@ class serializer
@copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de> @copyright Copyright (c) 2008-2009 Bjoern Hoehrmann <bjoern@hoehrmann.de>
@sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ @sa http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
*/ */
static uint8_t decode(uint8_t& state, uint32_t& codep, const 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<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, // 00..1F
@ -782,11 +801,11 @@ class serializer
} }
}; };
const uint8_t type = utf8d[byte]; const std::uint8_t type = utf8d[byte];
codep = (state != UTF8_ACCEPT) codep = (state != UTF8_ACCEPT)
? (byte & 0x3fu) | (codep << 6) ? (byte & 0x3fu) | (codep << 6u)
: static_cast<uint32_t>(0xff >> type) & (byte); : (0xFFu >> type) & (byte);
state = utf8d[256u + state * 16u + type]; state = utf8d[256u + state * 16u + type];
return state; return state;

View file

@ -4,6 +4,7 @@
#include <ciso646> // and #include <ciso646> // and
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdint> // uint8_t #include <cstdint> // uint8_t
#include <string> // string
namespace nlohmann namespace nlohmann
{ {

View file

@ -27,8 +27,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
#ifndef NLOHMANN_JSON_HPP #ifndef INCLUDE_NLOHMANN_JSON_HPP_
#define NLOHMANN_JSON_HPP #define INCLUDE_NLOHMANN_JSON_HPP_
#define NLOHMANN_JSON_VERSION_MAJOR 3 #define NLOHMANN_JSON_VERSION_MAJOR 3
#define NLOHMANN_JSON_VERSION_MINOR 5 #define NLOHMANN_JSON_VERSION_MINOR 5
@ -42,33 +42,35 @@ SOFTWARE.
#include <initializer_list> // initializer_list #include <initializer_list> // initializer_list
#include <iosfwd> // istream, ostream #include <iosfwd> // istream, ostream
#include <iterator> // random_access_iterator_tag #include <iterator> // random_access_iterator_tag
#include <memory> // unique_ptr
#include <numeric> // accumulate #include <numeric> // accumulate
#include <string> // string, stoi, to_string #include <string> // string, stoi, to_string
#include <utility> // declval, forward, move, pair, swap #include <utility> // declval, forward, move, pair, swap
#include <vector> // vector
#include <nlohmann/json_fwd.hpp> #include <nlohmann/adl_serializer.hpp>
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>
#include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/value_t.hpp>
#include <nlohmann/detail/conversions/from_json.hpp> #include <nlohmann/detail/conversions/from_json.hpp>
#include <nlohmann/detail/conversions/to_json.hpp> #include <nlohmann/detail/conversions/to_json.hpp>
#include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/input/binary_reader.hpp>
#include <nlohmann/detail/input/input_adapters.hpp> #include <nlohmann/detail/input/input_adapters.hpp>
#include <nlohmann/detail/input/lexer.hpp> #include <nlohmann/detail/input/lexer.hpp>
#include <nlohmann/detail/input/parser.hpp> #include <nlohmann/detail/input/parser.hpp>
#include <nlohmann/detail/iterators/primitive_iterator.hpp>
#include <nlohmann/detail/iterators/internal_iterator.hpp> #include <nlohmann/detail/iterators/internal_iterator.hpp>
#include <nlohmann/detail/iterators/iter_impl.hpp> #include <nlohmann/detail/iterators/iter_impl.hpp>
#include <nlohmann/detail/iterators/iteration_proxy.hpp> #include <nlohmann/detail/iterators/iteration_proxy.hpp>
#include <nlohmann/detail/iterators/json_reverse_iterator.hpp> #include <nlohmann/detail/iterators/json_reverse_iterator.hpp>
#include <nlohmann/detail/output/output_adapters.hpp> #include <nlohmann/detail/iterators/primitive_iterator.hpp>
#include <nlohmann/detail/input/binary_reader.hpp>
#include <nlohmann/detail/output/binary_writer.hpp>
#include <nlohmann/detail/output/serializer.hpp>
#include <nlohmann/detail/json_ref.hpp>
#include <nlohmann/detail/json_pointer.hpp> #include <nlohmann/detail/json_pointer.hpp>
#include <nlohmann/adl_serializer.hpp> #include <nlohmann/detail/json_ref.hpp>
#include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>
#include <nlohmann/detail/output/binary_writer.hpp>
#include <nlohmann/detail/output/output_adapters.hpp>
#include <nlohmann/detail/output/serializer.hpp>
#include <nlohmann/detail/value_t.hpp>
#include <nlohmann/json_fwd.hpp>
/*! /*!
@brief namespace for Niels Lohmann @brief namespace for Niels Lohmann
@ -317,6 +319,7 @@ class basic_json
@since 2.1.0 @since 2.1.0
*/ */
JSON_NODISCARD
static basic_json meta() static basic_json meta()
{ {
basic_json result; basic_json result;
@ -1322,6 +1325,8 @@ class basic_json
case value_t::discarded: case value_t::discarded:
m_type = value_t::discarded; m_type = value_t::discarded;
break; break;
default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE
} }
assert_invariant(); assert_invariant();
} }
@ -1409,7 +1414,7 @@ class basic_json
bool is_an_object = std::all_of(init.begin(), init.end(), bool is_an_object = std::all_of(init.begin(), init.end(),
[](const detail::json_ref<basic_json>& element_ref) [](const detail::json_ref<basic_json>& element_ref)
{ {
return (element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string()); return element_ref->is_array() and element_ref->size() == 2 and (*element_ref)[0].is_string();
}); });
// adjust type if type deduction is not wanted // adjust type if type deduction is not wanted
@ -1489,6 +1494,7 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
JSON_NODISCARD
static basic_json array(initializer_list_t init = {}) static basic_json array(initializer_list_t init = {})
{ {
return basic_json(init, false, value_t::array); return basic_json(init, false, value_t::array);
@ -1532,6 +1538,7 @@ class basic_json
@since version 1.0.0 @since version 1.0.0
*/ */
JSON_NODISCARD
static basic_json object(initializer_list_t init = {}) static basic_json object(initializer_list_t init = {})
{ {
return basic_json(init, false, value_t::object); return basic_json(init, false, value_t::object);
@ -2092,7 +2099,7 @@ class basic_json
*/ */
constexpr bool is_null() const noexcept constexpr bool is_null() const noexcept
{ {
return (m_type == value_t::null); return m_type == value_t::null;
} }
/*! /*!
@ -2114,7 +2121,7 @@ class basic_json
*/ */
constexpr bool is_boolean() const noexcept constexpr bool is_boolean() const noexcept
{ {
return (m_type == value_t::boolean); return m_type == value_t::boolean;
} }
/*! /*!
@ -2173,7 +2180,7 @@ class basic_json
*/ */
constexpr bool is_number_integer() const noexcept constexpr bool is_number_integer() const noexcept
{ {
return (m_type == value_t::number_integer or m_type == value_t::number_unsigned); return m_type == value_t::number_integer or m_type == value_t::number_unsigned;
} }
/*! /*!
@ -2201,7 +2208,7 @@ class basic_json
*/ */
constexpr bool is_number_unsigned() const noexcept constexpr bool is_number_unsigned() const noexcept
{ {
return (m_type == value_t::number_unsigned); return m_type == value_t::number_unsigned;
} }
/*! /*!
@ -2229,7 +2236,7 @@ class basic_json
*/ */
constexpr bool is_number_float() const noexcept constexpr bool is_number_float() const noexcept
{ {
return (m_type == value_t::number_float); return m_type == value_t::number_float;
} }
/*! /*!
@ -2251,7 +2258,7 @@ class basic_json
*/ */
constexpr bool is_object() const noexcept constexpr bool is_object() const noexcept
{ {
return (m_type == value_t::object); return m_type == value_t::object;
} }
/*! /*!
@ -2273,7 +2280,7 @@ class basic_json
*/ */
constexpr bool is_array() const noexcept constexpr bool is_array() const noexcept
{ {
return (m_type == value_t::array); return m_type == value_t::array;
} }
/*! /*!
@ -2295,7 +2302,7 @@ class basic_json
*/ */
constexpr bool is_string() const noexcept constexpr bool is_string() const noexcept
{ {
return (m_type == value_t::string); return m_type == value_t::string;
} }
/*! /*!
@ -2322,7 +2329,7 @@ class basic_json
*/ */
constexpr bool is_discarded() const noexcept constexpr bool is_discarded() const noexcept
{ {
return (m_type == value_t::discarded); return m_type == value_t::discarded;
} }
/*! /*!
@ -2856,7 +2863,7 @@ class basic_json
#ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015 #ifndef _MSC_VER // fix for issue #167 operator<< ambiguity under VS2015
and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value and not std::is_same<ValueType, std::initializer_list<typename string_t::value_type>>::value
#if defined(JSON_HAS_CPP_17) && defined(_MSC_VER) and _MSC_VER <= 1914 #if defined(JSON_HAS_CPP_17) && (defined(__GNUC__) || (defined(_MSC_VER) and _MSC_VER <= 1914))
and not std::is_same<ValueType, typename std::string_view>::value and not std::is_same<ValueType, typename std::string_view>::value
#endif #endif
#endif #endif
@ -3894,6 +3901,8 @@ class basic_json
@liveexample{The example shows how `find()` is used.,find__key_type} @liveexample{The example shows how `find()` is used.,find__key_type}
@sa @ref contains(KeyT&&) const -- checks whether a key exists
@since version 1.0.0 @since version 1.0.0
*/ */
template<typename KeyT> template<typename KeyT>
@ -3954,6 +3963,36 @@ class basic_json
return is_object() ? m_value.object->count(std::forward<KeyT>(key)) : 0; return is_object() ? m_value.object->count(std::forward<KeyT>(key)) : 0;
} }
/*!
@brief check the existence of an element in a JSON object
Check whether an element exists in a JSON object with key equivalent to
@a key. If the element is not found or the JSON value is not an object,
false is returned.
@note This method always returns false when executed on a JSON type
that is not an object.
@param[in] key key value to check its existence.
@return true if an element with specified @a key exists. If no such
element with such key is found or the JSON value is not an object,
false is returned.
@complexity Logarithmic in the size of the JSON object.
@liveexample{The following code shows an example for `contains()`.,contains}
@sa @ref find(KeyT&&) -- returns an iterator to an object element
@since version 3.6.0
*/
template<typename KeyT>
bool contains(KeyT&& key) const
{
return is_object() and m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end();
}
/// @} /// @}
@ -5530,28 +5569,28 @@ class basic_json
switch (lhs_type) switch (lhs_type)
{ {
case value_t::array: case value_t::array:
return (*lhs.m_value.array == *rhs.m_value.array); return *lhs.m_value.array == *rhs.m_value.array;
case value_t::object: case value_t::object:
return (*lhs.m_value.object == *rhs.m_value.object); return *lhs.m_value.object == *rhs.m_value.object;
case value_t::null: case value_t::null:
return true; return true;
case value_t::string: case value_t::string:
return (*lhs.m_value.string == *rhs.m_value.string); return *lhs.m_value.string == *rhs.m_value.string;
case value_t::boolean: case value_t::boolean:
return (lhs.m_value.boolean == rhs.m_value.boolean); return lhs.m_value.boolean == rhs.m_value.boolean;
case value_t::number_integer: case value_t::number_integer:
return (lhs.m_value.number_integer == rhs.m_value.number_integer); return lhs.m_value.number_integer == rhs.m_value.number_integer;
case value_t::number_unsigned: case value_t::number_unsigned:
return (lhs.m_value.number_unsigned == rhs.m_value.number_unsigned); return lhs.m_value.number_unsigned == rhs.m_value.number_unsigned;
case value_t::number_float: case value_t::number_float:
return (lhs.m_value.number_float == rhs.m_value.number_float); return lhs.m_value.number_float == rhs.m_value.number_float;
default: default:
return false; return false;
@ -5559,27 +5598,27 @@ class basic_json
} }
else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float) else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_float)
{ {
return (static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float); return static_cast<number_float_t>(lhs.m_value.number_integer) == rhs.m_value.number_float;
} }
else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer) else if (lhs_type == value_t::number_float and rhs_type == value_t::number_integer)
{ {
return (lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer)); return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_integer);
} }
else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float) else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_float)
{ {
return (static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float); return static_cast<number_float_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_float;
} }
else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned) else if (lhs_type == value_t::number_float and rhs_type == value_t::number_unsigned)
{ {
return (lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned)); return lhs.m_value.number_float == static_cast<number_float_t>(rhs.m_value.number_unsigned);
} }
else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer) else if (lhs_type == value_t::number_unsigned and rhs_type == value_t::number_integer)
{ {
return (static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer); return static_cast<number_integer_t>(lhs.m_value.number_unsigned) == rhs.m_value.number_integer;
} }
else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned) else if (lhs_type == value_t::number_integer and rhs_type == value_t::number_unsigned)
{ {
return (lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned)); return lhs.m_value.number_integer == static_cast<number_integer_t>(rhs.m_value.number_unsigned);
} }
return false; return false;
@ -5593,7 +5632,7 @@ class basic_json
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept friend bool operator==(const_reference lhs, const ScalarType rhs) noexcept
{ {
return (lhs == basic_json(rhs)); return lhs == basic_json(rhs);
} }
/*! /*!
@ -5604,7 +5643,7 @@ class basic_json
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept friend bool operator==(const ScalarType lhs, const_reference rhs) noexcept
{ {
return (basic_json(lhs) == rhs); return basic_json(lhs) == rhs;
} }
/*! /*!
@ -5638,7 +5677,7 @@ class basic_json
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept friend bool operator!=(const_reference lhs, const ScalarType rhs) noexcept
{ {
return (lhs != basic_json(rhs)); return lhs != basic_json(rhs);
} }
/*! /*!
@ -5649,7 +5688,7 @@ class basic_json
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept friend bool operator!=(const ScalarType lhs, const_reference rhs) noexcept
{ {
return (basic_json(lhs) != rhs); return basic_json(lhs) != rhs;
} }
/*! /*!
@ -5688,7 +5727,7 @@ class basic_json
switch (lhs_type) switch (lhs_type)
{ {
case value_t::array: case value_t::array:
return (*lhs.m_value.array) < (*rhs.m_value.array); return *lhs.m_value.array < *rhs.m_value.array;
case value_t::object: case value_t::object:
return *lhs.m_value.object < *rhs.m_value.object; return *lhs.m_value.object < *rhs.m_value.object;
@ -5754,7 +5793,7 @@ class basic_json
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept friend bool operator<(const_reference lhs, const ScalarType rhs) noexcept
{ {
return (lhs < basic_json(rhs)); return lhs < basic_json(rhs);
} }
/*! /*!
@ -5765,7 +5804,7 @@ class basic_json
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept friend bool operator<(const ScalarType lhs, const_reference rhs) noexcept
{ {
return (basic_json(lhs) < rhs); return basic_json(lhs) < rhs;
} }
/*! /*!
@ -5800,7 +5839,7 @@ class basic_json
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept friend bool operator<=(const_reference lhs, const ScalarType rhs) noexcept
{ {
return (lhs <= basic_json(rhs)); return lhs <= basic_json(rhs);
} }
/*! /*!
@ -5811,7 +5850,7 @@ class basic_json
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept friend bool operator<=(const ScalarType lhs, const_reference rhs) noexcept
{ {
return (basic_json(lhs) <= rhs); return basic_json(lhs) <= rhs;
} }
/*! /*!
@ -5846,7 +5885,7 @@ class basic_json
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept friend bool operator>(const_reference lhs, const ScalarType rhs) noexcept
{ {
return (lhs > basic_json(rhs)); return lhs > basic_json(rhs);
} }
/*! /*!
@ -5857,7 +5896,7 @@ class basic_json
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept friend bool operator>(const ScalarType lhs, const_reference rhs) noexcept
{ {
return (basic_json(lhs) > rhs); return basic_json(lhs) > rhs;
} }
/*! /*!
@ -5892,7 +5931,7 @@ class basic_json
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept friend bool operator>=(const_reference lhs, const ScalarType rhs) noexcept
{ {
return (lhs >= basic_json(rhs)); return lhs >= basic_json(rhs);
} }
/*! /*!
@ -5903,7 +5942,7 @@ class basic_json
std::is_scalar<ScalarType>::value, int>::type = 0> std::is_scalar<ScalarType>::value, int>::type = 0>
friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept friend bool operator>=(const ScalarType lhs, const_reference rhs) noexcept
{ {
return (basic_json(lhs) >= rhs); return basic_json(lhs) >= rhs;
} }
/// @} /// @}
@ -5949,8 +5988,8 @@ class basic_json
friend std::ostream& operator<<(std::ostream& o, const basic_json& j) friend std::ostream& operator<<(std::ostream& o, const basic_json& j)
{ {
// read width member and use it as indentation parameter if nonzero // read width member and use it as indentation parameter if nonzero
const bool pretty_print = (o.width() > 0); const bool pretty_print = o.width() > 0;
const auto indentation = (pretty_print ? o.width() : 0); const auto indentation = pretty_print ? o.width() : 0;
// reset width to 0 for subsequent calls to this stream // reset width to 0 for subsequent calls to this stream
o.width(0); o.width(0);
@ -6006,9 +6045,6 @@ class basic_json
@pre The container storage is contiguous. Violating this precondition @pre The container storage is contiguous. Violating this precondition
yields undefined behavior. **This precondition is enforced with an yields undefined behavior. **This precondition is enforced with an
assertion.** assertion.**
@pre Each element of the container has a size of 1 byte. Violating this
precondition yields undefined behavior. **This precondition is enforced
with a static assertion.**
@warning There is no way to enforce all preconditions at compile-time. If @warning There is no way to enforce all preconditions at compile-time. If
the function is called with a noncompliant container and with the function is called with a noncompliant container and with
@ -6051,6 +6087,7 @@ class basic_json
@since version 2.0.3 (contiguous containers) @since version 2.0.3 (contiguous containers)
*/ */
JSON_NODISCARD
static basic_json parse(detail::input_adapter&& i, static basic_json parse(detail::input_adapter&& i,
const parser_callback_t cb = nullptr, const parser_callback_t cb = nullptr,
const bool allow_exceptions = true) const bool allow_exceptions = true)
@ -6088,9 +6125,6 @@ class basic_json
@pre The container storage is contiguous. Violating this precondition @pre The container storage is contiguous. Violating this precondition
yields undefined behavior. **This precondition is enforced with an yields undefined behavior. **This precondition is enforced with an
assertion.** assertion.**
@pre Each element of the container has a size of 1 byte. Violating this
precondition yields undefined behavior. **This precondition is enforced
with a static assertion.**
@warning There is no way to enforce all preconditions at compile-time. If @warning There is no way to enforce all preconditions at compile-time. If
the function is called with a noncompliant container and with the function is called with a noncompliant container and with
@ -6127,13 +6161,9 @@ class basic_json
const bool strict = true) const bool strict = true)
{ {
assert(sax); assert(sax);
switch (format) return format == input_format_t::json
{ ? parser(std::move(i)).sax_parse(sax, strict)
case input_format_t::json: : detail::binary_reader<basic_json, SAX>(std::move(i)).sax_parse(format, sax, strict);
return parser(std::move(i)).sax_parse(sax, strict);
default:
return detail::binary_reader<basic_json, SAX>(std::move(i)).sax_parse(format, sax, strict);
}
} }
/*! /*!
@ -6826,6 +6856,7 @@ class basic_json
@a strict parameter since 3.0.0; added @a allow_exceptions parameter @a strict parameter since 3.0.0; added @a allow_exceptions parameter
since 3.2.0 since 3.2.0
*/ */
JSON_NODISCARD
static basic_json from_cbor(detail::input_adapter&& i, static basic_json from_cbor(detail::input_adapter&& i,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
@ -6841,6 +6872,7 @@ class basic_json
*/ */
template<typename A1, typename A2, template<typename A1, typename A2,
detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0> detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>
JSON_NODISCARD
static basic_json from_cbor(A1 && a1, A2 && a2, static basic_json from_cbor(A1 && a1, A2 && a2,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
@ -6933,6 +6965,7 @@ class basic_json
@a strict parameter since 3.0.0; added @a allow_exceptions parameter @a strict parameter since 3.0.0; added @a allow_exceptions parameter
since 3.2.0 since 3.2.0
*/ */
JSON_NODISCARD
static basic_json from_msgpack(detail::input_adapter&& i, static basic_json from_msgpack(detail::input_adapter&& i,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
@ -6948,6 +6981,7 @@ class basic_json
*/ */
template<typename A1, typename A2, template<typename A1, typename A2,
detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0> detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>
JSON_NODISCARD
static basic_json from_msgpack(A1 && a1, A2 && a2, static basic_json from_msgpack(A1 && a1, A2 && a2,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
@ -7019,6 +7053,7 @@ class basic_json
@since version 3.1.0; added @a allow_exceptions parameter since 3.2.0 @since version 3.1.0; added @a allow_exceptions parameter since 3.2.0
*/ */
JSON_NODISCARD
static basic_json from_ubjson(detail::input_adapter&& i, static basic_json from_ubjson(detail::input_adapter&& i,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
@ -7034,6 +7069,7 @@ class basic_json
*/ */
template<typename A1, typename A2, template<typename A1, typename A2,
detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0> detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>
JSON_NODISCARD
static basic_json from_ubjson(A1 && a1, A2 && a2, static basic_json from_ubjson(A1 && a1, A2 && a2,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
@ -7104,6 +7140,7 @@ class basic_json
@sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the @sa @ref from_ubjson(detail::input_adapter&&, const bool, const bool) for the
related UBJSON format related UBJSON format
*/ */
JSON_NODISCARD
static basic_json from_bson(detail::input_adapter&& i, static basic_json from_bson(detail::input_adapter&& i,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
@ -7119,6 +7156,7 @@ class basic_json
*/ */
template<typename A1, typename A2, template<typename A1, typename A2,
detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0> detail::enable_if_t<std::is_constructible<detail::input_adapter, A1, A2>::value, int> = 0>
JSON_NODISCARD
static basic_json from_bson(A1 && a1, A2 && a2, static basic_json from_bson(A1 && a1, A2 && a2,
const bool strict = true, const bool strict = true,
const bool allow_exceptions = true) const bool allow_exceptions = true)
@ -7454,63 +7492,58 @@ class basic_json
const auto operation_add = [&result](json_pointer & ptr, basic_json val) const auto operation_add = [&result](json_pointer & ptr, basic_json val)
{ {
// adding to the root of the target document means replacing it // adding to the root of the target document means replacing it
if (ptr.is_root()) if (ptr.empty())
{ {
result = val; result = val;
return;
} }
else
// make sure the top element of the pointer exists
json_pointer top_pointer = ptr.top();
if (top_pointer != ptr)
{ {
// make sure the top element of the pointer exists result.at(top_pointer);
json_pointer top_pointer = ptr.top(); }
if (top_pointer != ptr)
// get reference to parent of JSON pointer ptr
const auto last_path = ptr.pop_back();
basic_json& parent = result[ptr];
switch (parent.m_type)
{
case value_t::null:
case value_t::object:
{ {
result.at(top_pointer); // use operator[] to add value
parent[last_path] = val;
break;
} }
// get reference to parent of JSON pointer ptr case value_t::array:
const auto last_path = ptr.pop_back();
basic_json& parent = result[ptr];
switch (parent.m_type)
{ {
case value_t::null: if (last_path == "-")
case value_t::object:
{ {
// use operator[] to add value // special case: append to back
parent[last_path] = val; parent.push_back(val);
break;
} }
else
case value_t::array:
{ {
if (last_path == "-") const auto idx = json_pointer::array_index(last_path);
if (JSON_UNLIKELY(static_cast<size_type>(idx) > parent.size()))
{ {
// special case: append to back // avoid undefined behavior
parent.push_back(val); JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
} }
else
{
const auto idx = json_pointer::array_index(last_path);
if (JSON_UNLIKELY(static_cast<size_type>(idx) > parent.size()))
{
// avoid undefined behavior
JSON_THROW(out_of_range::create(401, "array index " + std::to_string(idx) + " is out of range"));
}
// default case: insert add offset // default case: insert add offset
parent.insert(parent.begin() + static_cast<difference_type>(idx), val); parent.insert(parent.begin() + static_cast<difference_type>(idx), val);
}
break;
} }
break;
// LCOV_EXCL_START
default:
{
// if there exists a parent it cannot be primitive
assert(false);
}
// LCOV_EXCL_STOP
} }
// if there exists a parent it cannot be primitive
default: // LCOV_EXCL_LINE
assert(false); // LCOV_EXCL_LINE
} }
}; };
@ -7665,7 +7698,7 @@ class basic_json
break; break;
} }
case patch_operations::invalid: default:
{ {
// op must be "add", "remove", "replace", "move", "copy", or // op must be "add", "remove", "replace", "move", "copy", or
// "test" // "test"
@ -7710,6 +7743,7 @@ class basic_json
@since version 2.0.0 @since version 2.0.0
*/ */
JSON_NODISCARD
static basic_json diff(const basic_json& source, const basic_json& target, static basic_json diff(const basic_json& source, const basic_json& target,
const std::string& path = "") const std::string& path = "")
{ {
@ -7729,106 +7763,105 @@ class basic_json
{ {
{"op", "replace"}, {"path", path}, {"value", target} {"op", "replace"}, {"path", path}, {"value", target}
}); });
return result;
} }
else
switch (source.type())
{ {
switch (source.type()) case value_t::array:
{ {
case value_t::array: // first pass: traverse common elements
std::size_t i = 0;
while (i < source.size() and i < target.size())
{ {
// first pass: traverse common elements // recursive call to compare array values at index i
std::size_t i = 0; auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i));
while (i < source.size() and i < target.size()) result.insert(result.end(), temp_diff.begin(), temp_diff.end());
{ ++i;
// recursive call to compare array values at index i
auto temp_diff = diff(source[i], target[i], path + "/" + std::to_string(i));
result.insert(result.end(), temp_diff.begin(), temp_diff.end());
++i;
}
// i now reached the end of at least one array
// in a second pass, traverse the remaining elements
// remove my remaining elements
const auto end_index = static_cast<difference_type>(result.size());
while (i < source.size())
{
// add operations in reverse order to avoid invalid
// indices
result.insert(result.begin() + end_index, object(
{
{"op", "remove"},
{"path", path + "/" + std::to_string(i)}
}));
++i;
}
// add other remaining elements
while (i < target.size())
{
result.push_back(
{
{"op", "add"},
{"path", path + "/" + std::to_string(i)},
{"value", target[i]}
});
++i;
}
break;
} }
case value_t::object: // i now reached the end of at least one array
// in a second pass, traverse the remaining elements
// remove my remaining elements
const auto end_index = static_cast<difference_type>(result.size());
while (i < source.size())
{ {
// first pass: traverse this object's elements // add operations in reverse order to avoid invalid
for (auto it = source.cbegin(); it != source.cend(); ++it) // indices
result.insert(result.begin() + end_index, object(
{ {
// escape the key name to be used in a JSON patch {"op", "remove"},
const auto key = json_pointer::escape(it.key()); {"path", path + "/" + std::to_string(i)}
}));
if (target.find(it.key()) != target.end()) ++i;
{
// recursive call to compare object values at key it
auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key);
result.insert(result.end(), temp_diff.begin(), temp_diff.end());
}
else
{
// found a key that is not in o -> remove it
result.push_back(object(
{
{"op", "remove"}, {"path", path + "/" + key}
}));
}
}
// second pass: traverse other object's elements
for (auto it = target.cbegin(); it != target.cend(); ++it)
{
if (source.find(it.key()) == source.end())
{
// found a key that is not in this -> add it
const auto key = json_pointer::escape(it.key());
result.push_back(
{
{"op", "add"}, {"path", path + "/" + key},
{"value", it.value()}
});
}
}
break;
} }
default: // add other remaining elements
while (i < target.size())
{ {
// both primitive type: replace value
result.push_back( result.push_back(
{ {
{"op", "replace"}, {"path", path}, {"value", target} {"op", "add"},
{"path", path + "/" + std::to_string(i)},
{"value", target[i]}
}); });
break; ++i;
} }
break;
}
case value_t::object:
{
// first pass: traverse this object's elements
for (auto it = source.cbegin(); it != source.cend(); ++it)
{
// escape the key name to be used in a JSON patch
const auto key = json_pointer::escape(it.key());
if (target.find(it.key()) != target.end())
{
// recursive call to compare object values at key it
auto temp_diff = diff(it.value(), target[it.key()], path + "/" + key);
result.insert(result.end(), temp_diff.begin(), temp_diff.end());
}
else
{
// found a key that is not in o -> remove it
result.push_back(object(
{
{"op", "remove"}, {"path", path + "/" + key}
}));
}
}
// second pass: traverse other object's elements
for (auto it = target.cbegin(); it != target.cend(); ++it)
{
if (source.find(it.key()) == source.end())
{
// found a key that is not in this -> add it
const auto key = json_pointer::escape(it.key());
result.push_back(
{
{"op", "add"}, {"path", path + "/" + key},
{"value", it.value()}
});
}
}
break;
}
default:
{
// both primitive type: replace value
result.push_back(
{
{"op", "replace"}, {"path", path}, {"value", target}
});
break;
} }
} }
@ -8012,4 +8045,4 @@ inline nlohmann::json::json_pointer operator "" _json_pointer(const char* s, std
#include <nlohmann/detail/macro_unscope.hpp> #include <nlohmann/detail/macro_unscope.hpp>
#endif #endif // INCLUDE_NLOHMANN_JSON_HPP_

View file

@ -1,5 +1,5 @@
#ifndef NLOHMANN_JSON_FWD_HPP #ifndef INCLUDE_NLOHMANN_JSON_FWD_HPP_
#define 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
@ -61,4 +61,4 @@ uses the standard template types.
using json = basic_json<>; using json = basic_json<>;
} // namespace nlohmann } // namespace nlohmann
#endif #endif // INCLUDE_NLOHMANN_JSON_FWD_HPP_

View file

@ -12,6 +12,7 @@ nlohmann_json_multiple_headers = declare_dependency(
include_directories: include_directories('include') include_directories: include_directories('include')
) )
if not meson.is_subproject()
install_headers('single_include/nlohmann/json.hpp', subdir: 'nlohmann') install_headers('single_include/nlohmann/json.hpp', subdir: 'nlohmann')
pkgc = import('pkgconfig') pkgc = import('pkgconfig')
@ -19,3 +20,4 @@ pkgc.generate(name: 'nlohmann_json',
version: meson.project_version(), version: meson.project_version(),
description: 'JSON for Modern C++' description: 'JSON for Modern C++'
) )
endif

File diff suppressed because it is too large Load diff

View file

@ -64,7 +64,12 @@ set_target_properties(doctest_main PROPERTIES
COMPILE_DEFINITIONS "$<$<CXX_COMPILER_ID:MSVC>:_SCL_SECURE_NO_WARNINGS>" COMPILE_DEFINITIONS "$<$<CXX_COMPILER_ID:MSVC>:_SCL_SECURE_NO_WARNINGS>"
COMPILE_OPTIONS "$<$<CXX_COMPILER_ID:MSVC>:/EHsc;$<$<CONFIG:Release>:/Od>>" COMPILE_OPTIONS "$<$<CXX_COMPILER_ID:MSVC>:/EHsc;$<$<CONFIG:Release>:/Od>>"
) )
target_compile_features(doctest_main PUBLIC cxx_std_11)
if (${CMAKE_VERSION} VERSION_LESS "3.8.0")
target_compile_features(catch_main PUBLIC cxx_range_for)
else()
target_compile_features(catch_main PUBLIC cxx_std_11)
endif()
target_include_directories(doctest_main PRIVATE "thirdparty/doctest") target_include_directories(doctest_main PRIVATE "thirdparty/doctest")
# https://stackoverflow.com/questions/2368811/how-to-set-warning-level-in-cmake # https://stackoverflow.com/questions/2368811/how-to-set-warning-level-in-cmake

View file

@ -111,6 +111,12 @@ struct my_allocator : std::allocator<T>
p->~T(); p->~T();
} }
} }
template <class U>
struct rebind
{
using other = my_allocator<U>;
};
}; };
// allows deletion of raw pointer, usually hold by json_value // allows deletion of raw pointer, usually hold by json_value

View file

@ -150,7 +150,7 @@ class alt_string
} }
private: private:
std::string str_impl; std::string str_impl {};
friend bool ::operator<(const char*, const alt_string&); friend bool ::operator<(const char*, const alt_string&);
}; };

View file

@ -1968,7 +1968,7 @@ TEST_CASE("all CBOR first bytes")
try try
{ {
json::from_cbor(std::vector<uint8_t>(1, byte)); auto res = json::from_cbor(std::vector<uint8_t>(1, byte));
} }
catch (const json::parse_error& e) catch (const json::parse_error& e)
{ {

View file

@ -126,7 +126,7 @@ class SaxEventLogger
return false; return false;
} }
std::vector<std::string> events; std::vector<std::string> events {};
bool errored = false; bool errored = false;
}; };

View file

@ -124,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

View file

@ -982,6 +982,93 @@ TEST_CASE("element access 2")
} }
} }
} }
SECTION("check existence of key in an object")
{
SECTION("existing element")
{
for (auto key :
{"integer", "unsigned", "floating", "null", "string", "boolean", "object", "array"
})
{
CHECK(j.contains(key) == true);
CHECK(j_const.contains(key) == true);
}
}
SECTION("nonexisting element")
{
CHECK(j.contains("foo") == false);
CHECK(j_const.contains("foo") == false);
}
SECTION("all types")
{
SECTION("null")
{
json j_nonobject(json::value_t::null);
const json j_nonobject_const(j_nonobject);
CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false);
}
SECTION("string")
{
json j_nonobject(json::value_t::string);
const json j_nonobject_const(j_nonobject);
CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false);
}
SECTION("object")
{
json j_nonobject(json::value_t::object);
const json j_nonobject_const(j_nonobject);
CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false);
}
SECTION("array")
{
json j_nonobject(json::value_t::array);
const json j_nonobject_const(j_nonobject);
CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false);
}
SECTION("boolean")
{
json j_nonobject(json::value_t::boolean);
const json j_nonobject_const(j_nonobject);
CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false);
}
SECTION("number (integer)")
{
json j_nonobject(json::value_t::number_integer);
const json j_nonobject_const(j_nonobject);
CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false);
}
SECTION("number (unsigned)")
{
json j_nonobject(json::value_t::number_unsigned);
const json j_nonobject_const(j_nonobject);
CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false);
}
SECTION("number (floating-point)")
{
json j_nonobject(json::value_t::number_float);
const json j_nonobject_const(j_nonobject);
CHECK(j_nonobject.contains("foo") == false);
CHECK(j_nonobject_const.contains("foo") == false);
}
}
}
} }
} }

View file

@ -439,6 +439,7 @@ TEST_CASE("JSON pointers")
}) })
{ {
CHECK(json::json_pointer(ptr).to_string() == ptr); CHECK(json::json_pointer(ptr).to_string() == ptr);
CHECK(std::string(json::json_pointer(ptr)) == ptr);
} }
} }
@ -460,4 +461,137 @@ TEST_CASE("JSON pointers")
CHECK(j.is_object()); CHECK(j.is_object());
} }
} }
SECTION("empty, push, pop and parent")
{
const json j =
{
{"", "Hello"},
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{
"answer", {
{"everything", 42}
}
},
{"list", {1, 0, 2}},
{
"object", {
{"currency", "USD"},
{"value", 42.99},
{"", "empty string"},
{"/", "slash"},
{"~", "tilde"},
{"~1", "tilde1"}
}
}
};
// empty json_pointer returns the root JSON-object
auto ptr = ""_json_pointer;
CHECK(ptr.empty());
CHECK(j[ptr] == j);
// simple field access
ptr.push_back("pi");
CHECK(!ptr.empty());
CHECK(j[ptr] == j["pi"]);
ptr.pop_back();
CHECK(ptr.empty());
CHECK(j[ptr] == j);
// object and children access
const std::string answer("answer");
ptr.push_back(answer);
ptr.push_back("everything");
CHECK(!ptr.empty());
CHECK(j[ptr] == j["answer"]["everything"]);
ptr.pop_back();
ptr.pop_back();
CHECK(ptr.empty());
CHECK(j[ptr] == j);
// push key which has to be encoded
ptr.push_back("object");
ptr.push_back("/");
CHECK(j[ptr] == j["object"]["/"]);
CHECK(ptr.to_string() == "/object/~1");
CHECK(j[ptr.parent_pointer()] == j["object"]);
ptr = ptr.parent_pointer().parent_pointer();
CHECK(ptr.empty());
CHECK(j[ptr] == j);
// parent-pointer of the empty json_pointer is empty
ptr = ptr.parent_pointer();
CHECK(ptr.empty());
CHECK(j[ptr] == j);
CHECK_THROWS_WITH(ptr.pop_back(),
"[json.exception.out_of_range.405] JSON pointer has no parent");
}
SECTION("operators")
{
const json j =
{
{"", "Hello"},
{"pi", 3.141},
{"happy", true},
{"name", "Niels"},
{"nothing", nullptr},
{
"answer", {
{"everything", 42}
}
},
{"list", {1, 0, 2}},
{
"object", {
{"currency", "USD"},
{"value", 42.99},
{"", "empty string"},
{"/", "slash"},
{"~", "tilde"},
{"~1", "tilde1"}
}
}
};
// empty json_pointer returns the root JSON-object
auto ptr = ""_json_pointer;
CHECK(j[ptr] == j);
// simple field access
ptr = ptr / "pi";
CHECK(j[ptr] == j["pi"]);
ptr.pop_back();
CHECK(j[ptr] == j);
// object and children access
const std::string answer("answer");
ptr /= answer;
ptr = ptr / "everything";
CHECK(j[ptr] == j["answer"]["everything"]);
ptr.pop_back();
ptr.pop_back();
CHECK(j[ptr] == j);
CHECK(ptr / ""_json_pointer == ptr);
CHECK(j["/answer"_json_pointer / "/everything"_json_pointer] == j["answer"]["everything"]);
// list children access
CHECK(j["/list"_json_pointer / 1] == j["list"][1]);
// push key which has to be encoded
ptr /= "object";
ptr = ptr / "/";
CHECK(j[ptr] == j["object"]["/"]);
CHECK(ptr.to_string() == "/object/~1");
}
} }

View file

@ -308,7 +308,7 @@ TEST_CASE("README" * doctest::skip())
// } // }
// calculate a JSON patch from two JSON values // calculate a JSON patch from two JSON values
json::diff(j_result, j_original); auto res = json::diff(j_result, j_original);
// [ // [
// { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] }, // { "op":" replace", "path": "/baz", "value": ["one", "two", "three"] },
// { "op":"remove","path":"/hello" }, // { "op":"remove","path":"/hello" },

View file

@ -129,8 +129,10 @@ struct nocopy
struct Data struct Data
{ {
std::string a; Data() = default;
std::string b; Data(const std::string& a_, const std::string b_) : a(a_), b(b_) {}
std::string a {};
std::string b {};
}; };
void from_json(const json& j, Data& data) void from_json(const json& j, Data& data)
@ -1705,13 +1707,81 @@ TEST_CASE("regression tests")
std::map<std::string, Data> expected std::map<std::string, Data> expected
{ {
{"1", {"testa_1", "testb_1" }}, {"1", {"testa_1", "testb_1"}},
{"2", {"testa_2", "testb_2"}}, {"2", {"testa_2", "testb_2"}},
{"3", {"testa_3", "testb_3"}}, {"3", {"testa_3", "testb_3"}},
}; };
const auto data = j.get<decltype(expected)>(); const auto data = j.get<decltype(expected)>();
CHECK(expected == data); CHECK(expected == data);
} }
SECTION("issue #1445 - buffer overflow in dumping invalid utf-8 strings")
{
SECTION("a bunch of -1, ensure_ascii=true")
{
json dump_test;
std::vector<char> data(300, -1);
std::vector<std::string> vec_string(300, "\\ufffd");
std::string s{data.data(), data.size()};
dump_test["1"] = s;
std::ostringstream os;
os << "{\"1\":\"";
std::copy( vec_string.begin(), vec_string.end(), std::ostream_iterator<std::string>(os));
os << "\"}";
s = dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace);
CHECK(s == os.str());
}
SECTION("a bunch of -2, ensure_ascii=false")
{
json dump_test;
std::vector<char> data(500, -2);
std::vector<std::string> vec_string(500, "\xEF\xBF\xBD");
std::string s{data.data(), data.size()};
dump_test["1"] = s;
std::ostringstream os;
os << "{\"1\":\"";
std::copy( vec_string.begin(), vec_string.end(), std::ostream_iterator<std::string>(os));
os << "\"}";
s = dump_test.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
CHECK(s == os.str());
}
SECTION("test case in issue #1445")
{
nlohmann::json dump_test;
const int data[] =
{
109, 108, 103, 125, -122, -53, 115,
18, 3, 0, 102, 19, 1, 15,
-110, 13, -3, -1, -81, 32, 2,
0, 0, 0, 0, 0, 0, 0,
8, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, -80, 2,
0, 0, 96, -118, 46, -116, 46,
109, -84, -87, 108, 14, 109, -24,
-83, 13, -18, -51, -83, -52, -115,
14, 6, 32, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
64, 3, 0, 0, 0, 35, -74,
-73, 55, 57, -128, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 33, 0, 0, 0, -96,
-54, -28, -26
};
std::string s;
for (unsigned i = 0; i < sizeof(data) / sizeof(int); i++)
{
s += static_cast<char>(data[i]);
}
dump_test["1"] = s;
dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace);
}
}
SECTION("issue #1447 - Integer Overflow (OSS-Fuzz 12506)")
{
json j = json::parse("[-9223372036854775808]");
CHECK(j.dump() == "[-9223372036854775808]");
}
} }
#if not defined(JSON_NOEXCEPTION) #if not defined(JSON_NOEXCEPTION)

View file

@ -2130,7 +2130,7 @@ TEST_CASE("all UBJSON first bytes")
try try
{ {
json::from_ubjson(std::vector<uint8_t>(1, byte)); auto res = json::from_ubjson(std::vector<uint8_t>(1, byte));
} }
catch (const json::parse_error& e) catch (const json::parse_error& e)
{ {

View file

@ -598,9 +598,8 @@ struct pod_serializer
static void to_json(BasicJsonType& j, const T& t) noexcept static void to_json(BasicJsonType& j, const T& t) noexcept
{ {
auto bytes = static_cast< const unsigned char*>(static_cast<const void*>(&t)); auto bytes = static_cast< const unsigned char*>(static_cast<const void*>(&t));
std::uint64_t value = bytes[0]; std::uint64_t value;
for (auto i = 1; i < 8; ++i) std::memcpy(&value, bytes, sizeof(value));
value |= std::uint64_t{bytes[i]} << 8 * i;
nlohmann::to_json(j, value); nlohmann::to_json(j, value);
} }
}; };

27
third_party/cpplint/LICENSE vendored Executable file
View file

@ -0,0 +1,27 @@
cpplint.py and its corresponding unit tests are Copyright (C) 2009 Google Inc.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

80
third_party/cpplint/README.rst vendored Executable file
View file

@ -0,0 +1,80 @@
cpplint - static code checker for C++
=====================================
.. image:: https://travis-ci.org/cpplint/cpplint.svg?branch=master
:target: https://travis-ci.org/cpplint/cpplint
.. image:: https://img.shields.io/pypi/v/cpplint.svg
:target: https://pypi.python.org/pypi/cpplint
.. image:: https://img.shields.io/pypi/pyversions/cpplint.svg
:target: https://pypi.python.org/pypi/cpplint
.. image:: https://img.shields.io/pypi/status/cpplint.svg
:target: https://pypi.python.org/pypi/cpplint
.. image:: https://img.shields.io/pypi/l/cpplint.svg
:target: https://pypi.python.org/pypi/cpplint
.. image:: https://img.shields.io/pypi/dd/cpplint.svg
:target: https://pypi.python.org/pypi/cpplint
.. image:: https://img.shields.io/pypi/dw/cpplint.svg
:target: https://pypi.python.org/pypi/cpplint
.. image:: https://img.shields.io/pypi/dm/cpplint.svg
:target: https://pypi.python.org/pypi/cpplint
Cpplint is a command-line tool to check C/C++ files for style issues following `Google's C++ style guide <http://google.github.io/styleguide/cppguide.html>`_.
Cpplint is developed and maintained by Google Inc. at `google/styleguide <https://github.com/google/styleguide>`_, also see see the `wikipedia entry <http://en.wikipedia.org/wiki/Cpplint>`_
While Google maintains cpplint, Google is not (very) responsive to issues and pull requests, this fork aims to be (somewhat) more open to add fixes to cpplint to enable fixes, when those fixes make cpplint usable in wider contexts.
Installation
============
To install cpplint from PyPI, run:
.. code-block:: bash
$ pip install cpplint
Then run it with:
.. code-block:: bash
$ cpplint [OPTIONS] files
For full usage instructions, run:
.. code-block:: bash
$ cpplint --help
Changes
-------
The modifications in this fork are minor fixes and cosmetic changes:
* more default extensions
* python 3 compatibility
* customizable file extensions with the --extensions argument
* continuous integration on travis
* support for recursive file discovery via the --recursive argument
* support for excluding files via --exclude
* JUnit XML output format
* Overriding repository root auto-detection via --repository
* Support ``#pragma once`` as an alternative to header include guards
Acknowledgements
----------------
Thanks to Google Inc. for open-sourcing their in-house tool.
Thanks to maintainers of the fork
* `tkruse <https://github.com/tkruse>`_
* `mattyclarkson <https://github.com/mattyclarkson>`_
* `theandrewdavis <https://github.com/theandrewdavis>`_

6583
third_party/cpplint/cpplint.py vendored Executable file

File diff suppressed because it is too large Load diff