Merge branch 'release/3.2.0'

This commit is contained in:
Niels Lohmann 2018-08-20 19:36:10 +02:00
commit 8c20571136
No known key found for this signature in database
GPG key ID: 7F3CEA63AE251B69
459 changed files with 9352 additions and 3052 deletions

View file

@ -1,22 +1,19 @@
**Bug Report** ---
name: Bug report
- What is the issue you have? about: Create a report to help us improve
- Please describe the steps to reproduce the issue. Can you provide a small but working code example? ---
- What is the expected behavior? - What is the issue you have?
- And what is the actual behavior instead? - Please describe the steps to reproduce the issue. Can you provide a small but working code example?
- Which compiler and operating system are you using? Is it a [supported compiler](https://github.com/nlohmann/json#supported-compilers)? - What is the expected behavior?
- Did you use a released version of the library or the version from the `develop` branch? - And what is the actual behavior instead?
- If you experience a compilation error: can you [compile and run the unit tests](https://github.com/nlohmann/json#execute-unit-tests)? - Which compiler and operating system are you using? Is it a [supported compiler](https://github.com/nlohmann/json#supported-compilers)?
- Did you use a released version of the library or the version from the `develop` branch?
**Feature Request**
- If you experience a compilation error: can you [compile and run the unit tests](https://github.com/nlohmann/json#execute-unit-tests)?
- Describe the feature in as much detail as possible.
- Include sample usage where appropriate.

View file

@ -0,0 +1,9 @@
---
name: Feature request
about: Suggest an idea for this project
---
- Describe the feature in as much detail as possible.
- Include sample usage where appropriate.

View file

@ -155,6 +155,12 @@ matrix:
- os: osx - os: osx
osx_image: xcode9.2 osx_image: xcode9.2
- os: osx
osx_image: xcode9.3
- os: osx
osx_image: xcode9.4
# Linux / GCC # Linux / GCC
- os: linux - os: linux
@ -189,15 +195,23 @@ matrix:
sources: ['ubuntu-toolchain-r-test'] sources: ['ubuntu-toolchain-r-test']
packages: ['g++-7', 'ninja-build'] packages: ['g++-7', 'ninja-build']
- os: linux
compiler: gcc
env: COMPILER=g++-8
addons:
apt:
sources: ['ubuntu-toolchain-r-test']
packages: ['g++-8', 'ninja-build']
- os: linux - os: linux
compiler: gcc compiler: gcc
env: env:
- COMPILER=g++-7 - COMPILER=g++-8
- CXXFLAGS=-std=c++17 - CXXFLAGS=-std=c++17
addons: addons:
apt: apt:
sources: ['ubuntu-toolchain-r-test'] sources: ['ubuntu-toolchain-r-test']
packages: ['g++-7', 'ninja-build'] packages: ['g++-8', 'ninja-build']
# Linux / Clang # Linux / Clang
@ -257,15 +271,23 @@ matrix:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0'] sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0']
packages: ['g++-6', 'clang-5.0', 'ninja-build'] packages: ['g++-6', 'clang-5.0', 'ninja-build']
- os: linux
compiler: clang
env: COMPILER=clang++-6.0
addons:
apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0']
packages: ['g++-6', 'clang-6.0', 'ninja-build']
- os: linux - os: linux
compiler: clang compiler: clang
env: env:
- COMPILER=clang++-5.0 - COMPILER=clang++-6.0
- CXXFLAGS=-std=c++1z - CXXFLAGS=-std=c++1z
addons: addons:
apt: apt:
sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-5.0'] sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-trusty-6.0']
packages: ['g++-6', 'clang-5.0', 'ninja-build'] packages: ['g++-6', 'clang-6.0', 'ninja-build']
################ ################
# build script # # build script #
@ -277,6 +299,7 @@ script:
if [[ (-x $(which brew)) ]]; then if [[ (-x $(which brew)) ]]; then
brew update brew update
brew install cmake ninja brew install cmake ninja
brew upgrade cmake
cmake --version cmake --version
fi fi

View file

@ -1,10 +1,10 @@
cmake_minimum_required(VERSION 3.0.0) cmake_minimum_required(VERSION 3.8)
## ##
## PROJECT ## PROJECT
## name and version ## name and version
## ##
project(nlohmann_json VERSION 3.1.2 LANGUAGES CXX) project(nlohmann_json VERSION 3.2.0 LANGUAGES CXX)
## ##
## INCLUDE ## INCLUDE
@ -22,13 +22,15 @@ option(JSON_MultipleHeaders "Use non-amalgamated version of the library." OFF)
## CONFIGURATION ## CONFIGURATION
## ##
set(NLOHMANN_JSON_TARGET_NAME ${PROJECT_NAME}) set(NLOHMANN_JSON_TARGET_NAME ${PROJECT_NAME})
set(NLOHMANN_JSON_CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}") set(NLOHMANN_JSON_CONFIG_INSTALL_DIR "lib/cmake/${PROJECT_NAME}"
CACHE INTERNAL "")
set(NLOHMANN_JSON_INCLUDE_INSTALL_DIR "include") set(NLOHMANN_JSON_INCLUDE_INSTALL_DIR "include")
set(NLOHMANN_JSON_TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets") set(NLOHMANN_JSON_TARGETS_EXPORT_NAME "${PROJECT_NAME}Targets")
set(NLOHMANN_JSON_CMAKE_CONFIG_TEMPLATE "cmake/config.cmake.in") set(NLOHMANN_JSON_CMAKE_CONFIG_TEMPLATE "cmake/config.cmake.in")
set(NLOHMANN_JSON_CMAKE_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}/cmake_config") set(NLOHMANN_JSON_CMAKE_CONFIG_DIR "${CMAKE_CURRENT_BINARY_DIR}")
set(NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE "${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}ConfigVersion.cmake") set(NLOHMANN_JSON_CMAKE_VERSION_CONFIG_FILE "${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}ConfigVersion.cmake")
set(NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE "${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}Config.cmake") set(NLOHMANN_JSON_CMAKE_PROJECT_CONFIG_FILE "${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}Config.cmake")
set(NLOHMANN_JSON_CMAKE_PROJECT_TARGETS_FILE "${NLOHMANN_JSON_CMAKE_CONFIG_DIR}/${PROJECT_NAME}Targets.cmake")
if (JSON_MultipleHeaders) if (JSON_MultipleHeaders)
set(NLOHMANN_JSON_INCLUDE_BUILD_DIR "${PROJECT_SOURCE_DIR}/include/") set(NLOHMANN_JSON_INCLUDE_BUILD_DIR "${PROJECT_SOURCE_DIR}/include/")
@ -43,6 +45,8 @@ endif()
## create target and add include path ## create target and add include path
## ##
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})
target_compile_features(${NLOHMANN_JSON_TARGET_NAME} INTERFACE cxx_std_11)
target_include_directories( target_include_directories(
${NLOHMANN_JSON_TARGET_NAME} ${NLOHMANN_JSON_TARGET_NAME}
@ -51,8 +55,8 @@ target_include_directories(
$<INSTALL_INTERFACE:include> $<INSTALL_INTERFACE:include>
) )
## add debug view defintion file for msvc (natvis) [cmake <= 3.2.2 does not support export of source files] ## add debug view definition file for msvc (natvis)
if (MSVC AND CMAKE_VERSION VERSION_GREATER "3.2.2") if (MSVC)
set(NLOHMANN_ADD_NATVIS TRUE) set(NLOHMANN_ADD_NATVIS TRUE)
set(NLOHMANN_NATVIS_FILE "nlohmann_json.natvis") set(NLOHMANN_NATVIS_FILE "nlohmann_json.natvis")
target_sources( target_sources(
@ -62,7 +66,7 @@ if (MSVC AND CMAKE_VERSION VERSION_GREATER "3.2.2")
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${NLOHMANN_NATVIS_FILE}> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${NLOHMANN_NATVIS_FILE}>
) )
endif() endif()
## ##
## TESTS ## TESTS
## create and configure the unit test target ## create and configure the unit test target
@ -102,6 +106,11 @@ if (NLOHMANN_ADD_NATVIS)
DESTINATION . DESTINATION .
) )
endif() endif()
export(
TARGETS ${NLOHMANN_JSON_TARGET_NAME}
NAMESPACE ${PROJECT_NAME}::
FILE ${NLOHMANN_JSON_CMAKE_PROJECT_TARGETS_FILE}
)
install( install(
TARGETS ${NLOHMANN_JSON_TARGET_NAME} TARGETS ${NLOHMANN_JSON_TARGET_NAME}
EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME} EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}
@ -109,5 +118,6 @@ install(
) )
install( install(
EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME} EXPORT ${NLOHMANN_JSON_TARGETS_EXPORT_NAME}
NAMESPACE ${PROJECT_NAME}::
DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR} DESTINATION ${NLOHMANN_JSON_CONFIG_INSTALL_DIR}
) )

View file

@ -1,6 +1,186 @@
# Change Log # Change Log
All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/).
## [v3.2.0](https://github.com/nlohmann/json/releases/tag/v3.2.0) (2018-08-18)
[Full Changelog](https://github.com/nlohmann/json/compare/v3.1.2...v3.2.0)
- Am I doing this wrong? Getting an empty string [\#1199](https://github.com/nlohmann/json/issues/1199)
- Incompatible Pointer Type [\#1196](https://github.com/nlohmann/json/issues/1196)
- json.exception.type\_error.316 [\#1195](https://github.com/nlohmann/json/issues/1195)
- Strange warnings in Code::Blocks 17.12, GNU GCC [\#1192](https://github.com/nlohmann/json/issues/1192)
- \[Question\] Current place in code to change floating point resolution [\#1191](https://github.com/nlohmann/json/issues/1191)
- Add key name when throwing type error [\#1189](https://github.com/nlohmann/json/issues/1189)
- Not able to include in visual studio code? [\#1188](https://github.com/nlohmann/json/issues/1188)
- Get an Index or row number of an element [\#1186](https://github.com/nlohmann/json/issues/1186)
- reduce repos size [\#1185](https://github.com/nlohmann/json/issues/1185)
- Difference between `merge\_patch` and `update` [\#1183](https://github.com/nlohmann/json/issues/1183)
- Is there a way to get an element from a JSON without throwing an exception on failure? [\#1182](https://github.com/nlohmann/json/issues/1182)
- to\_string? [\#1181](https://github.com/nlohmann/json/issues/1181)
- How to cache a json object's pointer into a map? [\#1180](https://github.com/nlohmann/json/issues/1180)
- Can this library work within a Qt project for Android using Qt Creator? [\#1178](https://github.com/nlohmann/json/issues/1178)
- How to get all keys of one object? [\#1177](https://github.com/nlohmann/json/issues/1177)
- How can I only parse the first level and get the value as string? [\#1175](https://github.com/nlohmann/json/issues/1175)
- I have a query regarding nlohmann::basic\_json::basic\_json [\#1174](https://github.com/nlohmann/json/issues/1174)
- unordered\_map with vectors won't convert to json? [\#1173](https://github.com/nlohmann/json/issues/1173)
- return json objects from functions [\#1172](https://github.com/nlohmann/json/issues/1172)
- Problem when exporting to CBOR [\#1171](https://github.com/nlohmann/json/issues/1171)
- Roundtripping null to nullptr does not work [\#1169](https://github.com/nlohmann/json/issues/1169)
- MSVC fails to compile std::swap specialization for nlohmann::json [\#1168](https://github.com/nlohmann/json/issues/1168)
- Unexpected behaviour of is\_null - Part II [\#1167](https://github.com/nlohmann/json/issues/1167)
- Floating point imprecision [\#1166](https://github.com/nlohmann/json/issues/1166)
- Combine json objects into one? [\#1165](https://github.com/nlohmann/json/issues/1165)
- Is there any way to know if the object has changed? [\#1164](https://github.com/nlohmann/json/issues/1164)
- Value throws on null string [\#1163](https://github.com/nlohmann/json/issues/1163)
- Weird template issue in large project [\#1162](https://github.com/nlohmann/json/issues/1162)
- \_json returns a different result vs ::parse [\#1161](https://github.com/nlohmann/json/issues/1161)
- Showing difference between two json objects [\#1160](https://github.com/nlohmann/json/issues/1160)
- no instance of overloaded function "std::swap" matches the specified type [\#1159](https://github.com/nlohmann/json/issues/1159)
- resize\(...\)? [\#1157](https://github.com/nlohmann/json/issues/1157)
- Issue with struct nested in class' to\_json [\#1155](https://github.com/nlohmann/json/issues/1155)
- Deserialize std::map with std::nan [\#1154](https://github.com/nlohmann/json/issues/1154)
- Parse throwing errors [\#1149](https://github.com/nlohmann/json/issues/1149)
- cocoapod integration [\#1148](https://github.com/nlohmann/json/issues/1148)
- wstring parsing [\#1147](https://github.com/nlohmann/json/issues/1147)
- Is it possible to dump a two-dimensional array to "\[\[null\],\[1,2,3\]\]"? [\#1146](https://github.com/nlohmann/json/issues/1146)
- Want to write a class member variable and a struct variable \( this structure is inside the class\) to the json file [\#1145](https://github.com/nlohmann/json/issues/1145)
- Does json support converting an instance of a struct into json string? [\#1143](https://github.com/nlohmann/json/issues/1143)
- \#Most efficient way to search for child parameters \(recursive find?\) [\#1141](https://github.com/nlohmann/json/issues/1141)
- could not find to\_json\(\) method in T's namespace [\#1140](https://github.com/nlohmann/json/issues/1140)
- chars get treated as JSON numbers not JSON strings [\#1139](https://github.com/nlohmann/json/issues/1139)
- How do I count number of objects in array? [\#1137](https://github.com/nlohmann/json/issues/1137)
- Serializing a vector of classes? [\#1136](https://github.com/nlohmann/json/issues/1136)
- Compile error. Unable convert form nullptr to nullptr&& [\#1135](https://github.com/nlohmann/json/issues/1135)
- std::unordered\_map in struct, serialization [\#1133](https://github.com/nlohmann/json/issues/1133)
- dump\(\) can't handle umlauts [\#1131](https://github.com/nlohmann/json/issues/1131)
- Add a way to get a key reference from the iterator [\#1127](https://github.com/nlohmann/json/issues/1127)
- can't not parse "\\“ string [\#1123](https://github.com/nlohmann/json/issues/1123)
- if json file contain Internationalization chars , get exception [\#1122](https://github.com/nlohmann/json/issues/1122)
- How to use a json::iterator dereferenced value in code? [\#1120](https://github.com/nlohmann/json/issues/1120)
- clang compiler: error : unknown type name 'not' [\#1119](https://github.com/nlohmann/json/issues/1119)
- Disable implicit conversions from json to std::initializer\_list\<T\> for any T [\#1118](https://github.com/nlohmann/json/issues/1118)
- Implicit conversions to complex types can lead to surprising and confusing errors [\#1116](https://github.com/nlohmann/json/issues/1116)
- How can I write from\_json for a complex datatype that is not default constructible? [\#1115](https://github.com/nlohmann/json/issues/1115)
- Compile error in VS2015 when compiling unit-conversions.cpp [\#1114](https://github.com/nlohmann/json/issues/1114)
- ADL Serializer for std::any / boost::any [\#1113](https://github.com/nlohmann/json/issues/1113)
- Unexpected behaviour of is\_null [\#1112](https://github.com/nlohmann/json/issues/1112)
- How to resolve " undefined reference to `std::\_\_throw\_bad\_cast\(\)'" [\#1111](https://github.com/nlohmann/json/issues/1111)
- cannot compile on ubuntu 18.04 and 16.04 [\#1110](https://github.com/nlohmann/json/issues/1110)
- JSON representation for floating point values has too many digits [\#1109](https://github.com/nlohmann/json/issues/1109)
- Not working for classes containing "\_declspec\(dllimport\)" in their declaration [\#1108](https://github.com/nlohmann/json/issues/1108)
- Get keys from json object [\#1107](https://github.com/nlohmann/json/issues/1107)
- dump\(\) without alphabetical order [\#1106](https://github.com/nlohmann/json/issues/1106)
- Cannot deserialize types using std::ratio [\#1105](https://github.com/nlohmann/json/issues/1105)
- i want to learn json [\#1104](https://github.com/nlohmann/json/issues/1104)
- Type checking during compile [\#1103](https://github.com/nlohmann/json/issues/1103)
- Iterate through sub items [\#1102](https://github.com/nlohmann/json/issues/1102)
- cppcheck failing for version 3.1.2 [\#1101](https://github.com/nlohmann/json/issues/1101)
- Deserializing std::map [\#1100](https://github.com/nlohmann/json/issues/1100)
- accessing key by reference [\#1098](https://github.com/nlohmann/json/issues/1098)
- clang 3.8.0 croaks while trying to compile with debug symbols [\#1097](https://github.com/nlohmann/json/issues/1097)
- Serialize a list of class objects with json [\#1096](https://github.com/nlohmann/json/issues/1096)
- Null bytes in files are treated like EOF [\#1095](https://github.com/nlohmann/json/issues/1095)
- Small question [\#1094](https://github.com/nlohmann/json/issues/1094)
- Upgrading to 3.x: to\_/from\_json with enum class [\#1093](https://github.com/nlohmann/json/issues/1093)
- Q: few questions about json construction [\#1092](https://github.com/nlohmann/json/issues/1092)
- general crayCC compilation failure [\#1091](https://github.com/nlohmann/json/issues/1091)
- Merge Patch clears original data [\#1090](https://github.com/nlohmann/json/issues/1090)
- \[Question\] how to use nlohmann/json in c++? [\#1088](https://github.com/nlohmann/json/issues/1088)
- C++17 decomposition declaration support [\#1087](https://github.com/nlohmann/json/issues/1087)
- \[Question\] Access multi-level json objects [\#1086](https://github.com/nlohmann/json/issues/1086)
- Serializing vector [\#1085](https://github.com/nlohmann/json/issues/1085)
- update nested value in multi hierarchy json object [\#1084](https://github.com/nlohmann/json/issues/1084)
- Overriding default values? [\#1083](https://github.com/nlohmann/json/issues/1083)
- detail namespace collision with Cereal? [\#1082](https://github.com/nlohmann/json/issues/1082)
- Error using json.dump\(\); [\#1081](https://github.com/nlohmann/json/issues/1081)
- Consuming TCP Stream [\#1080](https://github.com/nlohmann/json/issues/1080)
- Compilation error with strong typed enums in map in combination with namespaces [\#1079](https://github.com/nlohmann/json/issues/1079)
- cassert error [\#1076](https://github.com/nlohmann/json/issues/1076)
- Valid json data not being parsed [\#1075](https://github.com/nlohmann/json/issues/1075)
- Feature request :: Better testing for key existance without try/catch [\#1074](https://github.com/nlohmann/json/issues/1074)
- Hi, I have input like a.b.c and want to convert it to \"a\"{\"b\": \"c\"} form. Any suggestions how do I do this? Thanks. [\#1073](https://github.com/nlohmann/json/issues/1073)
- ADL deserializer not picked up for non default-constructible type [\#1072](https://github.com/nlohmann/json/issues/1072)
- Deserializing std::array doesn't compiler \(no insert\(\)\) [\#1071](https://github.com/nlohmann/json/issues/1071)
- Serializing OpenCV Mat problem [\#1070](https://github.com/nlohmann/json/issues/1070)
- Compilation error with ICPC compiler [\#1068](https://github.com/nlohmann/json/issues/1068)
- Minimal branch? [\#1066](https://github.com/nlohmann/json/issues/1066)
- Not existing value, crash [\#1065](https://github.com/nlohmann/json/issues/1065)
- cyryllic symbols [\#1064](https://github.com/nlohmann/json/issues/1064)
- newbie usage question [\#1063](https://github.com/nlohmann/json/issues/1063)
- Trying j\["strTest"\] = "%A" produces "strTest": "-0X1.CCCCCCCCCCCCCP+205" [\#1062](https://github.com/nlohmann/json/issues/1062)
- convert json value to std::string??? [\#1061](https://github.com/nlohmann/json/issues/1061)
- Commented out test cases, should they be removed? [\#1060](https://github.com/nlohmann/json/issues/1060)
- different behaviour between clang and gcc with braced initialization [\#1059](https://github.com/nlohmann/json/issues/1059)
- json array: initialize with prescribed size and `resize` method. [\#1057](https://github.com/nlohmann/json/issues/1057)
- Is it possible to use exceptions istead of assertions? [\#1056](https://github.com/nlohmann/json/issues/1056)
- when using assign operator in with json object a static assertion fails.. [\#1055](https://github.com/nlohmann/json/issues/1055)
- Iterate over leafs of a JSON data structure: enrich the JSON pointer API [\#1054](https://github.com/nlohmann/json/issues/1054)
- \[Feature request\] Access by path [\#1053](https://github.com/nlohmann/json/issues/1053)
- document that implicit js -\> primitive conversion does not work for std::string::value\_type and why [\#1052](https://github.com/nlohmann/json/issues/1052)
- error: BasicJsonType in namespace :: does not name a type [\#1051](https://github.com/nlohmann/json/issues/1051)
- Destructor is called when filling object through assignement [\#1050](https://github.com/nlohmann/json/issues/1050)
- Is this thing thread safe for reads? [\#1049](https://github.com/nlohmann/json/issues/1049)
- clang-tidy: Call to virtual function during construction [\#1046](https://github.com/nlohmann/json/issues/1046)
- Using STL algorithms with JSON containers with expected results? [\#1045](https://github.com/nlohmann/json/issues/1045)
- Usage with gtest/gmock not working as expected [\#1044](https://github.com/nlohmann/json/issues/1044)
- Consequences of from\_json / to\_json being in namespace of data struct. [\#1042](https://github.com/nlohmann/json/issues/1042)
- const\_reference operator\[\]\(const typename object\_t::key\_type& key\) const throw instead of assert [\#1039](https://github.com/nlohmann/json/issues/1039)
- Trying to retrieve data from nested objects [\#1038](https://github.com/nlohmann/json/issues/1038)
- Direct download link for json\_fwd.hpp? [\#1037](https://github.com/nlohmann/json/issues/1037)
- I know the library supports UTF-8, but failed to dump the value [\#1036](https://github.com/nlohmann/json/issues/1036)
- Putting a Vec3-like vector into a json object [\#1035](https://github.com/nlohmann/json/issues/1035)
- Ternary operator crash [\#1034](https://github.com/nlohmann/json/issues/1034)
- Issued with Clion Inspection Resolution since 2018.1 [\#1033](https://github.com/nlohmann/json/issues/1033)
- Some testcases fail and one never finishes [\#1032](https://github.com/nlohmann/json/issues/1032)
- Can this class work with wchar\_t / std::wstring? [\#1031](https://github.com/nlohmann/json/issues/1031)
- Makefile: Valgrind flags have no effect [\#1030](https://github.com/nlohmann/json/issues/1030)
- 「==」 Should be 「\>」 [\#1029](https://github.com/nlohmann/json/issues/1029)
- HOCON reader? [\#1027](https://github.com/nlohmann/json/issues/1027)
- add json string in previous string?? [\#1025](https://github.com/nlohmann/json/issues/1025)
- RFC: fluent parsing interface [\#1023](https://github.com/nlohmann/json/issues/1023)
- Does it support chinese character? [\#1022](https://github.com/nlohmann/json/issues/1022)
- to/from\_msgpack only works with standard typization [\#1021](https://github.com/nlohmann/json/issues/1021)
- Build failure using latest clang and GCC compilers [\#1020](https://github.com/nlohmann/json/issues/1020)
- can two json objects be concatenated? [\#1019](https://github.com/nlohmann/json/issues/1019)
- Erase by integer index [\#1018](https://github.com/nlohmann/json/issues/1018)
- Function find overload taking a json\_pointer [\#1017](https://github.com/nlohmann/json/issues/1017)
- I think should implement an parser function [\#1016](https://github.com/nlohmann/json/issues/1016)
- Readme gif [\#1015](https://github.com/nlohmann/json/issues/1015)
- Python bindings [\#1014](https://github.com/nlohmann/json/issues/1014)
- how to add two json string in single object?? [\#1012](https://github.com/nlohmann/json/issues/1012)
- how to serialize class Object \(convert data in object into json\)?? [\#1011](https://github.com/nlohmann/json/issues/1011)
- Enable forward declaration of json by making json a class instead of a using declaration [\#997](https://github.com/nlohmann/json/issues/997)
- compilation error while using intel c++ compiler 2018 [\#994](https://github.com/nlohmann/json/issues/994)
- How to create a json variable? [\#990](https://github.com/nlohmann/json/issues/990)
- istream \>\> json --- 1st character skipped in stream [\#976](https://github.com/nlohmann/json/issues/976)
- Add a SAX parser [\#971](https://github.com/nlohmann/json/issues/971)
- Add Key name to Exception [\#932](https://github.com/nlohmann/json/issues/932)
- How to solve large json file? [\#927](https://github.com/nlohmann/json/issues/927)
- json\_pointer public push\_back, pop\_back [\#837](https://github.com/nlohmann/json/issues/837)
- Using input\_adapter in a slightly unexpected way [\#834](https://github.com/nlohmann/json/issues/834)
- Stack-overflow \(OSS-Fuzz 4234\) [\#832](https://github.com/nlohmann/json/issues/832)
- Fix -Wno-sometimes-uninitialized by initializing "result" in parse\_sax [\#1200](https://github.com/nlohmann/json/pull/1200) ([thyu](https://github.com/thyu))
- \[RFC\] Introduce a new macro function: JSON\_INTERNAL\_CATCH [\#1187](https://github.com/nlohmann/json/pull/1187) ([simnalamburt](https://github.com/simnalamburt))
- Fix unit tests that were silently skipped or crashed \(depending on the compiler\) [\#1176](https://github.com/nlohmann/json/pull/1176) ([grembo](https://github.com/grembo))
- Refactor/no virtual sax [\#1153](https://github.com/nlohmann/json/pull/1153) ([theodelrieu](https://github.com/theodelrieu))
- Fixed compiler error in VS 2015 for debug mode [\#1151](https://github.com/nlohmann/json/pull/1151) ([sonulohani](https://github.com/sonulohani))
- Fix links to cppreference named requirements \(formerly concepts\) [\#1144](https://github.com/nlohmann/json/pull/1144) ([jrakow](https://github.com/jrakow))
- meson: fix include directory [\#1142](https://github.com/nlohmann/json/pull/1142) ([jrakow](https://github.com/jrakow))
- Feature/unordered map conversion [\#1138](https://github.com/nlohmann/json/pull/1138) ([theodelrieu](https://github.com/theodelrieu))
- fixed compile error for \#1045 [\#1134](https://github.com/nlohmann/json/pull/1134) ([Daniel599](https://github.com/Daniel599))
- test \(non\)equality for alt\_string implementation [\#1130](https://github.com/nlohmann/json/pull/1130) ([agrianius](https://github.com/agrianius))
- remove stringstream dependency [\#1117](https://github.com/nlohmann/json/pull/1117) ([TinyTinni](https://github.com/TinyTinni))
- Provide a from\_json overload for std::map [\#1089](https://github.com/nlohmann/json/pull/1089) ([theodelrieu](https://github.com/theodelrieu))
- fix typo in README [\#1078](https://github.com/nlohmann/json/pull/1078) ([martin-mfg](https://github.com/martin-mfg))
- Fix typo [\#1058](https://github.com/nlohmann/json/pull/1058) ([dns13](https://github.com/dns13))
- Misc cmake packaging enhancements [\#1048](https://github.com/nlohmann/json/pull/1048) ([chuckatkins](https://github.com/chuckatkins))
- Fixed incorrect LLVM version number in README [\#1047](https://github.com/nlohmann/json/pull/1047) ([jammehcow](https://github.com/jammehcow))
- Fix trivial typo in comment. [\#1043](https://github.com/nlohmann/json/pull/1043) ([coryan](https://github.com/coryan))
- Package Manager: Spack [\#1041](https://github.com/nlohmann/json/pull/1041) ([ax3l](https://github.com/ax3l))
- CMake: 3.8+ is Sufficient [\#1040](https://github.com/nlohmann/json/pull/1040) ([ax3l](https://github.com/ax3l))
- Added support for string\_view in C++17 [\#1028](https://github.com/nlohmann/json/pull/1028) ([gracicot](https://github.com/gracicot))
- Added public target\_compile\_features for auto and constexpr [\#1026](https://github.com/nlohmann/json/pull/1026) ([ktonon](https://github.com/ktonon))
## [v3.1.2](https://github.com/nlohmann/json/releases/tag/v3.1.2) (2018-03-14) ## [v3.1.2](https://github.com/nlohmann/json/releases/tag/v3.1.2) (2018-03-14)
[Full Changelog](https://github.com/nlohmann/json/compare/v3.1.1...v3.1.2) [Full Changelog](https://github.com/nlohmann/json/compare/v3.1.1...v3.1.2)
@ -16,7 +196,6 @@ All notable changes to this project will be documented in this file. This projec
- get\<T\> for types that are not default constructible [\#996](https://github.com/nlohmann/json/issues/996) - get\<T\> for types that are not default constructible [\#996](https://github.com/nlohmann/json/issues/996)
- Prevent Null values to appear in .dump\(\) [\#995](https://github.com/nlohmann/json/issues/995) - Prevent Null values to appear in .dump\(\) [\#995](https://github.com/nlohmann/json/issues/995)
- number parsing [\#993](https://github.com/nlohmann/json/issues/993) - number parsing [\#993](https://github.com/nlohmann/json/issues/993)
- How to create a json variable? [\#990](https://github.com/nlohmann/json/issues/990)
- C2664 \(C++/CLR\) cannot convert 'nullptr' to 'nullptr &&' [\#987](https://github.com/nlohmann/json/issues/987) - C2664 \(C++/CLR\) cannot convert 'nullptr' to 'nullptr &&' [\#987](https://github.com/nlohmann/json/issues/987)
- Uniform initialization from another json object differs between gcc and clang. [\#985](https://github.com/nlohmann/json/issues/985) - Uniform initialization from another json object differs between gcc and clang. [\#985](https://github.com/nlohmann/json/issues/985)
- Problem with adding the lib as a submodule [\#983](https://github.com/nlohmann/json/issues/983) - Problem with adding the lib as a submodule [\#983](https://github.com/nlohmann/json/issues/983)

View file

@ -9,6 +9,7 @@ SRCS = include/nlohmann/json.hpp \
include/nlohmann/detail/exceptions.hpp \ include/nlohmann/detail/exceptions.hpp \
include/nlohmann/detail/input/binary_reader.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/json_sax.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/internal_iterator.hpp \ include/nlohmann/detail/iterators/internal_iterator.hpp \
@ -20,7 +21,10 @@ SRCS = include/nlohmann/json.hpp \
include/nlohmann/detail/json_ref.hpp \ include/nlohmann/detail/json_ref.hpp \
include/nlohmann/detail/macro_scope.hpp \ include/nlohmann/detail/macro_scope.hpp \
include/nlohmann/detail/macro_unscope.hpp \ include/nlohmann/detail/macro_unscope.hpp \
include/nlohmann/detail/meta.hpp \ include/nlohmann/detail/meta/cpp_future.hpp \
include/nlohmann/detail/meta/detected.hpp \
include/nlohmann/detail/meta/type_traits.hpp \
include/nlohmann/detail/meta/void_t.hpp \
include/nlohmann/detail/output/binary_writer.hpp \ include/nlohmann/detail/output/binary_writer.hpp \
include/nlohmann/detail/output/output_adapters.hpp \ include/nlohmann/detail/output/output_adapters.hpp \
include/nlohmann/detail/output/serializer.hpp \ include/nlohmann/detail/output/serializer.hpp \
@ -82,9 +86,9 @@ clean:
coverage: coverage:
mkdir build_coverage mkdir build_coverage
cd build_coverage ; CXX=g++-5 cmake .. -GNinja -DJSON_Coverage=ON -DJSON_MultipleHeaders=ON cd build_coverage ; CXX=g++-7 cmake .. -GNinja -DJSON_Coverage=ON -DJSON_MultipleHeaders=ON
cd build_coverage ; ninja cd build_coverage ; ninja
cd build_coverage ; ctest -j10 cd build_coverage ; ctest -E '.*_default' -j10
cd build_coverage ; ninja lcov_html cd build_coverage ; ninja lcov_html
open build_coverage/test/html/index.html open build_coverage/test/html/index.html

144
README.md
View file

@ -76,6 +76,8 @@ If you are using the [Meson Build System](http://mesonbuild.com), then you can w
If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add `jsonformoderncpp/x.y.z@vthiery/stable` to your `conanfile.py`'s requires, where `x.y.z` is the release version you want to use. Please file issues [here](https://github.com/vthiery/conan-jsonformoderncpp/issues) if you experience problems with the packages. If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add `jsonformoderncpp/x.y.z@vthiery/stable` to your `conanfile.py`'s requires, where `x.y.z` is the release version you want to use. Please file issues [here](https://github.com/vthiery/conan-jsonformoderncpp/issues) if you experience problems with the packages.
If you are using [Spack](https://www.spack.io/) to manage your dependencies, you can use the `nlohmann_json` package. Please see the [spack project](https://github.com/spack/spack) 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 [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 install nlohmann/json`. Please file issues [here](https://github.com/LoopPerfect/buckaroo-recipes/issues/new?title=nlohmann/nlohmann/json).
@ -84,6 +86,8 @@ If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project fo
If you are using [cget](http://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install nlohmann/json`. A specific version can be installed with `cget install nlohmann/json@v3.1.0`. Also, the multiple header version can be installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`). If you are using [cget](http://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install nlohmann/json`. A specific version can be installed with `cget install nlohmann/json@v3.1.0`. Also, the multiple header version can be installed by adding the `-DJSON_MultipleHeaders=ON` flag (i.e., `cget install nlohmann/json -DJSON_MultipleHeaders=ON`).
If you are using [CocoaPods](https://cocoapods.org), you can use the library by adding pod `"nlohmann_json", '~>3.1.2'` to your podfile (see [an example](https://bitbucket.org/benman/nlohmann_json-cocoapod/src/master/)). Please file issues [here](https://bitbucket.org/benman/nlohmann_json-cocoapod/issues?status=new&status=open).
## 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)).
@ -169,7 +173,6 @@ json empty_object_explicit = json::object();
json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} }); json array_not_object = json::array({ {"currency", "USD"}, {"value", 42.99} });
``` ```
### Serialization / Deserialization ### Serialization / Deserialization
#### To/from strings #### To/from strings
@ -235,6 +238,7 @@ std::cout << j_string << " == " << serialized_string << std::endl;
[`.dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5adea76fedba9898d404fef8598aa663.html#a5adea76fedba9898d404fef8598aa663) always returns the serialized value, and [`.get<std::string>()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a16f9445f7629f634221a42b967cdcd43.html#a16f9445f7629f634221a42b967cdcd43) returns the originally stored string value. [`.dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5adea76fedba9898d404fef8598aa663.html#a5adea76fedba9898d404fef8598aa663) always returns the serialized value, and [`.get<std::string>()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a16f9445f7629f634221a42b967cdcd43.html#a16f9445f7629f634221a42b967cdcd43) returns the originally stored string value.
Note the library only supports UTF-8. When you store strings with different encodings in the library, calling [`dump()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a5adea76fedba9898d404fef8598aa663.html#a5adea76fedba9898d404fef8598aa663) may throw an exception.
#### To/from streams (e.g. files, string streams) #### To/from streams (e.g. files, string streams)
@ -283,10 +287,53 @@ std::vector<std::uint8_t> v = {'t', 'r', 'u', 'e'};
json j = json::parse(v); json j = json::parse(v);
``` ```
#### SAX interface
The library uses a SAX-like interface with the following functions:
```cpp
// called when null is parsed
bool null();
// called when a boolean is parsed; value is passed
bool boolean(bool val);
// called when a signed or unsigned integer number is parsed; value is passed
bool number_integer(number_integer_t val);
bool number_unsigned(number_unsigned_t val);
// called when a floating-point number is parsed; value and original string is passed
bool number_float(number_float_t val, const string_t& s);
// called when a string is parsed; value is passed and can be safely moved away
bool string(string_t& val);
// called when an object or array begins or ends, resp. The number of elements is passed (or -1 if not known)
bool start_object(std::size_t elements);
bool end_object();
bool start_array(std::size_t elements);
bool end_array();
// called when an object key is parsed; value is passed and can be safely moved away
bool key(string_t& val);
// called when a parse error occurs; byte position, the last token, and an exception is passed
bool parse_error(std::size_t position, const std::string& last_token, const detail::exception& ex);
```
The return value of each function determines whether parsing should proceed.
To implement your own SAX handler, proceed as follows:
1. Implement the SAX interface in a class. You can use class `nlohmann::json_sax<json>` as base class, but you can also use any class where the functions described above are implemented and public.
2. Create an object of your SAX interface class, e.g. `my_sax`.
3. Call `bool json::sax_parse(input, &my_sax)`; where the first parameter can be any input like a string or an input stream and the second parameter is a pointer to your SAX interface.
Note the `sax_parse` function only returns a `bool` indicating the result of the last executed SAX event. It does not return a `json` value - it is up to you to decide what to do with the SAX events. Furthermore, no exceptions are thrown in case of a parse error - it is up to you what to do with the exception object passed to your `parse_error` implementation. Internally, the SAX interface is used for the DOM parser (class `json_sax_dom_parser`) as well as the acceptor (`json_sax_acceptor`), see file [`json_sax.hpp`](https://github.com/nlohmann/json/blob/develop/include/nlohmann/detail/input/json_sax.hpp).
### STL-like access ### STL-like access
We designed the JSON class to behave just like an STL container. In fact, it satisfies the [**ReversibleContainer**](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) requirement. We designed the JSON class to behave just like an STL container. In fact, it satisfies the [**ReversibleContainer**](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer) requirement.
```cpp ```cpp
// create an array using push_back // create an array using push_back
@ -523,6 +570,14 @@ int vi = jn.get<int>();
// etc. // etc.
``` ```
Note that `char` types are not automatically converted to JSON strings, but to integer numbers. A conversion to a string must be specified explicitly:
```cpp
char ch = 'A'; // ASCII value 65
json j_default = ch; // stores integer number 65
json j_string = std::string(1, ch); // stores string "A"
```
### Arbitrary types conversions ### Arbitrary types conversions
Every type can be serialized in JSON, not just STL containers and scalar types. Usually, you would do something along those lines: Every type can be serialized in JSON, not just STL containers and scalar types. Usually, you would do something along those lines:
@ -600,7 +655,8 @@ Likewise, when calling `get<your_type>()`, the `from_json` method will be called
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).
* When using `get<your_type>()`, `your_type` **MUST** be [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). (There is a way to bypass this requirement described later.) * Those methods **MUST** be available (e.g., properly headers must be included) everywhere you use the implicit 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.)
* 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.
* In case your type contains several `operator=` definitions, code like `your_variable = your_json;` [may not compile](https://github.com/nlohmann/json/issues/667). You need to write `your_variable = your_json.get<decltype your_variable>();` instead. * In case your type contains several `operator=` definitions, code like `your_variable = your_json;` [may not compile](https://github.com/nlohmann/json/issues/667). You need to write `your_variable = your_json.get<decltype your_variable>();` instead.
* 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.
@ -612,7 +668,7 @@ Some important things:
This requires a bit more advanced technique. But first, let's see how this conversion mechanism works: This requires a bit more advanced technique. But first, let's see how this conversion mechanism works:
The library uses **JSON Serializers** to convert types to json. The library uses **JSON Serializers** to convert types to json.
The default serializer for `nlohmann::json` is `nlohmann::adl_serializer` (ADL means [Argument-Dependent Lookup](http://en.cppreference.com/w/cpp/language/adl)). The default serializer for `nlohmann::json` is `nlohmann::adl_serializer` (ADL means [Argument-Dependent Lookup](https://en.cppreference.com/w/cpp/language/adl)).
It is implemented like this (simplified): It is implemented like this (simplified):
@ -661,7 +717,7 @@ namespace nlohmann {
#### How can I use `get()` for non-default constructible/non-copyable types? #### How can I use `get()` for non-default constructible/non-copyable types?
There is a way, if your type is [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload: There is a way, if your type is [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload:
```cpp ```cpp
struct move_only_type { struct move_only_type {
@ -786,8 +842,8 @@ json j_from_ubjson = json::from_ubjson(v_ubjson);
Though it's 2018 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work: Though it's 2018 already, the support for C++11 is still a bit sparse. Currently, the following compilers are known to work:
- GCC 4.9 - 7.2 (and possibly later) - GCC 4.9 - 8.2 (and possibly later)
- Clang 3.4 - 5.0 (and possibly later) - Clang 3.4 - 6.1 (and possibly later)
- Intel C++ Compiler 17.0.2 (and possibly later) - Intel C++ Compiler 17.0.2 (and possibly later)
- Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later) - Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later)
- Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later) - Microsoft Visual C++ 2017 / Build Tools 15.5.180.51428 (and possibly later)
@ -809,32 +865,38 @@ Please note:
- For GCC running on MinGW or Android SDK, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod`) may occur. Note this is not an issue with the code, but rather with the compiler itself. On Android, see above to build with a newer environment. For MinGW, please refer to [this site](http://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. For Android NDK using `APP_STL := gnustl_static`, please refer to [this discussion](https://github.com/nlohmann/json/issues/219). - For GCC running on MinGW or Android SDK, the error `'to_string' is not a member of 'std'` (or similarly, for `strtod`) may occur. Note this is not an issue with the code, but rather with the compiler itself. On Android, see above to build with a newer environment. For MinGW, please refer to [this site](http://tehsausage.com/mingw-to-string) and [this discussion](https://github.com/nlohmann/json/issues/136) for information on how to fix this bug. For Android NDK using `APP_STL := gnustl_static`, please refer to [this discussion](https://github.com/nlohmann/json/issues/219).
- Unsupported versions of GCC and Clang are rejected by `#error` directives. This can be switched off by defining `JSON_SKIP_UNSUPPORTED_COMPILER_CHECK`. Note that you can expect no support in this case.
The following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json) and [AppVeyor](https://ci.appveyor.com/project/nlohmann/json): The following compilers are currently used in continuous integration at [Travis](https://travis-ci.org/nlohmann/json) and [AppVeyor](https://ci.appveyor.com/project/nlohmann/json):
| Compiler | Operating System | Version String | | Compiler | Operating System | Version String |
|-----------------|------------------------------|----------------| |-----------------|------------------------------|----------------|
| GCC 4.9.4 | Ubuntu 14.04.5 LTS | g++-4.9 (Ubuntu 4.9.4-2ubuntu1~14.04.1) 4.9.4 | | GCC 4.9.4 | Ubuntu 14.04.1 LTS | g++-4.9 (Ubuntu 4.9.4-2ubuntu1~14.04.1) 4.9.4 |
| GCC 5.4.1 | Ubuntu 14.04.5 LTS | g++-5 (Ubuntu 5.4.1-2ubuntu1~14.04) 5.4.1 20160904 | | GCC 5.5.0 | Ubuntu 14.04.1 LTS | g++-5 (Ubuntu 5.5.0-12ubuntu1~14.04) 5.5.0 20171010 |
| GCC 6.3.0 | Ubuntu 14.04.5 LTS | g++-6 (Ubuntu/Linaro 6.3.0-18ubuntu2~14.04) 6.3.0 20170519 | | GCC 6.4.0 | Ubuntu 14.04.1 LTS | g++-6 (Ubuntu 6.4.0-17ubuntu1~14.04) 6.4.0 20180424 |
| GCC 7.1.0 | Ubuntu 14.04.5 LTS | g++-7 (Ubuntu 7.1.0-5ubuntu2~14.04) 7.1.0 | GCC 7.3.0 | Ubuntu 14.04.1 LTS | g++-7 (Ubuntu 7.3.0-21ubuntu1~14.04) 7.3.0 |
| Clang 3.5.0 | Ubuntu 14.04.5 LTS | clang version 3.5.0-4ubuntu2~trusty2 (tags/RELEASE_350/final) | | GCC 7.3.0 | Windows Server 2012 R2 (x64) | g++ (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.3.0 |
| Clang 3.6.2 | Ubuntu 14.04.5 LTS | clang version 3.6.2-svn240577-1~exp1 (branches/release_36) | | GCC 8.1.0 | Ubuntu 14.04.1 LTS | g++-8 (Ubuntu 8.1.0-5ubuntu1~14.04) 8.1.0 |
| Clang 3.7.1 | Ubuntu 14.04.5 LTS | clang version 3.7.1-svn253571-1~exp1 (branches/release_37) | | Clang 3.5.0 | Ubuntu 14.04.1 LTS | clang version 3.5.0-4ubuntu2~trusty2 (tags/RELEASE_350/final) (based on LLVM 3.5.0) |
| Clang 3.8.0 | Ubuntu 14.04.5 LTS | clang version 3.8.0-2ubuntu3~trusty5 (tags/RELEASE_380/final) | | Clang 3.6.2 | Ubuntu 14.04.1 LTS | clang version 3.6.2-svn240577-1~exp1 (branches/release_36) (based on LLVM 3.6.2) |
| Clang 3.9.1 | Ubuntu 14.04.5 LTS | clang version 3.9.1-4ubuntu3~14.04.2 (tags/RELEASE_391/rc2) | | Clang 3.7.1 | Ubuntu 14.04.1 LTS | clang version 3.7.1-svn253571-1~exp1 (branches/release_37) (based on LLVM 3.7.1) |
| Clang 4.0.1 | Ubuntu 14.04.5 LTS | clang version 4.0.1-svn305264-1~exp1 (branches/release_40) | | Clang 3.8.0 | Ubuntu 14.04.1 LTS | clang version 3.8.0-2ubuntu3~trusty5 (tags/RELEASE_380/final) |
| Clang 5.0.0 | Ubuntu 14.04.5 LTS | clang version 5.0.0-svn310902-1~exp1 (branches/release_50) | | Clang 3.9.1 | Ubuntu 14.04.1 LTS | clang version 3.9.1-4ubuntu3~14.04.3 (tags/RELEASE_391/rc2) |
| Clang Xcode 6.4 | Darwin Kernel Version 14.3.0 (OSX 10.10.3) | Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn) | | Clang 4.0.1 | Ubuntu 14.04.1 LTS | clang version 4.0.1-svn305264-1~exp1 (branches/release_40) |
| Clang Xcode 7.3 | Darwin Kernel Version 15.0.0 (OSX 10.10.5) | Apple LLVM version 7.3.0 (clang-703.0.29) | | Clang 5.0.2 | Ubuntu 14.04.1 LTS | clang version 5.0.2-svn328729-1~exp1~20180509123505.100 (branches/release_50) |
| Clang Xcode 8.0 | Darwin Kernel Version 15.6.0 | Apple LLVM version 8.0.0 (clang-800.0.38) | | Clang 6.0.1 | Ubuntu 14.04.1 LTS | clang version 6.0.1-svn334776-1~exp1~20180726133705.85 (branches/release_60) |
| Clang Xcode 8.1 | Darwin Kernel Version 16.1.0 (macOS 10.12.1) | Apple LLVM version 8.0.0 (clang-800.0.42.1) | | 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 Xcode 8.2 | Darwin Kernel Version 16.1.0 (macOS 10.12.1) | Apple LLVM version 8.0.0 (clang-800.0.42.1) | | Clang Xcode 7.3 | OSX 10.11.6 | Apple LLVM version 7.3.0 (clang-703.0.31) |
| Clang Xcode 8.3 | Darwin Kernel Version 16.5.0 (macOS 10.12.4) | Apple LLVM version 8.1.0 (clang-802.0.38) | | Clang Xcode 8.0 | OSX 10.11.6 | Apple LLVM version 8.0.0 (clang-800.0.38) |
| Clang Xcode 9.0 | Darwin Kernel Version 16.7.0 (macOS 10.12.6) | Apple LLVM version 9.0.0 (clang-900.0.37) | | Clang Xcode 8.1 | OSX 10.12.6 | Apple LLVM version 8.0.0 (clang-800.0.42.1) |
| Clang Xcode 9.1 | Darwin Kernel Version 16.7.0 (macOS 10.12.6) | Apple LLVM version 9.0.0 (clang-900.0.38) | | Clang Xcode 8.2 | OSX 10.12.6 | Apple LLVM version 8.0.0 (clang-800.0.42.1) |
| Clang Xcode 9.2 | Darwin Kernel Version 16.7.0 (macOS 10.12.6) | Apple LLVM version 8.1.0 (clang-900.0.39.2) | | 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.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.3 | OSX 10.13.3 | Apple LLVM version 9.1.0 (clang-902.0.39.2) |
| 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.5.180.51428, MSVC 19.12.25830.2 | | Visual Studio 2017 | Windows Server 2016 | Microsoft (R) Build Engine version 15.7.180.61344, MSVC 19.14.26433.0 |
## License ## License
@ -862,6 +924,9 @@ If you have questions regarding the library, I would like to invite you to [open
Only if your request would contain confidential information, please [send me an email](mailto:mail@nlohmann.me). For encrypted messages, please use [this key](https://keybase.io/nlohmann/pgp_keys.asc). Only if your request would contain confidential information, please [send me an email](mailto:mail@nlohmann.me). For encrypted messages, please use [this key](https://keybase.io/nlohmann/pgp_keys.asc).
## Security
[Commits by Niels Lohmann](https://github.com/nlohmann/json/commits) and [releases](https://github.com/nlohmann/json/releases) are signed with this [PGP Key](https://keybase.io/nlohmann/pgp_keys.asc?fingerprint=797167ae41c0a6d9232e48457f3cea63ae251b69).
## Thanks ## Thanks
@ -916,7 +981,7 @@ I deeply appreciate the help of the following people.
- [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable and added Visual Studio 17 to the build matrix. - [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable and added Visual Studio 17 to the build matrix.
- [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file. - [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file.
- [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function. - [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function.
- [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](http://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling, found some nice performance improvements in the parser, improved the benchmarking code, and realized locale-independent number parsing and printing. - [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](https://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling, found some nice performance improvements in the parser, improved the benchmarking code, and realized locale-independent number parsing and printing.
- [cgzones](https://github.com/cgzones) had an idea how to fix the Coverity scan. - [cgzones](https://github.com/cgzones) had an idea how to fix the Coverity scan.
- [Jared Grubb](https://github.com/jaredgrubb) silenced a nasty documentation warning. - [Jared Grubb](https://github.com/jaredgrubb) silenced a nasty documentation warning.
- [Yixin Zhang](https://github.com/qwename) fixed an integer overflow check. - [Yixin Zhang](https://github.com/qwename) fixed an integer overflow check.
@ -975,14 +1040,29 @@ I deeply appreciate the help of the following people.
- [Paul Fultz II](https://github.com/pfultz2) added a note on the cget package manager. - [Paul Fultz II](https://github.com/pfultz2) added a note on the cget package manager.
- [Wilson Lin](https://github.com/wla80) made the integration section of the README more concise. - [Wilson Lin](https://github.com/wla80) made the integration section of the README more concise.
- [RalfBielig](https://github.com/ralfbielig) detected and fixed a memory leak in the parser callback. - [RalfBielig](https://github.com/ralfbielig) detected and fixed a memory leak in the parser callback.
- [agrianius](https://github.com/agrianius) allowed to dump JSON to an alternative string type - [agrianius](https://github.com/agrianius) allowed to dump JSON to an alternative string type.
- [Kevin Tonon](https://github.com/ktonon) overworked the C++11 compiler checks in CMake.
- [Axel Huebl](https://github.com/ax3l) simplified a CMake check and added support for the [Spack package manager](https://spack.io).
- [Carlos O'Ryan](https://github.com/coryan) fixed a typo.
- [James Upjohn](https://github.com/jammehcow) fixed a version number in the compilers section.
- [Chuck Atkins](https://github.com/chuckatkins) adjusted the CMake files to the CMake packaging guidelines
- [Jan Schöppach](https://github.com/dns13) fixed a typo.
- [martin-mfg](https://github.com/martin-mfg) fixed a typo.
- [Matthias Möller](https://github.com/TinyTinni) removed the dependency from `std::stringstream`.
- [agrianius](https://github.com/agrianius) added code to use alternative string implementations.
- [Daniel599](https://github.com/Daniel599) allowed to use more algorithms with the `items()` function.
- [Julius Rakow](https://github.com/jrakow) fixed the Meson include directory and fixed the links to [cppreference.com](cppreference.com).
- [Sonu Lohani](https://github.com/sonulohani) fixed the compilation with MSVC 2015 in debug mode.
- [grembo](https://github.com/grembo) fixed the test suite and re-enabled several test cases.
- [Hyeon Kim](https://github.com/simnalamburt) introduced the macro `JSON_INTERNAL_CATCH` to control the exception handling inside the library.
- [thyu](https://github.com/thyu) fixed a compiler warning.
Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone. Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone.
## Used third-party tools ## Used third-party tools
The library itself contains of a single header file licensed under the MIT license. However, it is built, tested, documented, and whatnot using a lot of third-party tools and services. Thanks a lot! The library itself consists of a single header file licensed under the MIT license. However, it is built, tested, documented, and whatnot using a lot of third-party tools and services. Thanks a lot!
- [**amalgamate.py - Amalgamate C source and header files**](https://github.com/edlund/amalgamate) to create a single header file - [**amalgamate.py - Amalgamate C source and header files**](https://github.com/edlund/amalgamate) to create a single header file
- [**American fuzzy lop**](http://lcamtuf.coredump.cx/afl/) for fuzz testing - [**American fuzzy lop**](http://lcamtuf.coredump.cx/afl/) for fuzz testing
@ -1015,7 +1095,7 @@ The library is currently used in Apple macOS Sierra and iOS 10. I am not sure wh
## Notes ## Notes
- The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](http://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a2e26bd0b0168abb61f67ad5bcd5b9fa1.html#a2e26bd0b0168abb61f67ad5bcd5b9fa1) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a674de1ee73e6bf4843fc5dc1351fb726.html#a674de1ee73e6bf4843fc5dc1351fb726). - The code contains numerous debug **assertions** which can be switched off by defining the preprocessor macro `NDEBUG`, see the [documentation of `assert`](https://en.cppreference.com/w/cpp/error/assert). In particular, note [`operator[]`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a2e26bd0b0168abb61f67ad5bcd5b9fa1.html#a2e26bd0b0168abb61f67ad5bcd5b9fa1) implements **unchecked access** for const objects: If the given key is not present, the behavior is undefined (think of a dereferenced null pointer) and yields an [assertion failure](https://github.com/nlohmann/json/issues/289) if assertions are switched on. If you are not sure whether an element in an object exists, use checked access with the [`at()` function](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a674de1ee73e6bf4843fc5dc1351fb726.html#a674de1ee73e6bf4843fc5dc1351fb726).
- As the exact type of a number is not defined in the [JSON specification](http://rfc7159.net/rfc7159), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions. - As the exact type of a number is not defined in the [JSON specification](http://rfc7159.net/rfc7159), this library tries to choose the best fitting C++ number type automatically. As a result, the type `double` may be used to store numbers which may yield [**floating-point exceptions**](https://github.com/nlohmann/json/issues/181) in certain rare situations if floating-point exceptions have been unmasked in the calling code. These exceptions are not caused by the library and need to be fixed in the calling code, such as by re-masking the exceptions prior to calling library functions.
- The library supports **Unicode input** as follows: - The library supports **Unicode input** as follows:
- Only **UTF-8** encoded input is supported which is the default encoding for JSON according to [RFC 7159](http://rfc7159.net/rfc7159#rfc.section.8.1). - Only **UTF-8** encoded input is supported which is the default encoding for JSON according to [RFC 7159](http://rfc7159.net/rfc7159#rfc.section.8.1).

View file

@ -1,26 +1,58 @@
version: '{build}' version: '{build}'
os:
- Visual Studio 2015
- Visual Studio 2017
environment: environment:
matrix: matrix:
- additional_flags: "" - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
- additional_flags: "/permissive- /std:c++latest /utf-8" COMPILER: mingw
platform: x86
FLAGS: ""
GENERATOR: Ninja
matrix: - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
exclude: platform: x86
- additional_flags: "/permissive- /std:c++latest /utf-8" FLAGS: ""
os: Visual Studio 2015 GENERATOR: Visual Studio 14 2015
init: []
install: [] - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
platform: x86
FLAGS: ""
GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
platform: x86
FLAGS: "/permissive- /std:c++latest /utf-8"
GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
platform: x64
FLAGS: ""
GENERATOR: Visual Studio 14 2015
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
platform: x64
FLAGS: ""
GENERATOR: Visual Studio 15 2017
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
platform: x64
FLAGS: "/permissive- /std:c++latest /utf-8"
GENERATOR: Visual Studio 15 2017
init:
- cmake --version
- msbuild /version
install:
- if "%COMPILER%"=="mingw" appveyor DownloadFile https://github.com/ninja-build/ninja/releases/download/v1.6.0/ninja-win.zip -FileName ninja.zip
- if "%COMPILER%"=="mingw" 7z x ninja.zip -oC:\projects\deps\ninja > nul
- if "%COMPILER%"=="mingw" set PATH=C:\projects\deps\ninja;%PATH%
- if "%COMPILER%"=="mingw" set PATH=C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin;%PATH%
- if "%COMPILER%"=="mingw" g++ --version
before_build:
- cmake . -G "%GENERATOR%" -DCMAKE_CXX_FLAGS="%FLAGS%" -DCMAKE_IGNORE_PATH="C:/Program Files/Git/usr/bin"
build_script: build_script:
- IF "%APPVEYOR_BUILD_WORKER_IMAGE%" == "Visual Studio 2015" ( SET GEN="Visual Studio 14 2015") ELSE (SET GEN="Visual Studio 15 2017")
- cmake . -G%GEN% -DCMAKE_CXX_FLAGS="%additional_flags%"
- cmake --build . --config Release - cmake --build . --config Release
test_script: test_script:

View file

@ -1,9 +1,9 @@
cmake_minimum_required(VERSION 3.0) cmake_minimum_required(VERSION 3.8)
project(JSON_Benchmarks LANGUAGES CXX) project(JSON_Benchmarks LANGUAGES CXX)
# set compiler flags # set compiler flags
if((CMAKE_CXX_COMPILER_ID MATCHES GNU) OR (CMAKE_CXX_COMPILER_ID MATCHES Clang)) if((CMAKE_CXX_COMPILER_ID MATCHES GNU) OR (CMAKE_CXX_COMPILER_ID MATCHES Clang))
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -flto -DNDEBUG -O3") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto -DNDEBUG -O3")
endif() endif()
# configure Google Benchmarks # configure Google Benchmarks
@ -23,4 +23,5 @@ file(COPY ${CMAKE_SOURCE_DIR}/../test/data/regression/floats.json
# benchmark binary # benchmark binary
add_executable(json_benchmarks src/benchmarks.cpp) add_executable(json_benchmarks src/benchmarks.cpp)
target_compile_features(json_benchmarks PRIVATE cxx_std_11)
target_link_libraries(json_benchmarks benchmark ${CMAKE_THREAD_LIBS_INIT}) target_link_libraries(json_benchmarks benchmark ${CMAKE_THREAD_LIBS_INIT})

View file

@ -1,3 +1,5 @@
@PACKAGE_INIT@ @PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/@NLOHMANN_JSON_TARGETS_EXPORT_NAME@.cmake") if(NOT TARGET @PROJECT_NAME@::@NLOHMANN_JSON_TARGET_NAME@)
include("${CMAKE_CURRENT_LIST_DIR}/@NLOHMANN_JSON_TARGETS_EXPORT_NAME@.cmake")
endif()
check_required_components("@PROJECT_NAME@") check_required_components("@PROJECT_NAME@")

View file

@ -5,7 +5,7 @@
#--------------------------------------------------------------------------- #---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8 DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "JSON for Modern C++" PROJECT_NAME = "JSON for Modern C++"
PROJECT_NUMBER = 3.1.2 PROJECT_NUMBER = 3.2.0
PROJECT_BRIEF = PROJECT_BRIEF =
PROJECT_LOGO = PROJECT_LOGO =
OUTPUT_DIRECTORY = . OUTPUT_DIRECTORY = .

Binary file not shown.

Before

Width:  |  Height:  |  Size: 568 KiB

After

Width:  |  Height:  |  Size: 682 KiB

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

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

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

@ -1 +1 @@
<a target="_blank" href="https://wandbox.org/permlink/tfI8DuCuZs3VB9VF"><b>online</b></a> <a target="_blank" href="https://wandbox.org/permlink/3OPLSVPyweUyEHaX"><b>online</b></a>

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

@ -1 +1 @@
<a target="_blank" href="https://wandbox.org/permlink/E1HQedkl1zo48WW5"><b>online</b></a> <a target="_blank" href="https://wandbox.org/permlink/4bn447WQbTERfBaL"><b>online</b></a>

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

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

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

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

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

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

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

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

View file

@ -2,7 +2,7 @@
"compiler": { "compiler": {
"c++": "201103", "c++": "201103",
"family": "clang", "family": "clang",
"version": "9.0.0 (clang-900.0.39.2)" "version": "9.1.0 (clang-902.0.39.2)"
}, },
"copyright": "(C) 2013-2017 Niels Lohmann", "copyright": "(C) 2013-2017 Niels Lohmann",
"name": "JSON for Modern C++", "name": "JSON for Modern C++",
@ -10,8 +10,8 @@
"url": "https://github.com/nlohmann/json", "url": "https://github.com/nlohmann/json",
"version": { "version": {
"major": 3, "major": 3,
"minor": 1, "minor": 2,
"patch": 2, "patch": 0,
"string": "3.1.2" "string": "3.2.0"
} }
} }

View file

@ -17,8 +17,8 @@ int main()
// output values and comparisons // output values and comparisons
std::cout << std::boolalpha; std::cout << std::boolalpha;
std::cout << array_1 << " == " << array_2 << " " << (array_1 > array_2) << '\n'; std::cout << array_1 << " > " << array_2 << " " << (array_1 > array_2) << '\n';
std::cout << object_1 << " == " << object_2 << " " << (object_1 > object_2) << '\n'; std::cout << object_1 << " > " << object_2 << " " << (object_1 > object_2) << '\n';
std::cout << number_1 << " == " << number_2 << " " << (number_1 > number_2) << '\n'; std::cout << number_1 << " > " << number_2 << " " << (number_1 > number_2) << '\n';
std::cout << string_1 << " == " << string_2 << " " << (string_1 > string_2) << '\n'; std::cout << string_1 << " > " << string_2 << " " << (string_1 > string_2) << '\n';
} }

View file

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

View file

@ -1,4 +1,4 @@
[1,2,3] == [1,2,4] false [1,2,3] > [1,2,4] false
{"A":"a","B":"b"} == {"A":"a","B":"b"} false {"A":"a","B":"b"} > {"A":"a","B":"b"} false
17 == 17.0000000000001 false 17 > 17.0000000000001 false
"foo" == "bar" true "foo" > "bar" true

View file

@ -1,4 +1,6 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <sstream>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

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

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

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

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

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

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

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

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

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

View file

@ -1,4 +1,6 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <sstream>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

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

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

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

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

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

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

@ -1 +1 @@
<a target="_blank" href="https://wandbox.org/permlink/8ObNa6ejw4BXQ5qG"><b>online</b></a> <a target="_blank" href="https://wandbox.org/permlink/hFd1W46W2Hb81sHN"><b>online</b></a>

124
doc/examples/sax_parse.cpp Normal file
View file

@ -0,0 +1,124 @@
#include <iostream>
#include <iomanip>
#include <sstream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
// a simple event consumer that collects string representations of the passed
// values; not inheriting from json::json_sax_t is not required, but can
// help not to forget a required function
class sax_event_consumer : public json::json_sax_t
{
public:
std::vector<std::string> events;
bool null() override
{
events.push_back("value: null");
return true;
}
bool boolean(bool val) override
{
events.push_back("value: " + std::string(val ? "true" : "false"));
return true;
}
bool number_integer(number_integer_t val) override
{
events.push_back("value: " + std::to_string(val));
return true;
}
bool number_unsigned(number_unsigned_t val) override
{
events.push_back("value: " + std::to_string(val));
return true;
}
bool number_float(number_float_t val, const string_t& s) override
{
events.push_back("value: " + s);
return true;
}
bool string(string_t& val) override
{
events.push_back("value: " + val);
return true;
}
bool start_object(std::size_t elements) override
{
events.push_back("start: object");
return true;
}
bool end_object() override
{
events.push_back("end: object");
return true;
}
bool start_array(std::size_t elements) override
{
events.push_back("start: array");
return true;
}
bool end_array() override
{
events.push_back("end: array");
return true;
}
bool key(string_t& val) override
{
events.push_back("key: " + val);
return true;
}
bool parse_error(std::size_t position, const std::string& last_token, const json::exception& ex) override
{
events.push_back("error: " + std::string(ex.what()));
return false;
}
};
int main()
{
// a JSON text
auto text = R"(
{
"Image": {
"Width": 800,
"Height": 600,
"Title": "View from 15th Floor",
"Thumbnail": {
"Url": "http://www.example.com/image/481989943",
"Height": 125,
"Width": 100
},
"Animated" : false,
"IDs": [116, 943, 234, 38793],
"Distance": 12.723374634
}
}
)";
// create a SAX event consumer object
sax_event_consumer sec;
// parse and serialize JSON
bool result = json::sax_parse(text, &sec);
// output the recorded events
for (auto& event : sec.events)
{
std::cout << "(" << event << ") ";
}
// output the result of sax_parse
std::cout << "\nresult: " << std::boolalpha << result << std::endl;
}

View file

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

View file

@ -0,0 +1,2 @@
(start: object) (key: Image) (start: object) (key: Width) (value: 800) (key: Height) (value: 600) (key: Title) (value: View from 15th Floor) (key: Thumbnail) (start: object) (key: Url) (value: http://www.example.com/image/481989943) (key: Height) (value: 125) (key: Width) (value: 100) (end: object) (key: Animated) (value: false) (key: IDs) (start: array) (value: 116) (value: 943) (value: 234) (value: 38793) (end: array) (key: Distance) (value: 12.723374634) (end: object) (end: object)
result: true

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

@ -1 +1 @@
<a target="_blank" href="https://wandbox.org/permlink/4bQSclXeqjVFYVL3"><b>online</b></a> <a target="_blank" href="https://wandbox.org/permlink/LRM37xarSuPJmv92"><b>online</b></a>

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

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

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

@ -1 +1 @@
<a target="_blank" href="https://wandbox.org/permlink/j3HE6cOkCmKbxxAt"><b>online</b></a> <a target="_blank" href="https://wandbox.org/permlink/2luqHy9iADx4UNm7"><b>online</b></a>

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

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

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

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

View file

@ -1,4 +1,5 @@
#include <iostream> #include <iostream>
#include <iomanip>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
using json = nlohmann::json; using json = nlohmann::json;

View file

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

View file

@ -39,9 +39,11 @@ These pages contain the API documentation of JSON for Modern C++, a C++11 header
- @link nlohmann::basic_json::dump dump @endlink serialize to string - @link nlohmann::basic_json::dump dump @endlink serialize to string
- @link nlohmann::basic_json::operator<<(std::ostream&, const basic_json &) operator<< @endlink serialize to stream - @link nlohmann::basic_json::operator<<(std::ostream&, const basic_json &) operator<< @endlink serialize to stream
- deserialization / parsing - deserialization / parsing
- @link nlohmann::basic_json::parse parse @endlink parse from string - @link nlohmann::basic_json::parse parse @endlink parse from input (string, file, etc.) and return JSON value
- @link nlohmann::basic_json::sax_parse sax_parse @endlink parse from input (string, file, etc.) and generate SAX events
- @link nlohmann::basic_json::operator>>(std::istream&, basic_json&) operator>> @endlink parse from stream - @link nlohmann::basic_json::operator>>(std::istream&, basic_json&) operator>> @endlink parse from stream
- @link nlohmann::basic_json::accept accept @endlink check for syntax errors without parsing - @link nlohmann::basic_json::accept accept @endlink check for syntax errors without parsing
- @link nlohmann::json_sax SAX interface @endlink define a user-defined SAX event consumer
- [binary formats](binary_formats.md): - [binary formats](binary_formats.md):
- CBOR: @link nlohmann::basic_json::from_cbor from_cbor @endlink / @link nlohmann::basic_json::to_cbor to_cbor @endlink - CBOR: @link nlohmann::basic_json::from_cbor from_cbor @endlink / @link nlohmann::basic_json::to_cbor to_cbor @endlink
- MessagePack: @link nlohmann::basic_json::from_msgpack from_msgpack @endlink / @link nlohmann::basic_json::to_msgpack to_msgpack @endlink - MessagePack: @link nlohmann::basic_json::from_msgpack from_msgpack @endlink / @link nlohmann::basic_json::to_msgpack to_msgpack @endlink
@ -304,4 +306,4 @@ Note that this table only lists those exceptions thrown due to the type. For ins
@author [Niels Lohmann](http://nlohmann.me) @author [Niels Lohmann](http://nlohmann.me)
@see https://github.com/nlohmann/json to download the source code @see https://github.com/nlohmann/json to download the source code
@version 3.1.2 @version 3.2.0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

View file

@ -5,21 +5,34 @@
#include <ciso646> // and, not #include <ciso646> // and, not
#include <forward_list> // forward_list #include <forward_list> // forward_list
#include <iterator> // inserter, front_inserter, end #include <iterator> // inserter, front_inserter, end
#include <map> // map
#include <string> // string #include <string> // string
#include <tuple> // tuple, make_tuple #include <tuple> // tuple, make_tuple
#include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible #include <type_traits> // is_arithmetic, is_same, is_enum, underlying_type, is_convertible
#include <unordered_map> // unordered_map
#include <utility> // pair, declval #include <utility> // pair, declval
#include <valarray> // valarray #include <valarray> // valarray
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta.hpp> #include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
namespace nlohmann namespace nlohmann
{ {
namespace detail namespace detail
{ {
template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename std::nullptr_t& n)
{
if (JSON_UNLIKELY(not j.is_null()))
{
JSON_THROW(type_error::create(302, "type must be null, but is " + std::string(j.type_name())));
}
n = nullptr;
}
// overloads for basic_json template parameters // overloads for basic_json template parameters
template<typename BasicJsonType, typename ArithmeticType, template<typename BasicJsonType, typename ArithmeticType,
enable_if_t<std::is_arithmetic<ArithmeticType>::value and enable_if_t<std::is_arithmetic<ArithmeticType>::value and
@ -70,6 +83,23 @@ void from_json(const BasicJsonType& j, typename BasicJsonType::string_t& s)
s = *j.template get_ptr<const typename BasicJsonType::string_t*>(); s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
} }
template <
typename BasicJsonType, typename CompatibleStringType,
enable_if_t <
is_compatible_string_type<BasicJsonType, CompatibleStringType>::value and
not std::is_same<typename BasicJsonType::string_t,
CompatibleStringType>::value,
int > = 0 >
void from_json(const BasicJsonType& j, CompatibleStringType& s)
{
if (JSON_UNLIKELY(not j.is_string()))
{
JSON_THROW(type_error::create(302, "type must be string, but is " + std::string(j.type_name())));
}
s = *j.template get_ptr<const typename BasicJsonType::string_t*>();
}
template<typename BasicJsonType> template<typename BasicJsonType>
void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val) void from_json(const BasicJsonType& j, typename BasicJsonType::number_float_t& val)
{ {
@ -277,6 +307,44 @@ void from_json(const BasicJsonType& j, std::tuple<Args...>& t)
from_json_tuple_impl(j, t, index_sequence_for<Args...> {}); from_json_tuple_impl(j, t, index_sequence_for<Args...> {});
} }
template <typename BasicJsonType, typename Key, typename Value, typename Compare, typename Allocator,
typename = enable_if_t<not std::is_constructible<
typename BasicJsonType::string_t, Key>::value>>
void from_json(const BasicJsonType& j, std::map<Key, Value, Compare, Allocator>& m)
{
if (JSON_UNLIKELY(not j.is_array()))
{
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
}
for (const auto& p : j)
{
if (JSON_UNLIKELY(not p.is_array()))
{
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
}
m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
}
}
template <typename BasicJsonType, typename Key, typename Value, typename Hash, typename KeyEqual, typename Allocator,
typename = enable_if_t<not std::is_constructible<
typename BasicJsonType::string_t, Key>::value>>
void from_json(const BasicJsonType& j, std::unordered_map<Key, Value, Hash, KeyEqual, Allocator>& m)
{
if (JSON_UNLIKELY(not j.is_array()))
{
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name())));
}
for (const auto& p : j)
{
if (JSON_UNLIKELY(not p.is_array()))
{
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name())));
}
m.emplace(p.at(0).template get<Key>(), p.at(1).template get<Value>());
}
}
struct from_json_fn struct from_json_fn
{ {
private: private:

View file

@ -887,7 +887,7 @@ void grisu2(char* buf, int& len, int& decimal_exponent, FloatType value)
// numbers, all float's can be recovered using strtod (and strtof). However, the resulting // numbers, all float's can be recovered using strtod (and strtof). However, the resulting
// decimal representations are not exactly "short". // decimal representations are not exactly "short".
// //
// The documentation for 'std::to_chars' (http://en.cppreference.com/w/cpp/utility/to_chars) // The documentation for 'std::to_chars' (https://en.cppreference.com/w/cpp/utility/to_chars)
// says "value is converted to a string as if by std::sprintf in the default ("C") locale" // says "value is converted to a string as if by std::sprintf in the default ("C") locale"
// and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars' // and since sprintf promotes float's to double's, I think this is exactly what 'std::to_chars'
// does. // does.

View file

@ -8,8 +8,10 @@
#include <valarray> // valarray #include <valarray> // valarray
#include <vector> // vector #include <vector> // vector
#include <nlohmann/detail/meta.hpp> #include <nlohmann/detail/meta/cpp_future.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
{ {
@ -51,6 +53,16 @@ struct external_constructor<value_t::string>
j.m_value = std::move(s); j.m_value = std::move(s);
j.assert_invariant(); j.assert_invariant();
} }
template<typename BasicJsonType, typename CompatibleStringType,
enable_if_t<not std::is_same<CompatibleStringType, typename BasicJsonType::string_t>::value,
int> = 0>
static void construct(BasicJsonType& j, const CompatibleStringType& str)
{
j.m_type = value_t::string;
j.m_value.string = j.template create<typename BasicJsonType::string_t>(str);
j.assert_invariant();
}
}; };
template<> template<>
@ -247,7 +259,7 @@ void to_json(BasicJsonType& j, const CompatibleArrayType& arr)
template<typename BasicJsonType, typename T, template<typename BasicJsonType, typename T,
enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0> enable_if_t<std::is_convertible<T, BasicJsonType>::value, int> = 0>
void to_json(BasicJsonType& j, std::valarray<T> arr) void to_json(BasicJsonType& j, const std::valarray<T>& arr)
{ {
external_constructor<value_t::array>::construct(j, std::move(arr)); external_constructor<value_t::array>::construct(j, std::move(arr));
} }
@ -284,6 +296,14 @@ void to_json(BasicJsonType& j, const std::pair<Args...>& p)
j = {p.first, p.second}; j = {p.first, p.second};
} }
// for https://github.com/nlohmann/json/pull/1134
template<typename BasicJsonType, typename T,
enable_if_t<std::is_same<T, typename iteration_proxy<typename BasicJsonType::iterator>::iteration_proxy_internal>::value, int> = 0>
void to_json(BasicJsonType& j, T b) noexcept
{
j = {{b.key(), b.value()}};
}
template<typename BasicJsonType, typename Tuple, std::size_t... Idx> template<typename BasicJsonType, typename Tuple, std::size_t... Idx>
void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...>) void to_json_tuple_impl(BasicJsonType& j, const Tuple& t, index_sequence<Idx...>)
{ {

File diff suppressed because it is too large Load diff

View file

@ -1,11 +1,8 @@
#pragma once #pragma once
#include <algorithm> // min
#include <array> // array
#include <cassert> // assert #include <cassert> // assert
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstring> // strlen #include <cstring> // strlen
#include <ios> // streamsize, streamoff, streampos
#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
#include <memory> // shared_ptr, make_shared, addressof #include <memory> // shared_ptr, make_shared, addressof
@ -20,6 +17,9 @@ namespace nlohmann
{ {
namespace detail namespace detail
{ {
/// the supported input formats
enum class input_format_t { json, cbor, msgpack, ubjson };
//////////////////// ////////////////////
// input adapters // // input adapters //
//////////////////// ////////////////////
@ -28,19 +28,17 @@ namespace detail
@brief abstract input adapter interface @brief abstract input adapter interface
Produces a stream of std::char_traits<char>::int_type characters from a Produces a stream of std::char_traits<char>::int_type characters from a
std::istream, a buffer, or some other input type. Accepts the return of exactly std::istream, a buffer, or some other input type. Accepts the return of
one non-EOF character for future input. The int_type characters returned exactly one non-EOF character for future input. The int_type characters
consist of all valid char values as positive values (typically unsigned char), returned consist of all valid char values as positive values (typically
plus an EOF value outside that range, specified by the value of the function unsigned char), plus an EOF value outside that range, specified by the value
std::char_traits<char>::eof(). This value is typically -1, but could be any of the function std::char_traits<char>::eof(). This value is typically -1, but
arbitrary value which is not a valid char value. could be any arbitrary value which is not a valid char value.
*/ */
struct input_adapter_protocol struct input_adapter_protocol
{ {
/// get a character [0,255] or std::char_traits<char>::eof(). /// get a character [0,255] or std::char_traits<char>::eof().
virtual std::char_traits<char>::int_type get_character() = 0; virtual std::char_traits<char>::int_type get_character() = 0;
/// restore the last non-eof() character to input
virtual void unget_character() = 0;
virtual ~input_adapter_protocol() = default; virtual ~input_adapter_protocol() = default;
}; };
@ -68,34 +66,7 @@ class input_stream_adapter : public input_adapter_protocol
explicit input_stream_adapter(std::istream& i) explicit input_stream_adapter(std::istream& i)
: is(i), sb(*i.rdbuf()) : is(i), sb(*i.rdbuf())
{ {}
// skip byte order mark
std::char_traits<char>::int_type c;
if ((c = get_character()) == 0xEF)
{
if ((c = get_character()) == 0xBB)
{
if ((c = get_character()) == 0xBF)
{
return; // Ignore BOM
}
else if (c != std::char_traits<char>::eof())
{
is.unget();
}
is.putback('\xBB');
}
else if (c != std::char_traits<char>::eof())
{
is.unget();
}
is.putback('\xEF');
}
else if (c != std::char_traits<char>::eof())
{
is.unget(); // no byte order mark; process as usual
}
}
// delete because of pointer members // delete because of pointer members
input_stream_adapter(const input_stream_adapter&) = delete; input_stream_adapter(const input_stream_adapter&) = delete;
@ -109,11 +80,6 @@ class input_stream_adapter : public input_adapter_protocol
return sb.sbumpc(); return sb.sbumpc();
} }
void unget_character() override
{
sb.sungetc(); // is.unget() avoided for performance
}
private: private:
/// the associated input stream /// the associated input stream
std::istream& is; std::istream& is;
@ -125,14 +91,8 @@ class input_buffer_adapter : public input_adapter_protocol
{ {
public: public:
input_buffer_adapter(const char* b, const std::size_t l) input_buffer_adapter(const char* b, const std::size_t l)
: cursor(b), limit(b + l), start(b) : cursor(b), limit(b + l)
{ {}
// skip byte order mark
if (l >= 3 and b[0] == '\xEF' and b[1] == '\xBB' and b[2] == '\xBF')
{
cursor += 3;
}
}
// delete because of pointer members // delete because of pointer members
input_buffer_adapter(const input_buffer_adapter&) = delete; input_buffer_adapter(const input_buffer_adapter&) = delete;
@ -148,21 +108,164 @@ class input_buffer_adapter : public input_adapter_protocol
return std::char_traits<char>::eof(); return std::char_traits<char>::eof();
} }
void unget_character() noexcept override
{
if (JSON_LIKELY(cursor > start))
{
--cursor;
}
}
private: private:
/// pointer to the current character /// pointer to the current character
const char* cursor; const char* cursor;
/// pointer past the last character /// pointer past the last character
const char* limit; const char* const limit;
/// pointer to the first character };
const char* start;
template<typename WideStringType>
class wide_string_input_adapter : public input_adapter_protocol
{
public:
explicit wide_string_input_adapter(const WideStringType& w) : str(w) {}
std::char_traits<char>::int_type get_character() noexcept override
{
// check if buffer needs to be filled
if (utf8_bytes_index == utf8_bytes_filled)
{
if (sizeof(typename WideStringType::value_type) == 2)
{
fill_buffer_utf16();
}
else
{
fill_buffer_utf32();
}
assert(utf8_bytes_filled > 0);
assert(utf8_bytes_index == 0);
}
// use buffer
assert(utf8_bytes_filled > 0);
assert(utf8_bytes_index < utf8_bytes_filled);
return utf8_bytes[utf8_bytes_index++];
}
private:
void fill_buffer_utf16()
{
utf8_bytes_index = 0;
if (current_wchar == str.size())
{
utf8_bytes[0] = std::char_traits<char>::eof();
utf8_bytes_filled = 1;
}
else
{
// get the current character
const int wc = static_cast<int>(str[current_wchar++]);
// UTF-16 to UTF-8 encoding
if (wc < 0x80)
{
utf8_bytes[0] = wc;
utf8_bytes_filled = 1;
}
else if (wc <= 0x7FF)
{
utf8_bytes[0] = 0xC0 | ((wc >> 6));
utf8_bytes[1] = 0x80 | (wc & 0x3F);
utf8_bytes_filled = 2;
}
else if (0xD800 > wc or wc >= 0xE000)
{
utf8_bytes[0] = 0xE0 | ((wc >> 12));
utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);
utf8_bytes[2] = 0x80 | (wc & 0x3F);
utf8_bytes_filled = 3;
}
else
{
if (current_wchar < str.size())
{
const int wc2 = static_cast<int>(str[current_wchar++]);
const int charcode = 0x10000 + (((wc & 0x3FF) << 10) | (wc2 & 0x3FF));
utf8_bytes[0] = 0xf0 | (charcode >> 18);
utf8_bytes[1] = 0x80 | ((charcode >> 12) & 0x3F);
utf8_bytes[2] = 0x80 | ((charcode >> 6) & 0x3F);
utf8_bytes[3] = 0x80 | (charcode & 0x3F);
utf8_bytes_filled = 4;
}
else
{
// unknown character
++current_wchar;
utf8_bytes[0] = wc;
utf8_bytes_filled = 1;
}
}
}
}
void fill_buffer_utf32()
{
utf8_bytes_index = 0;
if (current_wchar == str.size())
{
utf8_bytes[0] = std::char_traits<char>::eof();
utf8_bytes_filled = 1;
}
else
{
// get the current character
const int wc = static_cast<int>(str[current_wchar++]);
// UTF-32 to UTF-8 encoding
if (wc < 0x80)
{
utf8_bytes[0] = wc;
utf8_bytes_filled = 1;
}
else if (wc <= 0x7FF)
{
utf8_bytes[0] = 0xC0 | ((wc >> 6) & 0x1F);
utf8_bytes[1] = 0x80 | (wc & 0x3F);
utf8_bytes_filled = 2;
}
else if (wc <= 0xFFFF)
{
utf8_bytes[0] = 0xE0 | ((wc >> 12) & 0x0F);
utf8_bytes[1] = 0x80 | ((wc >> 6) & 0x3F);
utf8_bytes[2] = 0x80 | (wc & 0x3F);
utf8_bytes_filled = 3;
}
else if (wc <= 0x10FFFF)
{
utf8_bytes[0] = 0xF0 | ((wc >> 18 ) & 0x07);
utf8_bytes[1] = 0x80 | ((wc >> 12) & 0x3F);
utf8_bytes[2] = 0x80 | ((wc >> 6) & 0x3F);
utf8_bytes[3] = 0x80 | (wc & 0x3F);
utf8_bytes_filled = 4;
}
else
{
// unknown character
utf8_bytes[0] = wc;
utf8_bytes_filled = 1;
}
}
}
private:
/// the wstring to process
const WideStringType& str;
/// index of the current wchar in str
std::size_t current_wchar = 0;
/// a buffer for UTF-8 bytes
std::array<std::char_traits<char>::int_type, 4> utf8_bytes = {{0, 0, 0, 0}};
/// index to the utf8_codes array for the next valid byte
std::size_t utf8_bytes_index = 0;
/// number of valid bytes in the utf8_codes array
std::size_t utf8_bytes_filled = 0;
}; };
class input_adapter class input_adapter
@ -178,6 +281,15 @@ class input_adapter
input_adapter(std::istream&& i) input_adapter(std::istream&& i)
: ia(std::make_shared<input_stream_adapter>(i)) {} : ia(std::make_shared<input_stream_adapter>(i)) {}
input_adapter(const std::wstring& ws)
: ia(std::make_shared<wide_string_input_adapter<std::wstring>>(ws)) {}
input_adapter(const std::u16string& ws)
: ia(std::make_shared<wide_string_input_adapter<std::u16string>>(ws)) {}
input_adapter(const std::u32string& ws)
: ia(std::make_shared<wide_string_input_adapter<std::u32string>>(ws)) {}
/// input adapter for buffer /// input adapter for buffer
template<typename CharT, template<typename CharT,
typename std::enable_if< typename std::enable_if<

View file

@ -0,0 +1,702 @@
#pragma once
#include <cstddef>
#include <string>
#include <vector>
#include <nlohmann/detail/input/parser.hpp>
#include <nlohmann/detail/exceptions.hpp>
namespace nlohmann
{
/*!
@brief SAX interface
This class describes the SAX interface used by @ref nlohmann::json::sax_parse.
Each function is called in different situations while the input is parsed. The
boolean return value informs the parser whether to continue processing the
input.
*/
template<typename BasicJsonType>
struct json_sax
{
/// type for (signed) integers
using number_integer_t = typename BasicJsonType::number_integer_t;
/// type for unsigned integers
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
/// type for floating-point numbers
using number_float_t = typename BasicJsonType::number_float_t;
/// type for strings
using string_t = typename BasicJsonType::string_t;
/*!
@brief a null value was read
@return whether parsing should proceed
*/
virtual bool null() = 0;
/*!
@brief a boolean value was read
@param[in] val boolean value
@return whether parsing should proceed
*/
virtual bool boolean(bool val) = 0;
/*!
@brief an integer number was read
@param[in] val integer value
@return whether parsing should proceed
*/
virtual bool number_integer(number_integer_t val) = 0;
/*!
@brief an unsigned integer number was read
@param[in] val unsigned integer value
@return whether parsing should proceed
*/
virtual bool number_unsigned(number_unsigned_t val) = 0;
/*!
@brief an floating-point number was read
@param[in] val floating-point value
@param[in] s raw token value
@return whether parsing should proceed
*/
virtual bool number_float(number_float_t val, const string_t& s) = 0;
/*!
@brief a string was read
@param[in] val string value
@return whether parsing should proceed
@note It is safe to move the passed string.
*/
virtual bool string(string_t& val) = 0;
/*!
@brief the beginning of an object was read
@param[in] elements number of object elements or -1 if unknown
@return whether parsing should proceed
@note binary formats may report the number of elements
*/
virtual bool start_object(std::size_t elements) = 0;
/*!
@brief an object key was read
@param[in] val object key
@return whether parsing should proceed
@note It is safe to move the passed string.
*/
virtual bool key(string_t& val) = 0;
/*!
@brief the end of an object was read
@return whether parsing should proceed
*/
virtual bool end_object() = 0;
/*!
@brief the beginning of an array was read
@param[in] elements number of array elements or -1 if unknown
@return whether parsing should proceed
@note binary formats may report the number of elements
*/
virtual bool start_array(std::size_t elements) = 0;
/*!
@brief the end of an array was read
@return whether parsing should proceed
*/
virtual bool end_array() = 0;
/*!
@brief a parse error occurred
@param[in] position the position in the input where the error occurs
@param[in] last_token the last read token
@param[in] error_msg a detailed error message
@return whether parsing should proceed (must return false)
*/
virtual bool parse_error(std::size_t position,
const std::string& last_token,
const detail::exception& ex) = 0;
virtual ~json_sax() = default;
};
namespace detail
{
/*!
@brief SAX implementation to create a JSON value from SAX events
This class implements the @ref json_sax interface and processes the SAX events
to create a JSON value which makes it basically a DOM parser. The structure or
hierarchy of the JSON value is managed by the stack `ref_stack` which contains
a pointer to the respective array or object for each recursion depth.
After successful parsing, the value that is passed by reference to the
constructor contains the parsed value.
@tparam BasicJsonType the JSON type
*/
template<typename BasicJsonType>
class json_sax_dom_parser
{
public:
using number_integer_t = typename BasicJsonType::number_integer_t;
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
using number_float_t = typename BasicJsonType::number_float_t;
using string_t = typename BasicJsonType::string_t;
/*!
@param[in, out] r reference to a JSON value that is manipulated while
parsing
@param[in] allow_exceptions_ whether parse errors yield exceptions
*/
explicit json_sax_dom_parser(BasicJsonType& r, const bool allow_exceptions_ = true)
: root(r), allow_exceptions(allow_exceptions_)
{}
bool null()
{
handle_value(nullptr);
return true;
}
bool boolean(bool val)
{
handle_value(val);
return true;
}
bool number_integer(number_integer_t val)
{
handle_value(val);
return true;
}
bool number_unsigned(number_unsigned_t val)
{
handle_value(val);
return true;
}
bool number_float(number_float_t val, const string_t&)
{
handle_value(val);
return true;
}
bool string(string_t& val)
{
handle_value(val);
return true;
}
bool start_object(std::size_t len)
{
ref_stack.push_back(handle_value(BasicJsonType::value_t::object));
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)));
}
return true;
}
bool key(string_t& val)
{
// add null at given key and store the reference for later
object_element = &(ref_stack.back()->m_value.object->operator[](val));
return true;
}
bool end_object()
{
ref_stack.pop_back();
return true;
}
bool start_array(std::size_t len)
{
ref_stack.push_back(handle_value(BasicJsonType::value_t::array));
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)));
}
return true;
}
bool end_array()
{
ref_stack.pop_back();
return true;
}
bool parse_error(std::size_t, const std::string&,
const detail::exception& ex)
{
errored = true;
if (allow_exceptions)
{
// determine the proper exception type from the id
switch ((ex.id / 100) % 100)
{
case 1:
JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex));
case 4:
JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex));
// LCOV_EXCL_START
case 2:
JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex));
case 3:
JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex));
case 5:
JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex));
default:
assert(false);
// LCOV_EXCL_STOP
}
}
return false;
}
constexpr bool is_errored() const
{
return errored;
}
private:
/*!
@invariant If the ref stack is empty, then the passed value will be the new
root.
@invariant If the ref stack contains a value, then it is an array or an
object to which we can add elements
*/
template<typename Value>
BasicJsonType* handle_value(Value&& v)
{
if (ref_stack.empty())
{
root = BasicJsonType(std::forward<Value>(v));
return &root;
}
else
{
assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
if (ref_stack.back()->is_array())
{
ref_stack.back()->m_value.array->emplace_back(std::forward<Value>(v));
return &(ref_stack.back()->m_value.array->back());
}
else
{
assert(object_element);
*object_element = BasicJsonType(std::forward<Value>(v));
return object_element;
}
}
}
/// the parsed JSON value
BasicJsonType& root;
/// stack to model hierarchy of values
std::vector<BasicJsonType*> ref_stack;
/// helper to hold the reference for the next object element
BasicJsonType* object_element = nullptr;
/// whether a syntax error occurred
bool errored = false;
/// whether to throw exceptions in case of errors
const bool allow_exceptions = true;
};
template<typename BasicJsonType>
class json_sax_dom_callback_parser
{
public:
using number_integer_t = typename BasicJsonType::number_integer_t;
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
using number_float_t = typename BasicJsonType::number_float_t;
using string_t = typename BasicJsonType::string_t;
using parser_callback_t = typename BasicJsonType::parser_callback_t;
using parse_event_t = typename BasicJsonType::parse_event_t;
json_sax_dom_callback_parser(BasicJsonType& r,
const parser_callback_t cb,
const bool allow_exceptions_ = true)
: root(r), callback(cb), allow_exceptions(allow_exceptions_)
{
keep_stack.push_back(true);
}
bool null()
{
handle_value(nullptr);
return true;
}
bool boolean(bool val)
{
handle_value(val);
return true;
}
bool number_integer(number_integer_t val)
{
handle_value(val);
return true;
}
bool number_unsigned(number_unsigned_t val)
{
handle_value(val);
return true;
}
bool number_float(number_float_t val, const string_t&)
{
handle_value(val);
return true;
}
bool string(string_t& val)
{
handle_value(val);
return true;
}
bool start_object(std::size_t len)
{
// check callback for object start
const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::object_start, discarded);
keep_stack.push_back(keep);
auto val = handle_value(BasicJsonType::value_t::object, true);
ref_stack.push_back(val.second);
// check object limit
if (ref_stack.back())
{
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)));
}
}
return true;
}
bool key(string_t& val)
{
BasicJsonType k = BasicJsonType(val);
// check callback for key
const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::key, k);
key_keep_stack.push_back(keep);
// add discarded value at given key and store the reference for later
if (keep and ref_stack.back())
{
object_element = &(ref_stack.back()->m_value.object->operator[](val) = discarded);
}
return true;
}
bool end_object()
{
if (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;
}
}
assert(not ref_stack.empty());
assert(not keep_stack.empty());
ref_stack.pop_back();
keep_stack.pop_back();
if (not ref_stack.empty() and ref_stack.back())
{
// remove discarded value
if (ref_stack.back()->is_object())
{
for (auto it = ref_stack.back()->begin(); it != ref_stack.back()->end(); ++it)
{
if (it->is_discarded())
{
ref_stack.back()->erase(it);
break;
}
}
}
}
return true;
}
bool start_array(std::size_t len)
{
const bool keep = callback(static_cast<int>(ref_stack.size()), parse_event_t::array_start, discarded);
keep_stack.push_back(keep);
auto val = handle_value(BasicJsonType::value_t::array, true);
ref_stack.push_back(val.second);
// check array limit
if (ref_stack.back())
{
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)));
}
}
return true;
}
bool end_array()
{
bool keep = true;
if (ref_stack.back())
{
keep = callback(static_cast<int>(ref_stack.size()) - 1, parse_event_t::array_end, *ref_stack.back());
if (not keep)
{
// discard array
*ref_stack.back() = discarded;
}
}
assert(not ref_stack.empty());
assert(not keep_stack.empty());
ref_stack.pop_back();
keep_stack.pop_back();
// remove discarded value
if (not keep and not ref_stack.empty())
{
if (ref_stack.back()->is_array())
{
ref_stack.back()->m_value.array->pop_back();
}
}
return true;
}
bool parse_error(std::size_t, const std::string&,
const detail::exception& ex)
{
errored = true;
if (allow_exceptions)
{
// determine the proper exception type from the id
switch ((ex.id / 100) % 100)
{
case 1:
JSON_THROW(*reinterpret_cast<const detail::parse_error*>(&ex));
case 4:
JSON_THROW(*reinterpret_cast<const detail::out_of_range*>(&ex));
// LCOV_EXCL_START
case 2:
JSON_THROW(*reinterpret_cast<const detail::invalid_iterator*>(&ex));
case 3:
JSON_THROW(*reinterpret_cast<const detail::type_error*>(&ex));
case 5:
JSON_THROW(*reinterpret_cast<const detail::other_error*>(&ex));
default:
assert(false);
// LCOV_EXCL_STOP
}
}
return false;
}
constexpr bool is_errored() const
{
return errored;
}
private:
/*!
@param[in] v value to add to the JSON value we build during parsing
@param[in] skip_callback whether we should skip calling the callback
function; this is required after start_array() and
start_object() SAX events, because otherwise we would call the
callback function with an empty array or object, respectively.
@invariant If the ref stack is empty, then the passed value will be the new
root.
@invariant If the ref stack contains a value, then it is an array or an
object to which we can add elements
@return pair of boolean (whether value should be kept) and pointer (to the
passed value in the ref_stack hierarchy; nullptr if not kept)
*/
template<typename Value>
std::pair<bool, BasicJsonType*> handle_value(Value&& v, const bool skip_callback = false)
{
assert(not keep_stack.empty());
// do not handle this value if we know it would be added to a discarded
// container
if (not keep_stack.back())
{
return {false, nullptr};
}
// create value
auto value = BasicJsonType(std::forward<Value>(v));
// check callback
const bool keep = skip_callback or callback(static_cast<int>(ref_stack.size()), parse_event_t::value, value);
// do not handle this value if we just learnt it shall be discarded
if (not keep)
{
return {false, nullptr};
}
if (ref_stack.empty())
{
root = std::move(value);
return {true, &root};
}
else
{
// skip this value if we already decided to skip the parent
// (https://github.com/nlohmann/json/issues/971#issuecomment-413678360)
if (not ref_stack.back())
{
return {false, nullptr};
}
assert(ref_stack.back()->is_array() or ref_stack.back()->is_object());
if (ref_stack.back()->is_array())
{
ref_stack.back()->m_value.array->push_back(std::move(value));
return {true, &(ref_stack.back()->m_value.array->back())};
}
else
{
// 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)
{
return {false, nullptr};
}
assert(object_element);
*object_element = std::move(value);
return {true, object_element};
}
}
}
/// the parsed JSON value
BasicJsonType& root;
/// stack to model hierarchy of values
std::vector<BasicJsonType*> ref_stack;
/// stack to manage which values to keep
std::vector<bool> keep_stack;
/// stack to manage which object keys to keep
std::vector<bool> key_keep_stack;
/// helper to hold the reference for the next object element
BasicJsonType* object_element = nullptr;
/// whether a syntax error occurred
bool errored = false;
/// callback function
const parser_callback_t callback = nullptr;
/// whether to throw exceptions in case of errors
const bool allow_exceptions = true;
/// a discarded value for the callback
BasicJsonType discarded = BasicJsonType::value_t::discarded;
};
template<typename BasicJsonType>
class json_sax_acceptor
{
public:
using number_integer_t = typename BasicJsonType::number_integer_t;
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
using number_float_t = typename BasicJsonType::number_float_t;
using string_t = typename BasicJsonType::string_t;
bool null()
{
return true;
}
bool boolean(bool)
{
return true;
}
bool number_integer(number_integer_t)
{
return true;
}
bool number_unsigned(number_unsigned_t)
{
return true;
}
bool number_float(number_float_t, const string_t&)
{
return true;
}
bool string(string_t&)
{
return true;
}
bool start_object(std::size_t = std::size_t(-1))
{
return true;
}
bool key(string_t&)
{
return true;
}
bool end_object()
{
return true;
}
bool start_array(std::size_t = std::size_t(-1))
{
return true;
}
bool end_array()
{
return true;
}
bool parse_error(std::size_t, const std::string&, const detail::exception&)
{
return false;
}
};
}
}

View file

@ -3,10 +3,8 @@
#include <clocale> // localeconv #include <clocale> // localeconv
#include <cstddef> // size_t #include <cstddef> // size_t
#include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull #include <cstdlib> // strtof, strtod, strtold, strtoll, strtoull
#include <cstdio> // snprintf
#include <initializer_list> // initializer_list #include <initializer_list> // initializer_list
#include <ios> // hex, uppercase
#include <iomanip> // setw, setfill
#include <sstream> // stringstream
#include <string> // char_traits, string #include <string> // char_traits, string
#include <vector> // vector #include <vector> // vector
@ -94,12 +92,14 @@ class lexer
return "end of input"; return "end of input";
case token_type::literal_or_value: case token_type::literal_or_value:
return "'[', '{', or a literal"; return "'[', '{', or a literal";
// LCOV_EXCL_START
default: // catch non-enum values default: // catch non-enum values
return "unknown token"; // LCOV_EXCL_LINE return "unknown token";
// LCOV_EXCL_STOP
} }
} }
explicit lexer(detail::input_adapter_t adapter) explicit lexer(detail::input_adapter_t&& adapter)
: ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {} : ia(std::move(adapter)), decimal_point_char(get_decimal_point()) {}
// delete because of pointer members // delete because of pointer members
@ -747,11 +747,13 @@ class lexer
goto scan_number_any1; goto scan_number_any1;
} }
// LCOV_EXCL_START
default: default:
{ {
// all other characters are rejected outside scan_number() // all other characters are rejected outside scan_number()
assert(false); // LCOV_EXCL_LINE assert(false);
} }
// LCOV_EXCL_STOP
} }
scan_number_minus: scan_number_minus:
@ -1081,7 +1083,16 @@ scan_number_done:
std::char_traits<char>::int_type get() std::char_traits<char>::int_type get()
{ {
++chars_read; ++chars_read;
current = ia->get_character(); if (next_unget)
{
// just reset the next_unget variable and work with current
next_unget = false;
}
else
{
current = ia->get_character();
}
if (JSON_LIKELY(current != std::char_traits<char>::eof())) if (JSON_LIKELY(current != std::char_traits<char>::eof()))
{ {
token_string.push_back(std::char_traits<char>::to_char_type(current)); token_string.push_back(std::char_traits<char>::to_char_type(current));
@ -1089,13 +1100,20 @@ scan_number_done:
return current; return current;
} }
/// unget current character (return it again on next get) /*!
@brief unget current character (read it again on next get)
We implement unget by setting variable next_unget to true. The input is not
changed - we just simulate ungetting by modifying chars_read and
token_string. The next call to get() will behave as if the unget character
is read again.
*/
void unget() void unget()
{ {
next_unget = true;
--chars_read; --chars_read;
if (JSON_LIKELY(current != std::char_traits<char>::eof())) if (JSON_LIKELY(current != std::char_traits<char>::eof()))
{ {
ia->unget_character();
assert(token_string.size() != 0); assert(token_string.size() != 0);
token_string.pop_back(); token_string.pop_back();
} }
@ -1131,9 +1149,9 @@ scan_number_done:
} }
/// return current string value (implicitly resets the token; useful only once) /// return current string value (implicitly resets the token; useful only once)
string_t&& move_string() string_t& get_string()
{ {
return std::move(token_buffer); return token_buffer;
} }
///////////////////// /////////////////////
@ -1158,10 +1176,9 @@ scan_number_done:
if ('\x00' <= c and c <= '\x1F') if ('\x00' <= c and c <= '\x1F')
{ {
// escape control characters // escape control characters
std::stringstream ss; char cs[9];
ss << "<U+" << std::setw(4) << std::uppercase << std::setfill('0') snprintf(cs, 9, "<U+%.4X>", static_cast<unsigned char>(c));
<< std::hex << static_cast<int>(c) << ">"; result += cs;
result += ss.str();
} }
else else
{ {
@ -1183,8 +1200,43 @@ scan_number_done:
// actual scanner // actual scanner
///////////////////// /////////////////////
/*!
@brief skip the UTF-8 byte order mark
@return true iff there is no BOM or the correct BOM has been skipped
*/
bool skip_bom()
{
if (get() == 0xEF)
{
if (get() == 0xBB and get() == 0xBF)
{
// we completely parsed the BOM
return true;
}
else
{
// after reading 0xEF, an unexpected character followed
return false;
}
}
else
{
// the first character is not the beginning of the BOM; unget it to
// process is later
unget();
return true;
}
}
token_type scan() token_type scan()
{ {
// initially, skip the BOM
if (chars_read == 0 and not skip_bom())
{
error_message = "invalid BOM; must be 0xEF 0xBB 0xBF if given";
return token_type::parse_error;
}
// read next character and ignore whitespace // read next character and ignore whitespace
do do
{ {
@ -1254,6 +1306,9 @@ scan_number_done:
/// the current character /// the current character
std::char_traits<char>::int_type current = std::char_traits<char>::eof(); std::char_traits<char>::int_type current = std::char_traits<char>::eof();
/// whether the next get() call should just return current
bool next_unget = false;
/// the number of characters read /// the number of characters read
std::size_t chars_read = 0; std::size_t chars_read = 0;

View file

@ -9,7 +9,9 @@
#include <nlohmann/detail/exceptions.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/input/input_adapters.hpp> #include <nlohmann/detail/input/input_adapters.hpp>
#include <nlohmann/detail/input/json_sax.hpp>
#include <nlohmann/detail/input/lexer.hpp> #include <nlohmann/detail/input/lexer.hpp>
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
@ -57,11 +59,14 @@ class parser
std::function<bool(int depth, parse_event_t event, BasicJsonType& parsed)>; std::function<bool(int depth, parse_event_t event, BasicJsonType& parsed)>;
/// a parser reading from an input adapter /// a parser reading from an input adapter
explicit parser(detail::input_adapter_t adapter, explicit parser(detail::input_adapter_t&& adapter,
const parser_callback_t cb = nullptr, const parser_callback_t cb = nullptr,
const bool allow_exceptions_ = true) const bool allow_exceptions_ = true)
: callback(cb), m_lexer(adapter), allow_exceptions(allow_exceptions_) : callback(cb), m_lexer(std::move(adapter)), allow_exceptions(allow_exceptions_)
{} {
// read first token
get_token();
}
/*! /*!
@brief public parser interface @brief public parser interface
@ -75,31 +80,54 @@ class parser
*/ */
void parse(const bool strict, BasicJsonType& result) void parse(const bool strict, BasicJsonType& result)
{ {
// read first token if (callback)
get_token();
parse_internal(true, result);
result.assert_invariant();
// in strict mode, input must be completely read
if (strict)
{ {
get_token(); json_sax_dom_callback_parser<BasicJsonType> sdp(result, callback, allow_exceptions);
expect(token_type::end_of_input); sax_parse_internal(&sdp);
result.assert_invariant();
// in strict mode, input must be completely read
if (strict and (get_token() != token_type::end_of_input))
{
sdp.parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input)));
}
// in case of an error, return discarded value
if (sdp.is_errored())
{
result = value_t::discarded;
return;
}
// set top-level value to null if it was discarded by the callback
// function
if (result.is_discarded())
{
result = nullptr;
}
} }
else
// in case of an error, return discarded value
if (errored)
{ {
result = value_t::discarded; json_sax_dom_parser<BasicJsonType> sdp(result, allow_exceptions);
return; sax_parse_internal(&sdp);
} result.assert_invariant();
// set top-level value to null if it was discarded by the callback // in strict mode, input must be completely read
// function if (strict and (get_token() != token_type::end_of_input))
if (result.is_discarded()) {
{ sdp.parse_error(m_lexer.get_position(),
result = nullptr; m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input)));
}
// in case of an error, return discarded value
if (sdp.is_errored())
{
result = value_t::discarded;
return;
}
} }
} }
@ -111,414 +139,311 @@ class parser
*/ */
bool accept(const bool strict = true) bool accept(const bool strict = true)
{ {
// read first token json_sax_acceptor<BasicJsonType> sax_acceptor;
get_token(); return sax_parse(&sax_acceptor, strict);
}
if (not accept_internal()) template <typename SAX>
bool sax_parse(SAX* sax, const bool strict = true)
{
(void)detail::is_sax_static_asserts<SAX, BasicJsonType> {};
const bool result = sax_parse_internal(sax);
// strict mode: next byte must be EOF
if (result and strict and (get_token() != token_type::end_of_input))
{ {
return false; return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_of_input)));
} }
// strict => last token must be EOF return result;
return not strict or (get_token() == token_type::end_of_input);
} }
private: private:
/*! template <typename SAX>
@brief the actual parser bool sax_parse_internal(SAX* sax)
@throw parse_error.101 in case of an unexpected token
@throw parse_error.102 if to_unicode fails or surrogate error
@throw parse_error.103 if to_unicode fails
*/
void parse_internal(bool keep, BasicJsonType& result)
{ {
// never parse after a parse error was detected // stack to remember the hieararchy of structured values we are parsing
assert(not errored); // true = array; false = object
std::vector<bool> states;
// value to avoid a goto (see comment where set to true)
bool skip_to_state_evaluation = false;
// start with a discarded value while (true)
if (not result.is_discarded())
{ {
result.m_value.destroy(result.m_type); if (not skip_to_state_evaluation)
result.m_type = value_t::discarded;
}
switch (last_token)
{
case token_type::begin_object:
{ {
if (keep) // invariant: get_token() was called before each iteration
switch (last_token)
{ {
if (callback) case token_type::begin_object:
{ {
keep = callback(depth++, parse_event_t::object_start, result); if (JSON_UNLIKELY(not sax->start_object(std::size_t(-1))))
}
if (not callback or keep)
{
// explicitly set result to object to cope with {}
result.m_type = value_t::object;
result.m_value = value_t::object;
}
}
// read next token
get_token();
// closing } -> we are done
if (last_token == token_type::end_object)
{
if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
{
result.m_value.destroy(result.m_type);
result.m_type = value_t::discarded;
}
break;
}
// parse values
string_t key;
BasicJsonType value;
while (true)
{
// store key
if (not expect(token_type::value_string))
{
return;
}
key = m_lexer.move_string();
bool keep_tag = false;
if (keep)
{
if (callback)
{ {
BasicJsonType k(key); return false;
keep_tag = callback(depth, parse_event_t::key, k); }
// closing } -> we are done
if (get_token() == token_type::end_object)
{
if (JSON_UNLIKELY(not sax->end_object()))
{
return false;
}
break;
}
// parse key
if (JSON_UNLIKELY(last_token != token_type::value_string))
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
} }
else else
{ {
keep_tag = true; if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
{
return false;
}
}
// parse separator (:)
if (JSON_UNLIKELY(get_token() != token_type::name_separator))
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
}
// remember we are now inside an object
states.push_back(false);
// parse values
get_token();
continue;
}
case token_type::begin_array:
{
if (JSON_UNLIKELY(not sax->start_array(std::size_t(-1))))
{
return false;
}
// closing ] -> we are done
if (get_token() == token_type::end_array)
{
if (JSON_UNLIKELY(not sax->end_array()))
{
return false;
}
break;
}
// remember we are now inside an array
states.push_back(true);
// parse values (no need to call get_token)
continue;
}
case token_type::value_float:
{
const auto res = m_lexer.get_number_float();
if (JSON_UNLIKELY(not std::isfinite(res)))
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
out_of_range::create(406, "number overflow parsing '" + m_lexer.get_token_string() + "'"));
}
else
{
if (JSON_UNLIKELY(not sax->number_float(res, m_lexer.get_string())))
{
return false;
}
break;
} }
} }
// parse separator (:) case token_type::literal_false:
get_token();
if (not expect(token_type::name_separator))
{ {
return; if (JSON_UNLIKELY(not sax->boolean(false)))
{
return false;
}
break;
} }
// parse and add value case token_type::literal_null:
get_token();
value.m_value.destroy(value.m_type);
value.m_type = value_t::discarded;
parse_internal(keep, value);
if (JSON_UNLIKELY(errored))
{ {
return; if (JSON_UNLIKELY(not sax->null()))
{
return false;
}
break;
} }
if (keep and keep_tag and not value.is_discarded()) case token_type::literal_true:
{ {
result.m_value.object->emplace(std::move(key), std::move(value)); if (JSON_UNLIKELY(not sax->boolean(true)))
{
return false;
}
break;
} }
// comma -> next value case token_type::value_integer:
get_token();
if (last_token == token_type::value_separator)
{ {
get_token(); if (JSON_UNLIKELY(not sax->number_integer(m_lexer.get_number_integer())))
continue; {
return false;
}
break;
} }
// closing } case token_type::value_string:
if (not expect(token_type::end_object))
{ {
return; if (JSON_UNLIKELY(not sax->string(m_lexer.get_string())))
} {
break; return false;
} }
break;
if (keep and callback and not callback(--depth, parse_event_t::object_end, result))
{
result.m_value.destroy(result.m_type);
result.m_type = value_t::discarded;
}
break;
}
case token_type::begin_array:
{
if (keep)
{
if (callback)
{
keep = callback(depth++, parse_event_t::array_start, result);
} }
if (not callback or keep) case token_type::value_unsigned:
{ {
// explicitly set result to array to cope with [] if (JSON_UNLIKELY(not sax->number_unsigned(m_lexer.get_number_unsigned())))
result.m_type = value_t::array; {
result.m_value = value_t::array; return false;
}
break;
}
case token_type::parse_error:
{
// using "uninitialized" to avoid "expected" message
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::uninitialized)));
}
default: // the last token was unexpected
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::literal_or_value)));
} }
} }
// read next token
get_token();
// closing ] -> we are done
if (last_token == token_type::end_array)
{
if (callback and not callback(--depth, parse_event_t::array_end, result))
{
result.m_value.destroy(result.m_type);
result.m_type = value_t::discarded;
}
break;
}
// parse values
BasicJsonType value;
while (true)
{
// parse value
value.m_value.destroy(value.m_type);
value.m_type = value_t::discarded;
parse_internal(keep, value);
if (JSON_UNLIKELY(errored))
{
return;
}
if (keep and not value.is_discarded())
{
result.m_value.array->push_back(std::move(value));
}
// comma -> next value
get_token();
if (last_token == token_type::value_separator)
{
get_token();
continue;
}
// closing ]
if (not expect(token_type::end_array))
{
return;
}
break;
}
if (keep and callback and not callback(--depth, parse_event_t::array_end, result))
{
result.m_value.destroy(result.m_type);
result.m_type = value_t::discarded;
}
break;
} }
else
case token_type::literal_null:
{ {
result.m_type = value_t::null; skip_to_state_evaluation = false;
break;
} }
case token_type::value_string: // we reached this line after we successfully parsed a value
if (states.empty())
{ {
result.m_type = value_t::string; // empty stack: we reached the end of the hieararchy: done
result.m_value = m_lexer.move_string();
break;
}
case token_type::literal_true:
{
result.m_type = value_t::boolean;
result.m_value = true;
break;
}
case token_type::literal_false:
{
result.m_type = value_t::boolean;
result.m_value = false;
break;
}
case token_type::value_unsigned:
{
result.m_type = value_t::number_unsigned;
result.m_value = m_lexer.get_number_unsigned();
break;
}
case token_type::value_integer:
{
result.m_type = value_t::number_integer;
result.m_value = m_lexer.get_number_integer();
break;
}
case token_type::value_float:
{
result.m_type = value_t::number_float;
result.m_value = m_lexer.get_number_float();
// throw in case of infinity or NAN
if (JSON_UNLIKELY(not std::isfinite(result.m_value.number_float)))
{
if (allow_exceptions)
{
JSON_THROW(out_of_range::create(406, "number overflow parsing '" +
m_lexer.get_token_string() + "'"));
}
expect(token_type::uninitialized);
}
break;
}
case token_type::parse_error:
{
// using "uninitialized" to avoid "expected" message
if (not expect(token_type::uninitialized))
{
return;
}
break; // LCOV_EXCL_LINE
}
default:
{
// the last token was unexpected; we expected a value
if (not expect(token_type::literal_or_value))
{
return;
}
break; // LCOV_EXCL_LINE
}
}
if (keep and callback and not callback(depth, parse_event_t::value, result))
{
result.m_value.destroy(result.m_type);
result.m_type = value_t::discarded;
}
}
/*!
@brief the actual acceptor
@invariant 1. The last token is not yet processed. Therefore, the caller
of this function must make sure a token has been read.
2. When this function returns, the last token is processed.
That is, the last read character was already considered.
This invariant makes sure that no token needs to be "unput".
*/
bool accept_internal()
{
switch (last_token)
{
case token_type::begin_object:
{
// read next token
get_token();
// closing } -> we are done
if (last_token == token_type::end_object)
{
return true;
}
// parse values
while (true)
{
// parse key
if (last_token != token_type::value_string)
{
return false;
}
// parse separator (:)
get_token();
if (last_token != token_type::name_separator)
{
return false;
}
// parse value
get_token();
if (not accept_internal())
{
return false;
}
// comma -> next value
get_token();
if (last_token == token_type::value_separator)
{
get_token();
continue;
}
// closing }
return (last_token == token_type::end_object);
}
}
case token_type::begin_array:
{
// read next token
get_token();
// closing ] -> we are done
if (last_token == token_type::end_array)
{
return true;
}
// parse values
while (true)
{
// parse value
if (not accept_internal())
{
return false;
}
// comma -> next value
get_token();
if (last_token == token_type::value_separator)
{
get_token();
continue;
}
// closing ]
return (last_token == token_type::end_array);
}
}
case token_type::value_float:
{
// reject infinity or NAN
return std::isfinite(m_lexer.get_number_float());
}
case token_type::literal_false:
case token_type::literal_null:
case token_type::literal_true:
case token_type::value_integer:
case token_type::value_string:
case token_type::value_unsigned:
return true; return true;
}
else
{
if (states.back()) // array
{
// comma -> next value
if (get_token() == token_type::value_separator)
{
// parse a new value
get_token();
continue;
}
default: // the last token was unexpected // closing ]
return false; if (JSON_LIKELY(last_token == token_type::end_array))
{
if (JSON_UNLIKELY(not sax->end_array()))
{
return false;
}
// We are done with this array. Before we can parse a
// new value, we need to evaluate the new state first.
// By setting skip_to_state_evaluation to false, we
// are effectively jumping to the beginning of this if.
assert(not states.empty());
states.pop_back();
skip_to_state_evaluation = true;
continue;
}
else
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_array)));
}
}
else // object
{
// comma -> next value
if (get_token() == token_type::value_separator)
{
// parse key
if (JSON_UNLIKELY(get_token() != token_type::value_string))
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::value_string)));
}
else
{
if (JSON_UNLIKELY(not sax->key(m_lexer.get_string())))
{
return false;
}
}
// parse separator (:)
if (JSON_UNLIKELY(get_token() != token_type::name_separator))
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::name_separator)));
}
// parse values
get_token();
continue;
}
// closing }
if (JSON_LIKELY(last_token == token_type::end_object))
{
if (JSON_UNLIKELY(not sax->end_object()))
{
return false;
}
// We are done with this object. Before we can parse a
// new value, we need to evaluate the new state first.
// By setting skip_to_state_evaluation to false, we
// are effectively jumping to the beginning of this if.
assert(not states.empty());
states.pop_back();
skip_to_state_evaluation = true;
continue;
}
else
{
return sax->parse_error(m_lexer.get_position(),
m_lexer.get_token_string(),
parse_error::create(101, m_lexer.get_position(), exception_message(token_type::end_object)));
}
}
}
} }
} }
@ -528,29 +453,7 @@ class parser
return (last_token = m_lexer.scan()); return (last_token = m_lexer.scan());
} }
/*! std::string exception_message(const token_type expected)
@throw parse_error.101 if expected token did not occur
*/
bool expect(token_type t)
{
if (JSON_UNLIKELY(t != last_token))
{
errored = true;
expected = t;
if (allow_exceptions)
{
throw_exception();
}
else
{
return false;
}
}
return true;
}
[[noreturn]] void throw_exception() const
{ {
std::string error_msg = "syntax error - "; std::string error_msg = "syntax error - ";
if (last_token == token_type::parse_error) if (last_token == token_type::parse_error)
@ -568,22 +471,16 @@ class parser
error_msg += "; expected " + std::string(lexer_t::token_type_name(expected)); error_msg += "; expected " + std::string(lexer_t::token_type_name(expected));
} }
JSON_THROW(parse_error::create(101, m_lexer.get_position(), error_msg)); return error_msg;
} }
private: private:
/// current level of recursion
int depth = 0;
/// callback function /// callback function
const parser_callback_t callback = nullptr; const parser_callback_t callback = nullptr;
/// the type of the last read token /// the type of the last read token
token_type last_token = token_type::uninitialized; token_type last_token = token_type::uninitialized;
/// the lexer /// the lexer
lexer_t m_lexer; lexer_t m_lexer;
/// whether a syntax error occurred
bool errored = false;
/// possible reason for the syntax error
token_type expected = token_type::uninitialized;
/// whether to throw exceptions in case of errors /// whether to throw exceptions in case of errors
const bool allow_exceptions = true; const bool allow_exceptions = true;
}; };

View file

@ -8,7 +8,7 @@
#include <nlohmann/detail/iterators/internal_iterator.hpp> #include <nlohmann/detail/iterators/internal_iterator.hpp>
#include <nlohmann/detail/iterators/primitive_iterator.hpp> #include <nlohmann/detail/iterators/primitive_iterator.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta.hpp> #include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
namespace nlohmann namespace nlohmann
@ -31,7 +31,7 @@ This class implements a both iterators (iterator and const_iterator) for the
@requirement The class satisfies the following concept requirements: @requirement The class satisfies the following concept requirements:
- -
[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): [BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
The iterator that can be moved can be moved in both directions (i.e. The iterator that can be moved can be moved in both directions (i.e.
incremented and decremented). incremented and decremented).
@ -583,7 +583,7 @@ class iter_impl
@brief return the key of an object iterator @brief return the key of an object iterator
@pre The iterator is initialized; i.e. `m_object != nullptr`. @pre The iterator is initialized; i.e. `m_object != nullptr`.
*/ */
typename object_t::key_type key() const const typename object_t::key_type& key() const
{ {
assert(m_object != nullptr); assert(m_object != nullptr);

View file

@ -2,6 +2,7 @@
#include <cstddef> // size_t #include <cstddef> // size_t
#include <string> // string, to_string #include <string> // string, to_string
#include <iterator> // input_iterator_tag
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
@ -16,15 +17,31 @@ template<typename IteratorType> class iteration_proxy
/// helper class for iteration /// helper class for iteration
class iteration_proxy_internal class iteration_proxy_internal
{ {
public:
using difference_type = std::ptrdiff_t;
using value_type = iteration_proxy_internal;
using pointer = iteration_proxy_internal*;
using reference = iteration_proxy_internal&;
using iterator_category = std::input_iterator_tag;
private: private:
/// the iterator /// the iterator
IteratorType anchor; IteratorType anchor;
/// an index for arrays (used to create key names) /// an index for arrays (used to create key names)
std::size_t array_index = 0; std::size_t array_index = 0;
/// last stringified array index
mutable std::size_t array_index_last = 0;
/// a string representation of the array index
mutable std::string array_index_str = "0";
/// an empty string (to return a reference for primitive values)
const std::string empty_str = "";
public: public:
explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {} explicit iteration_proxy_internal(IteratorType it) noexcept : anchor(it) {}
iteration_proxy_internal(const iteration_proxy_internal&) = default;
iteration_proxy_internal& operator=(const iteration_proxy_internal&) = default;
/// dereference operator (needed for range-based for) /// dereference operator (needed for range-based for)
iteration_proxy_internal& operator*() iteration_proxy_internal& operator*()
{ {
@ -40,6 +57,12 @@ template<typename IteratorType> class iteration_proxy
return *this; return *this;
} }
/// equality operator (needed for InputIterator)
bool operator==(const iteration_proxy_internal& o) const noexcept
{
return anchor == o.anchor;
}
/// inequality operator (needed for range-based for) /// inequality operator (needed for range-based for)
bool operator!=(const iteration_proxy_internal& o) const noexcept bool operator!=(const iteration_proxy_internal& o) const noexcept
{ {
@ -47,7 +70,7 @@ template<typename IteratorType> class iteration_proxy
} }
/// return key of the iterator /// return key of the iterator
std::string key() const const std::string& key() const
{ {
assert(anchor.m_object != nullptr); assert(anchor.m_object != nullptr);
@ -55,7 +78,14 @@ template<typename IteratorType> class iteration_proxy
{ {
// use integer array index as key // use integer array index as key
case value_t::array: case value_t::array:
return std::to_string(array_index); {
if (array_index != array_index_last)
{
array_index_str = std::to_string(array_index);
array_index_last = array_index;
}
return array_index_str;
}
// use key from the object // use key from the object
case value_t::object: case value_t::object:
@ -63,7 +93,7 @@ template<typename IteratorType> class iteration_proxy
// use an empty key for all primitive types // use an empty key for all primitive types
default: default:
return ""; return empty_str;
} }
} }

View file

@ -21,10 +21,10 @@ create @ref const_reverse_iterator).
@requirement The class satisfies the following concept requirements: @requirement The class satisfies the following concept requirements:
- -
[BidirectionalIterator](http://en.cppreference.com/w/cpp/concept/BidirectionalIterator): [BidirectionalIterator](https://en.cppreference.com/w/cpp/named_req/BidirectionalIterator):
The iterator that can be moved can be moved in both directions (i.e. The iterator that can be moved can be moved in both directions (i.e.
incremented and decremented). incremented and decremented).
- [OutputIterator](http://en.cppreference.com/w/cpp/concept/OutputIterator): - [OutputIterator](https://en.cppreference.com/w/cpp/named_req/OutputIterator):
It is possible to write to the pointed-to element (only if @a Base is It is possible to write to the pointed-to element (only if @a Base is
@ref iterator). @ref iterator).
@ -41,11 +41,11 @@ class json_reverse_iterator : public std::reverse_iterator<Base>
using reference = typename Base::reference; using reference = typename Base::reference;
/// create reverse iterator from iterator /// create reverse iterator from iterator
json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept explicit json_reverse_iterator(const typename base_iterator::iterator_type& it) noexcept
: base_iterator(it) {} : base_iterator(it) {}
/// create reverse iterator from base class /// create reverse iterator from base class
json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {} explicit json_reverse_iterator(const base_iterator& it) noexcept : base_iterator(it) {}
/// post-increment (it++) /// post-increment (it++)
json_reverse_iterator const operator++(int) json_reverse_iterator const operator++(int)

View file

@ -87,7 +87,7 @@ class primitive_iterator_t
primitive_iterator_t const operator++(int) noexcept primitive_iterator_t const operator++(int) noexcept
{ {
auto result = *this; auto result = *this;
m_it++; ++m_it;
return result; return result;
} }
@ -100,7 +100,7 @@ class primitive_iterator_t
primitive_iterator_t const operator--(int) noexcept primitive_iterator_t const operator--(int) noexcept
{ {
auto result = *this; auto result = *this;
m_it--; --m_it;
return result; return result;
} }

View file

@ -4,13 +4,15 @@
// 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
// exclude unsupported compilers // exclude unsupported compilers
#if defined(__clang__) #if !defined(JSON_SKIP_UNSUPPORTED_COMPILER_CHECK)
#if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400 #if defined(__clang__)
#error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers" #if (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) < 30400
#endif #error "unsupported Clang version - see https://github.com/nlohmann/json#supported-compilers"
#elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER)) #endif
#if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900 #elif defined(__GNUC__) && !(defined(__ICC) || defined(__INTEL_COMPILER))
#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers" #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) < 40900
#error "unsupported GCC version - see https://github.com/nlohmann/json#supported-compilers"
#endif
#endif #endif
#endif #endif
@ -40,10 +42,12 @@
#define JSON_THROW(exception) throw exception #define JSON_THROW(exception) throw exception
#define JSON_TRY try #define JSON_TRY try
#define JSON_CATCH(exception) catch(exception) #define JSON_CATCH(exception) catch(exception)
#define JSON_INTERNAL_CATCH(exception) catch(exception)
#else #else
#define JSON_THROW(exception) std::abort() #define JSON_THROW(exception) std::abort()
#define JSON_TRY if(true) #define JSON_TRY if(true)
#define JSON_CATCH(exception) if(false) #define JSON_CATCH(exception) if(false)
#define JSON_INTERNAL_CATCH(exception) if(false)
#endif #endif
// override exception macros // override exception macros
@ -58,6 +62,11 @@
#if defined(JSON_CATCH_USER) #if defined(JSON_CATCH_USER)
#undef JSON_CATCH #undef JSON_CATCH
#define JSON_CATCH JSON_CATCH_USER #define JSON_CATCH JSON_CATCH_USER
#define JSON_INTERNAL_CATCH JSON_CATCH_USER
#endif
#if defined(JSON_INTERNAL_CATCH_USER)
#undef JSON_INTERNAL_CATCH
#define JSON_INTERNAL_CATCH JSON_INTERNAL_CATCH_USER
#endif #endif
// manual branch prediction // manual branch prediction

View file

@ -9,6 +9,7 @@
#endif #endif
// clean up // clean up
#undef JSON_INTERNAL_CATCH
#undef JSON_CATCH #undef JSON_CATCH
#undef JSON_THROW #undef JSON_THROW
#undef JSON_TRY #undef JSON_TRY

View file

@ -0,0 +1,83 @@
#pragma once
#include <ciso646> // not
#include <cstddef> // size_t
#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type
namespace nlohmann
{
namespace detail
{
// alias templates to reduce boilerplate
template<bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
template<typename T>
using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
// implementation of C++14 index_sequence and affiliates
// source: https://stackoverflow.com/a/32223343
template<std::size_t... Ints>
struct index_sequence
{
using type = index_sequence;
using value_type = std::size_t;
static constexpr std::size_t size() noexcept
{
return sizeof...(Ints);
}
};
template<class Sequence1, class Sequence2>
struct merge_and_renumber;
template<std::size_t... I1, std::size_t... I2>
struct merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>
: index_sequence < I1..., (sizeof...(I1) + I2)... > {};
template<std::size_t N>
struct make_index_sequence
: merge_and_renumber < typename make_index_sequence < N / 2 >::type,
typename make_index_sequence < N - N / 2 >::type > {};
template<> struct make_index_sequence<0> : index_sequence<> {};
template<> struct make_index_sequence<1> : index_sequence<0> {};
template<typename... Ts>
using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
/*
Implementation of two C++17 constructs: conjunction, negation. This is needed
to avoid evaluating all the traits in a condition
For example: not std::is_same<void, T>::value and has_value_type<T>::value
will not compile when T = void (on MSVC at least). Whereas
conjunction<negation<std::is_same<void, T>>, has_value_type<T>>::value will
stop evaluating if negation<...>::value == false
Please note that those constructs must be used with caution, since symbols can
become very long quickly (which can slow down compilation and cause MSVC
internal compiler errors). Only use it when you have to (see example ahead).
*/
template<class...> struct conjunction : std::true_type {};
template<class B1> struct conjunction<B1> : B1 {};
template<class B1, class... Bn>
struct conjunction<B1, Bn...> : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
template<class B> struct negation : std::integral_constant<bool, not B::value> {};
// dispatch utility (taken from ranges-v3)
template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
template<> struct priority_tag<0> {};
// taken from ranges-v3
template<typename T>
struct static_const
{
static constexpr T value{};
};
template<typename T>
constexpr T static_const<T>::value;
}
}

View file

@ -0,0 +1,56 @@
#pragma once
#include <type_traits>
#include <nlohmann/detail/meta/void_t.hpp>
// http://en.cppreference.com/w/cpp/experimental/is_detected
namespace nlohmann
{
namespace detail
{
struct nonesuch
{
nonesuch() = delete;
~nonesuch() = delete;
nonesuch(nonesuch const&) = delete;
void operator=(nonesuch const&) = delete;
};
template <class Default,
class AlwaysVoid,
template <class...> class Op,
class... Args>
struct detector
{
using value_t = std::false_type;
using type = Default;
};
template <class Default, template <class...> class Op, class... Args>
struct detector<Default, void_t<Op<Args...>>, Op, Args...>
{
using value_t = std::true_type;
using type = Op<Args...>;
};
template <template <class...> class Op, class... Args>
using is_detected = typename detector<nonesuch, void, Op, Args...>::value_t;
template <template <class...> class Op, class... Args>
using detected_t = typename detector<nonesuch, void, Op, Args...>::type;
template <class Default, template <class...> class Op, class... Args>
using detected_or = detector<Default, void, Op, Args...>;
template <class Default, template <class...> class Op, class... Args>
using detected_or_t = typename detected_or<Default, Op, Args...>::type;
template <class Expected, template <class...> class Op, class... Args>
using is_detected_exact = std::is_same<Expected, detected_t<Op, Args...>>;
template <class To, template <class...> class Op, class... Args>
using is_detected_convertible =
std::is_convertible<detected_t<Op, Args...>, To>;
}
}

View file

@ -0,0 +1,141 @@
#pragma once
#include <cstdint> // size_t
#include <utility> // declval
#include <nlohmann/detail/meta/detected.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>
namespace nlohmann
{
namespace detail
{
template <typename T>
using null_function_t = decltype(std::declval<T&>().null());
template <typename T>
using boolean_function_t =
decltype(std::declval<T&>().boolean(std::declval<bool>()));
template <typename T, typename Integer>
using number_integer_function_t =
decltype(std::declval<T&>().number_integer(std::declval<Integer>()));
template <typename T, typename Unsigned>
using number_unsigned_function_t =
decltype(std::declval<T &>().number_unsigned(std::declval<Unsigned>()));
template <typename T, typename Float, typename String>
using number_float_function_t = decltype(std::declval<T &>().number_float(
std::declval<Float>(), std::declval<const String &>()));
template <typename T, typename String>
using string_function_t =
decltype(std::declval<T &>().string(std::declval<String &>()));
template <typename T>
using start_object_function_t =
decltype(std::declval<T &>().start_object(std::declval<std::size_t>()));
template <typename T, typename String>
using key_function_t =
decltype(std::declval<T &>().key(std::declval<String &>()));
template <typename T>
using end_object_function_t = decltype(std::declval<T &>().end_object());
template <typename T>
using start_array_function_t =
decltype(std::declval<T &>().start_array(std::declval<std::size_t>()));
template <typename T>
using end_array_function_t = decltype(std::declval<T &>().end_array());
template <typename T, typename Exception>
using parse_error_function_t = decltype(std::declval<T &>().parse_error(
std::declval<std::size_t>(), std::declval<const std::string &>(),
std::declval<const Exception &>()));
template <typename SAX, typename BasicJsonType>
struct is_sax
{
private:
static_assert(is_basic_json<BasicJsonType>::value,
"BasicJsonType must be of type basic_json<...>");
using number_integer_t = typename BasicJsonType::number_integer_t;
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
using number_float_t = typename BasicJsonType::number_float_t;
using string_t = typename BasicJsonType::string_t;
using exception_t = typename BasicJsonType::exception;
public:
static constexpr bool value =
is_detected_exact<bool, null_function_t, SAX>::value &&
is_detected_exact<bool, boolean_function_t, SAX>::value &&
is_detected_exact<bool, number_integer_function_t, SAX,
number_integer_t>::value &&
is_detected_exact<bool, number_unsigned_function_t, SAX,
number_unsigned_t>::value &&
is_detected_exact<bool, number_float_function_t, SAX, number_float_t,
string_t>::value &&
is_detected_exact<bool, string_function_t, SAX, string_t>::value &&
is_detected_exact<bool, start_object_function_t, SAX>::value &&
is_detected_exact<bool, key_function_t, SAX, string_t>::value &&
is_detected_exact<bool, end_object_function_t, SAX>::value &&
is_detected_exact<bool, start_array_function_t, SAX>::value &&
is_detected_exact<bool, end_array_function_t, SAX>::value &&
is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value;
};
template <typename SAX, typename BasicJsonType>
struct is_sax_static_asserts
{
private:
static_assert(is_basic_json<BasicJsonType>::value,
"BasicJsonType must be of type basic_json<...>");
using number_integer_t = typename BasicJsonType::number_integer_t;
using number_unsigned_t = typename BasicJsonType::number_unsigned_t;
using number_float_t = typename BasicJsonType::number_float_t;
using string_t = typename BasicJsonType::string_t;
using exception_t = typename BasicJsonType::exception;
public:
static_assert(is_detected_exact<bool, null_function_t, SAX>::value,
"Missing/invalid function: bool null()");
static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
"Missing/invalid function: bool boolean(bool)");
static_assert(is_detected_exact<bool, boolean_function_t, SAX>::value,
"Missing/invalid function: bool boolean(bool)");
static_assert(
is_detected_exact<bool, number_integer_function_t, SAX,
number_integer_t>::value,
"Missing/invalid function: bool number_integer(number_integer_t)");
static_assert(
is_detected_exact<bool, number_unsigned_function_t, SAX,
number_unsigned_t>::value,
"Missing/invalid function: bool number_unsigned(number_unsigned_t)");
static_assert(is_detected_exact<bool, number_float_function_t, SAX,
number_float_t, string_t>::value,
"Missing/invalid function: bool number_float(number_float_t, const string_t&)");
static_assert(
is_detected_exact<bool, string_function_t, SAX, string_t>::value,
"Missing/invalid function: bool string(string_t&)");
static_assert(is_detected_exact<bool, start_object_function_t, SAX>::value,
"Missing/invalid function: bool start_object(std::size_t)");
static_assert(is_detected_exact<bool, key_function_t, SAX, string_t>::value,
"Missing/invalid function: bool key(string_t&)");
static_assert(is_detected_exact<bool, end_object_function_t, SAX>::value,
"Missing/invalid function: bool end_object()");
static_assert(is_detected_exact<bool, start_array_function_t, SAX>::value,
"Missing/invalid function: bool start_array(std::size_t)");
static_assert(is_detected_exact<bool, end_array_function_t, SAX>::value,
"Missing/invalid function: bool end_array()");
static_assert(
is_detected_exact<bool, parse_error_function_t, SAX, exception_t>::value,
"Missing/invalid function: bool parse_error(std::size_t, const "
"std::string&, const exception&)");
};
}
}

View file

@ -1,12 +1,12 @@
#pragma once #pragma once
#include <ciso646> // not #include <ciso646> // not
#include <cstddef> // size_t
#include <limits> // numeric_limits #include <limits> // numeric_limits
#include <type_traits> // conditional, enable_if, false_type, integral_constant, is_constructible, is_integral, is_same, remove_cv, remove_reference, true_type #include <type_traits> // false_type, is_constructible, is_integral, is_same, true_type
#include <utility> // declval #include <utility> // declval
#include <nlohmann/json_fwd.hpp> #include <nlohmann/json_fwd.hpp>
#include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
namespace nlohmann namespace nlohmann
@ -30,68 +30,6 @@ template<typename> struct is_basic_json : std::false_type {};
NLOHMANN_BASIC_JSON_TPL_DECLARATION NLOHMANN_BASIC_JSON_TPL_DECLARATION
struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {}; struct is_basic_json<NLOHMANN_BASIC_JSON_TPL> : std::true_type {};
// alias templates to reduce boilerplate
template<bool B, typename T = void>
using enable_if_t = typename std::enable_if<B, T>::type;
template<typename T>
using uncvref_t = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
// implementation of C++14 index_sequence and affiliates
// source: https://stackoverflow.com/a/32223343
template<std::size_t... Ints>
struct index_sequence
{
using type = index_sequence;
using value_type = std::size_t;
static constexpr std::size_t size() noexcept
{
return sizeof...(Ints);
}
};
template<class Sequence1, class Sequence2>
struct merge_and_renumber;
template<std::size_t... I1, std::size_t... I2>
struct merge_and_renumber<index_sequence<I1...>, index_sequence<I2...>>
: index_sequence < I1..., (sizeof...(I1) + I2)... > {};
template<std::size_t N>
struct make_index_sequence
: merge_and_renumber < typename make_index_sequence < N / 2 >::type,
typename make_index_sequence < N - N / 2 >::type > {};
template<> struct make_index_sequence<0> : index_sequence<> {};
template<> struct make_index_sequence<1> : index_sequence<0> {};
template<typename... Ts>
using index_sequence_for = make_index_sequence<sizeof...(Ts)>;
/*
Implementation of two C++17 constructs: conjunction, negation. This is needed
to avoid evaluating all the traits in a condition
For example: not std::is_same<void, T>::value and has_value_type<T>::value
will not compile when T = void (on MSVC at least). Whereas
conjunction<negation<std::is_same<void, T>>, has_value_type<T>>::value will
stop evaluating if negation<...>::value == false
Please note that those constructs must be used with caution, since symbols can
become very long quickly (which can slow down compilation and cause MSVC
internal compiler errors). Only use it when you have to (see example ahead).
*/
template<class...> struct conjunction : std::true_type {};
template<class B1> struct conjunction<B1> : B1 {};
template<class B1, class... Bn>
struct conjunction<B1, Bn...> : std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {};
template<class B> struct negation : std::integral_constant<bool, not B::value> {};
// dispatch utility (taken from ranges-v3)
template<unsigned N> struct priority_tag : priority_tag < N - 1 > {};
template<> struct priority_tag<0> {};
//////////////////////// ////////////////////////
// has_/is_ functions // // has_/is_ functions //
//////////////////////// ////////////////////////
@ -120,6 +58,17 @@ struct is_compatible_object_type_impl<true, RealType, CompatibleObjectType>
std::is_constructible<typename RealType::mapped_type, typename CompatibleObjectType::mapped_type>::value; std::is_constructible<typename RealType::mapped_type, typename CompatibleObjectType::mapped_type>::value;
}; };
template<bool B, class RealType, class CompatibleStringType>
struct is_compatible_string_type_impl : std::false_type {};
template<class RealType, class CompatibleStringType>
struct is_compatible_string_type_impl<true, RealType, CompatibleStringType>
{
static constexpr auto value =
std::is_same<typename RealType::value_type, typename CompatibleStringType::value_type>::value and
std::is_constructible<RealType, CompatibleStringType>::value;
};
template<class BasicJsonType, class CompatibleObjectType> template<class BasicJsonType, class CompatibleObjectType>
struct is_compatible_object_type struct is_compatible_object_type
{ {
@ -130,6 +79,15 @@ struct is_compatible_object_type
typename BasicJsonType::object_t, CompatibleObjectType >::value; typename BasicJsonType::object_t, CompatibleObjectType >::value;
}; };
template<class BasicJsonType, class CompatibleStringType>
struct is_compatible_string_type
{
static auto constexpr value = is_compatible_string_type_impl <
conjunction<negation<std::is_same<void, CompatibleStringType>>,
has_value_type<CompatibleStringType>>::value,
typename BasicJsonType::string_t, CompatibleStringType >::value;
};
template<typename BasicJsonType, typename T> template<typename BasicJsonType, typename T>
struct is_basic_json_nested_type struct is_basic_json_nested_type
{ {
@ -244,15 +202,5 @@ struct is_compatible_type
is_compatible_complete_type<BasicJsonType, CompatibleType>> is_compatible_complete_type<BasicJsonType, CompatibleType>>
{ {
}; };
// taken from ranges-v3
template<typename T>
struct static_const
{
static constexpr T value{};
};
template<typename T>
constexpr T static_const<T>::value;
} }
} }

View file

@ -0,0 +1,10 @@
#pragma once
namespace nlohmann
{
namespace detail
{
template <typename...>
using void_t = void;
}
}

View file

@ -149,9 +149,9 @@ class binary_writer
break; break;
} }
case value_t::number_float: // Double-Precision Float case value_t::number_float:
{ {
oa->write_character(static_cast<CharType>(0xFB)); oa->write_character(get_cbor_float_prefix(j.m_value.number_float));
write_number(j.m_value.number_float); write_number(j.m_value.number_float);
break; break;
} }
@ -409,9 +409,9 @@ class binary_writer
break; break;
} }
case value_t::number_float: // float 64 case value_t::number_float:
{ {
oa->write_character(static_cast<CharType>(0xCB)); oa->write_character(get_msgpack_float_prefix(j.m_value.number_float));
write_number(j.m_value.number_float); write_number(j.m_value.number_float);
break; break;
} }
@ -588,7 +588,7 @@ class binary_writer
if (use_type and not j.m_value.array->empty()) if (use_type and not j.m_value.array->empty())
{ {
assert(use_count); assert(use_count);
const char first_prefix = ubjson_prefix(j.front()); const CharType first_prefix = ubjson_prefix(j.front());
const bool same_prefix = std::all_of(j.begin() + 1, j.end(), const bool same_prefix = std::all_of(j.begin() + 1, j.end(),
[this, first_prefix](const BasicJsonType & v) [this, first_prefix](const BasicJsonType & v)
{ {
@ -599,7 +599,7 @@ class binary_writer
{ {
prefix_required = false; prefix_required = false;
oa->write_character(static_cast<CharType>('$')); oa->write_character(static_cast<CharType>('$'));
oa->write_character(static_cast<CharType>(first_prefix)); oa->write_character(first_prefix);
} }
} }
@ -633,7 +633,7 @@ class binary_writer
if (use_type and not j.m_value.object->empty()) if (use_type and not j.m_value.object->empty())
{ {
assert(use_count); assert(use_count);
const char first_prefix = ubjson_prefix(j.front()); const CharType first_prefix = ubjson_prefix(j.front());
const bool same_prefix = std::all_of(j.begin(), j.end(), const bool same_prefix = std::all_of(j.begin(), j.end(),
[this, first_prefix](const BasicJsonType & v) [this, first_prefix](const BasicJsonType & v)
{ {
@ -644,7 +644,7 @@ class binary_writer
{ {
prefix_required = false; prefix_required = false;
oa->write_character(static_cast<CharType>('$')); oa->write_character(static_cast<CharType>('$'));
oa->write_character(static_cast<CharType>(first_prefix)); oa->write_character(first_prefix);
} }
} }
@ -712,7 +712,7 @@ class binary_writer
{ {
if (add_prefix) if (add_prefix)
{ {
oa->write_character(static_cast<CharType>('D')); // float64 oa->write_character(get_ubjson_float_prefix(n));
} }
write_number(n); write_number(n);
} }
@ -833,7 +833,7 @@ class binary_writer
write_number_with_ubjson_prefix. Therefore, we return 'L' for any write_number_with_ubjson_prefix. Therefore, we return 'L' for any
value that does not fit the previous limits. value that does not fit the previous limits.
*/ */
char ubjson_prefix(const BasicJsonType& j) const noexcept CharType ubjson_prefix(const BasicJsonType& j) const noexcept
{ {
switch (j.type()) switch (j.type())
{ {
@ -892,7 +892,7 @@ class binary_writer
} }
case value_t::number_float: case value_t::number_float:
return 'D'; return get_ubjson_float_prefix(j.m_value.number_float);
case value_t::string: case value_t::string:
return 'S'; return 'S';
@ -908,6 +908,36 @@ class binary_writer
} }
} }
static constexpr CharType get_cbor_float_prefix(float)
{
return static_cast<CharType>(0xFA); // Single-Precision Float
}
static constexpr CharType get_cbor_float_prefix(double)
{
return static_cast<CharType>(0xFB); // Double-Precision Float
}
static constexpr CharType get_msgpack_float_prefix(float)
{
return static_cast<CharType>(0xCA); // float 32
}
static constexpr CharType get_msgpack_float_prefix(double)
{
return static_cast<CharType>(0xCB); // float 64
}
static constexpr CharType get_ubjson_float_prefix(float)
{
return 'd'; // float 32
}
static constexpr CharType get_ubjson_float_prefix(double)
{
return 'D'; // float 64
}
private: private:
/// whether we can assume little endianess /// whether we can assume little endianess
const bool is_little_endian = binary_reader<BasicJsonType>::little_endianess(); const bool is_little_endian = binary_reader<BasicJsonType>::little_endianess();

View file

@ -9,17 +9,14 @@
#include <cstddef> // size_t, ptrdiff_t #include <cstddef> // size_t, ptrdiff_t
#include <cstdint> // uint8_t #include <cstdint> // uint8_t
#include <cstdio> // snprintf #include <cstdio> // snprintf
#include <iomanip> // setfill
#include <iterator> // next
#include <limits> // numeric_limits #include <limits> // numeric_limits
#include <string> // string #include <string> // string
#include <sstream> // stringstream
#include <type_traits> // is_same #include <type_traits> // is_same
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/conversions/to_chars.hpp> #include <nlohmann/detail/conversions/to_chars.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta.hpp> #include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/output/output_adapters.hpp> #include <nlohmann/detail/output/output_adapters.hpp>
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
@ -389,9 +386,9 @@ class serializer
case UTF8_REJECT: // decode found invalid UTF-8 byte case UTF8_REJECT: // decode found invalid UTF-8 byte
{ {
std::stringstream ss; std::string sn(3, '\0');
ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast<int>(byte); snprintf(&sn[0], sn.size(), "%.2X", byte);
JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + ss.str())); JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn));
} }
default: // decode found yet incomplete multi-byte code point default: // decode found yet incomplete multi-byte code point
@ -417,9 +414,9 @@ class serializer
else else
{ {
// we finish reading, but do not accept: string was incomplete // we finish reading, but do not accept: string was incomplete
std::stringstream ss; std::string sn(3, '\0');
ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast<int>(static_cast<uint8_t>(s.back())); snprintf(&sn[0], sn.size(), "%.2X", static_cast<uint8_t>(s.back()));
JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + ss.str())); JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn));
} }
} }

View file

@ -1,10 +1,11 @@
/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | JSON for Modern C++ __| | __| | | | JSON for Modern C++
| | |__ | | | | | | version 3.1.2 | | |__ | | | | | | version 3.2.0
|_____|_____|_____|_|___| https://github.com/nlohmann/json |_____|_____|_____|_|___| https://github.com/nlohmann/json
Licensed under the MIT License <http://opensource.org/licenses/MIT>. Licensed under the MIT License <http://opensource.org/licenses/MIT>.
SPDX-License-Identifier: MIT
Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>. Copyright (c) 2013-2018 Niels Lohmann <http://nlohmann.me>.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
@ -30,8 +31,8 @@ SOFTWARE.
#define NLOHMANN_JSON_HPP #define NLOHMANN_JSON_HPP
#define NLOHMANN_JSON_VERSION_MAJOR 3 #define NLOHMANN_JSON_VERSION_MAJOR 3
#define NLOHMANN_JSON_VERSION_MINOR 1 #define NLOHMANN_JSON_VERSION_MINOR 2
#define NLOHMANN_JSON_VERSION_PATCH 2 #define NLOHMANN_JSON_VERSION_PATCH 0
#include <algorithm> // all_of, find, for_each #include <algorithm> // all_of, find, for_each
#include <cassert> // assert #include <cassert> // assert
@ -47,7 +48,8 @@ SOFTWARE.
#include <nlohmann/json_fwd.hpp> #include <nlohmann/json_fwd.hpp>
#include <nlohmann/detail/macro_scope.hpp> #include <nlohmann/detail/macro_scope.hpp>
#include <nlohmann/detail/meta.hpp> #include <nlohmann/detail/meta/cpp_future.hpp>
#include <nlohmann/detail/meta/type_traits.hpp>
#include <nlohmann/detail/exceptions.hpp> #include <nlohmann/detail/exceptions.hpp>
#include <nlohmann/detail/value_t.hpp> #include <nlohmann/detail/value_t.hpp>
#include <nlohmann/detail/conversions/from_json.hpp> #include <nlohmann/detail/conversions/from_json.hpp>
@ -100,42 +102,42 @@ and `from_json()` (@ref adl_serializer by default)
@requirement The class satisfies the following concept requirements: @requirement The class satisfies the following concept requirements:
- Basic - Basic
- [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible): - [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible):
JSON values can be default constructed. The result will be a JSON null JSON values can be default constructed. The result will be a JSON null
value. value.
- [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible): - [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible):
A JSON value can be constructed from an rvalue argument. A JSON value can be constructed from an rvalue argument.
- [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible): - [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible):
A JSON value can be copy-constructed from an lvalue expression. A JSON value can be copy-constructed from an lvalue expression.
- [MoveAssignable](http://en.cppreference.com/w/cpp/concept/MoveAssignable): - [MoveAssignable](https://en.cppreference.com/w/cpp/named_req/MoveAssignable):
A JSON value van be assigned from an rvalue argument. A JSON value van be assigned from an rvalue argument.
- [CopyAssignable](http://en.cppreference.com/w/cpp/concept/CopyAssignable): - [CopyAssignable](https://en.cppreference.com/w/cpp/named_req/CopyAssignable):
A JSON value can be copy-assigned from an lvalue expression. A JSON value can be copy-assigned from an lvalue expression.
- [Destructible](http://en.cppreference.com/w/cpp/concept/Destructible): - [Destructible](https://en.cppreference.com/w/cpp/named_req/Destructible):
JSON values can be destructed. JSON values can be destructed.
- Layout - Layout
- [StandardLayoutType](http://en.cppreference.com/w/cpp/concept/StandardLayoutType): - [StandardLayoutType](https://en.cppreference.com/w/cpp/named_req/StandardLayoutType):
JSON values have JSON values have
[standard layout](http://en.cppreference.com/w/cpp/language/data_members#Standard_layout): [standard layout](https://en.cppreference.com/w/cpp/language/data_members#Standard_layout):
All non-static data members are private and standard layout types, the All non-static data members are private and standard layout types, the
class has no virtual functions or (virtual) base classes. class has no virtual functions or (virtual) base classes.
- Library-wide - Library-wide
- [EqualityComparable](http://en.cppreference.com/w/cpp/concept/EqualityComparable): - [EqualityComparable](https://en.cppreference.com/w/cpp/named_req/EqualityComparable):
JSON values can be compared with `==`, see @ref JSON values can be compared with `==`, see @ref
operator==(const_reference,const_reference). operator==(const_reference,const_reference).
- [LessThanComparable](http://en.cppreference.com/w/cpp/concept/LessThanComparable): - [LessThanComparable](https://en.cppreference.com/w/cpp/named_req/LessThanComparable):
JSON values can be compared with `<`, see @ref JSON values can be compared with `<`, see @ref
operator<(const_reference,const_reference). operator<(const_reference,const_reference).
- [Swappable](http://en.cppreference.com/w/cpp/concept/Swappable): - [Swappable](https://en.cppreference.com/w/cpp/named_req/Swappable):
Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of Any JSON lvalue or rvalue of can be swapped with any lvalue or rvalue of
other compatible types, using unqualified function call @ref swap(). other compatible types, using unqualified function call @ref swap().
- [NullablePointer](http://en.cppreference.com/w/cpp/concept/NullablePointer): - [NullablePointer](https://en.cppreference.com/w/cpp/named_req/NullablePointer):
JSON values can be compared against `std::nullptr_t` objects which are used JSON values can be compared against `std::nullptr_t` objects which are used
to model the `null` value. to model the `null` value.
- Container - Container
- [Container](http://en.cppreference.com/w/cpp/concept/Container): - [Container](https://en.cppreference.com/w/cpp/named_req/Container):
JSON values can be used like STL containers and provide iterator access. JSON values can be used like STL containers and provide iterator access.
- [ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer); - [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer);
JSON values can be used like STL containers and provide reverse iterator JSON values can be used like STL containers and provide reverse iterator
access. access.
@ -169,8 +171,12 @@ class basic_json
friend class ::nlohmann::detail::iter_impl; friend class ::nlohmann::detail::iter_impl;
template<typename BasicJsonType, typename CharType> template<typename BasicJsonType, typename CharType>
friend class ::nlohmann::detail::binary_writer; friend class ::nlohmann::detail::binary_writer;
template<typename BasicJsonType> template<typename BasicJsonType, typename SAX>
friend class ::nlohmann::detail::binary_reader; friend class ::nlohmann::detail::binary_reader;
template<typename BasicJsonType>
friend class ::nlohmann::detail::json_sax_dom_parser;
template<typename BasicJsonType>
friend class ::nlohmann::detail::json_sax_dom_callback_parser;
/// workaround type for MSVC /// workaround type for MSVC
using basic_json_t = NLOHMANN_BASIC_JSON_TPL; using basic_json_t = NLOHMANN_BASIC_JSON_TPL;
@ -198,13 +204,17 @@ class basic_json
public: public:
using value_t = detail::value_t; using value_t = detail::value_t;
/// @copydoc nlohmann::json_pointer /// JSON Pointer, see @ref nlohmann::json_pointer
using json_pointer = ::nlohmann::json_pointer<basic_json>; using json_pointer = ::nlohmann::json_pointer<basic_json>;
template<typename T, typename SFINAE> template<typename T, typename SFINAE>
using json_serializer = JSONSerializer<T, SFINAE>; using json_serializer = JSONSerializer<T, SFINAE>;
/// helper type for initializer lists of basic_json values /// helper type for initializer lists of basic_json values
using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>; using initializer_list_t = std::initializer_list<detail::json_ref<basic_json>>;
using input_format_t = detail::input_format_t;
/// SAX interface type, see @ref nlohmann::json_sax
using json_sax_t = json_sax<basic_json>;
//////////////// ////////////////
// exceptions // // exceptions //
//////////////// ////////////////
@ -937,7 +947,7 @@ class basic_json
object = nullptr; // silence warning, see #821 object = nullptr; // silence warning, see #821
if (JSON_UNLIKELY(t == value_t::null)) if (JSON_UNLIKELY(t == value_t::null))
{ {
JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.1.2")); // LCOV_EXCL_LINE JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.2.0")); // LCOV_EXCL_LINE
} }
break; break;
} }
@ -1105,7 +1115,6 @@ class basic_json
*/ */
using parser_callback_t = typename parser::parser_callback_t; using parser_callback_t = typename parser::parser_callback_t;
////////////////// //////////////////
// constructors // // constructors //
////////////////// //////////////////
@ -1267,7 +1276,7 @@ class basic_json
was provided), strong guarantee holds: if an exception is thrown, there are was provided), strong guarantee holds: if an exception is thrown, there are
no changes to any JSON value. no changes to any JSON value.
@since version 3.1.2 @since version 3.2.0
*/ */
template <typename BasicJsonType, template <typename BasicJsonType,
detail::enable_if_t< detail::enable_if_t<
@ -1587,7 +1596,7 @@ class basic_json
@warning A precondition is enforced with a runtime assertion that will @warning A precondition is enforced with a runtime assertion that will
result in calling `std::abort` if this precondition is not met. result in calling `std::abort` if this precondition is not met.
Assertions can be disabled by defining `NDEBUG` at compile time. Assertions can be disabled by defining `NDEBUG` at compile time.
See http://en.cppreference.com/w/cpp/error/assert for more See https://en.cppreference.com/w/cpp/error/assert for more
information. information.
@throw invalid_iterator.201 if iterators @a first and @a last are not @throw invalid_iterator.201 if iterators @a first and @a last are not
@ -1727,7 +1736,7 @@ class basic_json
changes to any JSON value. changes to any JSON value.
@requirement This function helps `basic_json` satisfying the @requirement This function helps `basic_json` satisfying the
[Container](http://en.cppreference.com/w/cpp/concept/Container) [Container](https://en.cppreference.com/w/cpp/named_req/Container)
requirements: requirements:
- The complexity is linear. - The complexity is linear.
- As postcondition, it holds: `other == basic_json(other)`. - As postcondition, it holds: `other == basic_json(other)`.
@ -1812,7 +1821,7 @@ class basic_json
exceptions. exceptions.
@requirement This function helps `basic_json` satisfying the @requirement This function helps `basic_json` satisfying the
[MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible) [MoveConstructible](https://en.cppreference.com/w/cpp/named_req/MoveConstructible)
requirements. requirements.
@liveexample{The code below shows the move constructor explicitly called @liveexample{The code below shows the move constructor explicitly called
@ -1846,7 +1855,7 @@ class basic_json
@complexity Linear. @complexity Linear.
@requirement This function helps `basic_json` satisfying the @requirement This function helps `basic_json` satisfying the
[Container](http://en.cppreference.com/w/cpp/concept/Container) [Container](https://en.cppreference.com/w/cpp/named_req/Container)
requirements: requirements:
- The complexity is linear. - The complexity is linear.
@ -1883,7 +1892,7 @@ class basic_json
@complexity Linear. @complexity Linear.
@requirement This function helps `basic_json` satisfying the @requirement This function helps `basic_json` satisfying the
[Container](http://en.cppreference.com/w/cpp/concept/Container) [Container](https://en.cppreference.com/w/cpp/named_req/Container)
requirements: requirements:
- The complexity is linear. - The complexity is linear.
- All stored elements are destroyed and all memory is freed. - All stored elements are destroyed and all memory is freed.
@ -2500,7 +2509,7 @@ class basic_json
@complexity Depending on the implementation of the called `from_json()` @complexity Depending on the implementation of the called `from_json()`
method. method.
@since version 3.1.2 @since version 3.2.0
*/ */
template<typename BasicJsonType, detail::enable_if_t< template<typename BasicJsonType, detail::enable_if_t<
not std::is_same<BasicJsonType, basic_json>::value and not std::is_same<BasicJsonType, basic_json>::value and
@ -2514,8 +2523,8 @@ class basic_json
@brief get a value (explicit) @brief get a value (explicit)
Explicit type conversion between the JSON value and a compatible value Explicit type conversion between the JSON value and a compatible value
which is [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) which is [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
and [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). and [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
The value is converted by calling the @ref json_serializer<ValueType> The value is converted by calling the @ref json_serializer<ValueType>
`from_json()` method. `from_json()` method.
@ -2575,8 +2584,8 @@ class basic_json
@brief get a value (explicit); special case @brief get a value (explicit); special case
Explicit type conversion between the JSON value and a compatible value Explicit type conversion between the JSON value and a compatible value
which is **not** [CopyConstructible](http://en.cppreference.com/w/cpp/concept/CopyConstructible) which is **not** [CopyConstructible](https://en.cppreference.com/w/cpp/named_req/CopyConstructible)
and **not** [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). and **not** [DefaultConstructible](https://en.cppreference.com/w/cpp/named_req/DefaultConstructible).
The value is converted by calling the @ref json_serializer<ValueType> The value is converted by calling the @ref json_serializer<ValueType>
`from_json()` method. `from_json()` method.
@ -2821,9 +2830,9 @@ class basic_json
not detail::is_basic_json<ValueType>::value not detail::is_basic_json<ValueType>::value
#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
#endif #if defined(JSON_HAS_CPP_17) && defined(_MSC_VER) and _MSC_VER <= 1914
#if defined(JSON_HAS_CPP_17)
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
, int >::type = 0 > , int >::type = 0 >
operator ValueType() const operator ValueType() const
@ -3405,7 +3414,7 @@ class basic_json
@return copy of the element at key @a key or @a default_value if @a key @return copy of the element at key @a key or @a default_value if @a key
is not found is not found
@throw type_error.306 if the JSON value is not an objec; in that case, @throw type_error.306 if the JSON value is not an object; in that case,
using `value()` with a key makes no sense. using `value()` with a key makes no sense.
@complexity Logarithmic in the size of the container. @complexity Logarithmic in the size of the container.
@ -3429,7 +3438,7 @@ class basic_json
{ {
return ptr.get_checked(this); return ptr.get_checked(this);
} }
JSON_CATCH (out_of_range&) JSON_INTERNAL_CATCH (out_of_range&)
{ {
return default_value; return default_value;
} }
@ -3940,7 +3949,7 @@ class basic_json
@complexity Constant. @complexity Constant.
@requirement This function helps `basic_json` satisfying the @requirement This function helps `basic_json` satisfying the
[Container](http://en.cppreference.com/w/cpp/concept/Container) [Container](https://en.cppreference.com/w/cpp/named_req/Container)
requirements: requirements:
- The complexity is constant. - The complexity is constant.
@ -3979,7 +3988,7 @@ class basic_json
@complexity Constant. @complexity Constant.
@requirement This function helps `basic_json` satisfying the @requirement This function helps `basic_json` satisfying the
[Container](http://en.cppreference.com/w/cpp/concept/Container) [Container](https://en.cppreference.com/w/cpp/named_req/Container)
requirements: requirements:
- The complexity is constant. - The complexity is constant.
- Has the semantics of `const_cast<const basic_json&>(*this).begin()`. - Has the semantics of `const_cast<const basic_json&>(*this).begin()`.
@ -4011,7 +4020,7 @@ class basic_json
@complexity Constant. @complexity Constant.
@requirement This function helps `basic_json` satisfying the @requirement This function helps `basic_json` satisfying the
[Container](http://en.cppreference.com/w/cpp/concept/Container) [Container](https://en.cppreference.com/w/cpp/named_req/Container)
requirements: requirements:
- The complexity is constant. - The complexity is constant.
@ -4050,7 +4059,7 @@ class basic_json
@complexity Constant. @complexity Constant.
@requirement This function helps `basic_json` satisfying the @requirement This function helps `basic_json` satisfying the
[Container](http://en.cppreference.com/w/cpp/concept/Container) [Container](https://en.cppreference.com/w/cpp/named_req/Container)
requirements: requirements:
- The complexity is constant. - The complexity is constant.
- Has the semantics of `const_cast<const basic_json&>(*this).end()`. - Has the semantics of `const_cast<const basic_json&>(*this).end()`.
@ -4080,7 +4089,7 @@ class basic_json
@complexity Constant. @complexity Constant.
@requirement This function helps `basic_json` satisfying the @requirement This function helps `basic_json` satisfying the
[ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)
requirements: requirements:
- The complexity is constant. - The complexity is constant.
- Has the semantics of `reverse_iterator(end())`. - Has the semantics of `reverse_iterator(end())`.
@ -4117,7 +4126,7 @@ class basic_json
@complexity Constant. @complexity Constant.
@requirement This function helps `basic_json` satisfying the @requirement This function helps `basic_json` satisfying the
[ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)
requirements: requirements:
- The complexity is constant. - The complexity is constant.
- Has the semantics of `reverse_iterator(begin())`. - Has the semantics of `reverse_iterator(begin())`.
@ -4154,7 +4163,7 @@ class basic_json
@complexity Constant. @complexity Constant.
@requirement This function helps `basic_json` satisfying the @requirement This function helps `basic_json` satisfying the
[ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)
requirements: requirements:
- The complexity is constant. - The complexity is constant.
- Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`. - Has the semantics of `const_cast<const basic_json&>(*this).rbegin()`.
@ -4183,7 +4192,7 @@ class basic_json
@complexity Constant. @complexity Constant.
@requirement This function helps `basic_json` satisfying the @requirement This function helps `basic_json` satisfying the
[ReversibleContainer](http://en.cppreference.com/w/cpp/concept/ReversibleContainer) [ReversibleContainer](https://en.cppreference.com/w/cpp/named_req/ReversibleContainer)
requirements: requirements:
- The complexity is constant. - The complexity is constant.
- Has the semantics of `const_cast<const basic_json&>(*this).rend()`. - Has the semantics of `const_cast<const basic_json&>(*this).rend()`.
@ -4324,7 +4333,7 @@ class basic_json
@complexity Constant. @complexity Constant.
@since version 3.x.x. @since version 3.1.0.
*/ */
iteration_proxy<iterator> items() noexcept iteration_proxy<iterator> items() noexcept
{ {
@ -4381,7 +4390,7 @@ class basic_json
false in the case of a string. false in the case of a string.
@requirement This function helps `basic_json` satisfying the @requirement This function helps `basic_json` satisfying the
[Container](http://en.cppreference.com/w/cpp/concept/Container) [Container](https://en.cppreference.com/w/cpp/named_req/Container)
requirements: requirements:
- The complexity is constant. - The complexity is constant.
- Has the semantics of `begin() == end()`. - Has the semantics of `begin() == end()`.
@ -4452,7 +4461,7 @@ class basic_json
the case of a string. the case of a string.
@requirement This function helps `basic_json` satisfying the @requirement This function helps `basic_json` satisfying the
[Container](http://en.cppreference.com/w/cpp/concept/Container) [Container](https://en.cppreference.com/w/cpp/named_req/Container)
requirements: requirements:
- The complexity is constant. - The complexity is constant.
- Has the semantics of `std::distance(begin(), end())`. - Has the semantics of `std::distance(begin(), end())`.
@ -4522,7 +4531,7 @@ class basic_json
@exceptionsafety No-throw guarantee: this function never throws exceptions. @exceptionsafety No-throw guarantee: this function never throws exceptions.
@requirement This function helps `basic_json` satisfying the @requirement This function helps `basic_json` satisfying the
[Container](http://en.cppreference.com/w/cpp/concept/Container) [Container](https://en.cppreference.com/w/cpp/named_req/Container)
requirements: requirements:
- The complexity is constant. - The complexity is constant.
- Has the semantics of returning `b.size()` where `b` is the largest - Has the semantics of returning `b.size()` where `b` is the largest
@ -5991,7 +6000,7 @@ class basic_json
@since version 2.0.3 (contiguous containers) @since version 2.0.3 (contiguous containers)
*/ */
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)
{ {
@ -6000,26 +6009,80 @@ class basic_json
return result; return result;
} }
static bool accept(detail::input_adapter&& i)
{
return parser(i).accept(true);
}
/*! /*!
@copydoc basic_json parse(detail::input_adapter, const parser_callback_t) @brief generate SAX events
The SAX event lister must follow the interface of @ref json_sax.
This function reads from a compatible input. Examples are:
- an array of 1-byte values
- strings with character/literal type with size of 1 byte
- input streams
- container with contiguous storage of 1-byte values. Compatible container
types include `std::vector`, `std::string`, `std::array`,
`std::valarray`, and `std::initializer_list`. Furthermore, C-style
arrays can be used with `std::begin()`/`std::end()`. User-defined
containers can be used as long as they implement random-access iterators
and a contiguous storage.
@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.**
@pre The container storage is contiguous. Violating this precondition
yields undefined behavior. **This precondition is enforced with an
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
the function is called with a noncompliant container and with
assertions switched off, the behavior is undefined and will most
likely yield segmentation violation.
@param[in] i input to read from
@param[in,out] sax SAX event listener
@param[in] format the format to parse (JSON, CBOR, MessagePack, or UBJSON)
@param[in] strict whether the input has to be consumed completely
@return return value of the last processed SAX event
@throw parse_error.101 if a parse error occurs; example: `""unexpected end
of input; expected string literal""`
@throw parse_error.102 if to_unicode fails or surrogate error
@throw parse_error.103 if to_unicode fails
@complexity Linear in the length of the input. The parser is a predictive
LL(1) parser. The complexity can be higher if the SAX consumer @a sax has
a super-linear complexity.
@note A UTF-8 byte order mark is silently ignored.
@liveexample{The example below demonstrates the `sax_parse()` function
reading from string and processing the events with a user-defined SAX
event consumer.,sax_parse}
@since version 3.2.0
*/ */
static basic_json parse(detail::input_adapter& i, template <typename SAX>
const parser_callback_t cb = nullptr, static bool sax_parse(detail::input_adapter&& i, SAX* sax,
const bool allow_exceptions = true) input_format_t format = input_format_t::json,
const bool strict = true)
{ {
basic_json result; assert(sax);
parser(i, cb, allow_exceptions).parse(true, result); switch (format)
return result; {
} case input_format_t::json:
return parser(std::move(i)).sax_parse(sax, strict);
static bool accept(detail::input_adapter i) default:
{ return detail::binary_reader<basic_json, SAX>(std::move(i)).sax_parse(format, sax, strict);
return parser(i).accept(true); }
}
static bool accept(detail::input_adapter& i)
{
return parser(i).accept(true);
} }
/*! /*!
@ -6091,6 +6154,15 @@ class basic_json
return parser(detail::input_adapter(first, last)).accept(true); return parser(detail::input_adapter(first, last)).accept(true);
} }
template<class IteratorType, class SAX, typename std::enable_if<
std::is_base_of<
std::random_access_iterator_tag,
typename std::iterator_traits<IteratorType>::iterator_category>::value, int>::type = 0>
static bool sax_parse(IteratorType first, IteratorType last, SAX* sax)
{
return parser(detail::input_adapter(first, last)).sax_parse(sax);
}
/*! /*!
@brief deserialize from stream @brief deserialize from stream
@deprecated This stream operator is deprecated and will be removed in @deprecated This stream operator is deprecated and will be removed in
@ -6587,6 +6659,9 @@ class basic_json
@param[in] i an input in CBOR format convertible to an input adapter @param[in] i an input in CBOR format convertible to an input adapter
@param[in] strict whether to expect the input to be consumed until EOF @param[in] strict whether to expect the input to be consumed until EOF
(true by default) (true by default)
@param[in] allow_exceptions whether to throw exceptions in case of a
parse error (optional, true by default)
@return deserialized JSON value @return deserialized JSON value
@throw parse_error.110 if the given input ends prematurely or the end of @throw parse_error.110 if the given input ends prematurely or the end of
@ -6602,29 +6677,39 @@ class basic_json
@sa http://cbor.io @sa http://cbor.io
@sa @ref to_cbor(const basic_json&) for the analogous serialization @sa @ref to_cbor(const basic_json&) for the analogous serialization
@sa @ref from_msgpack(detail::input_adapter, const bool) for the @sa @ref from_msgpack(detail::input_adapter, const bool, const bool) for the
related MessagePack format related MessagePack format
@sa @ref from_ubjson(detail::input_adapter, const bool) for the related @sa @ref from_ubjson(detail::input_adapter, const bool, const bool) for the
UBJSON format related UBJSON format
@since version 2.0.9; parameter @a start_index since 2.1.1; changed to @since version 2.0.9; parameter @a start_index since 2.1.1; changed to
consume input adapters, removed start_index parameter, and added consume input adapters, removed start_index parameter, and added
@a strict parameter since 3.0.0 @a strict parameter since 3.0.0; added @allow_exceptions parameter
since 3.2.0
*/ */
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)
{ {
return binary_reader(i).parse_cbor(strict); basic_json result;
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::cbor, &sdp, strict);
return res ? result : basic_json(value_t::discarded);
} }
/*! /*!
@copydoc from_cbor(detail::input_adapter, const bool) @copydoc from_cbor(detail::input_adapter, const bool, const bool)
*/ */
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>
static basic_json from_cbor(A1 && a1, A2 && a2, const bool strict = true) static basic_json from_cbor(A1 && a1, A2 && a2,
const bool strict = true,
const bool allow_exceptions = true)
{ {
return binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).parse_cbor(strict); basic_json result;
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::cbor, &sdp, strict);
return res ? result : basic_json(value_t::discarded);
} }
/*! /*!
@ -6677,6 +6762,10 @@ class basic_json
adapter adapter
@param[in] strict whether to expect the input to be consumed until EOF @param[in] strict whether to expect the input to be consumed until EOF
(true by default) (true by default)
@param[in] allow_exceptions whether to throw exceptions in case of a
parse error (optional, true by default)
@return deserialized JSON value
@throw parse_error.110 if the given input ends prematurely or the end of @throw parse_error.110 if the given input ends prematurely or the end of
file was not reached when @a strict was set to true file was not reached when @a strict was set to true
@ -6691,29 +6780,39 @@ class basic_json
@sa http://msgpack.org @sa http://msgpack.org
@sa @ref to_msgpack(const basic_json&) for the analogous serialization @sa @ref to_msgpack(const basic_json&) for the analogous serialization
@sa @ref from_cbor(detail::input_adapter, const bool) for the related CBOR @sa @ref from_cbor(detail::input_adapter, const bool, const bool) for the
format related CBOR format
@sa @ref from_ubjson(detail::input_adapter, const bool) for the related @sa @ref from_ubjson(detail::input_adapter, const bool, const bool) for
UBJSON format the related UBJSON format
@since version 2.0.9; parameter @a start_index since 2.1.1; changed to @since version 2.0.9; parameter @a start_index since 2.1.1; changed to
consume input adapters, removed start_index parameter, and added consume input adapters, removed start_index parameter, and added
@a strict parameter since 3.0.0 @a strict parameter since 3.0.0; added @allow_exceptions parameter
since 3.2.0
*/ */
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)
{ {
return binary_reader(i).parse_msgpack(strict); basic_json result;
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::msgpack, &sdp, strict);
return res ? result : basic_json(value_t::discarded);
} }
/*! /*!
@copydoc from_msgpack(detail::input_adapter, const bool) @copydoc from_msgpack(detail::input_adapter, const bool, const bool)
*/ */
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>
static basic_json from_msgpack(A1 && a1, A2 && a2, const bool strict = true) static basic_json from_msgpack(A1 && a1, A2 && a2,
const bool strict = true,
const bool allow_exceptions = true)
{ {
return binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).parse_msgpack(strict); basic_json result;
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::msgpack, &sdp, strict);
return res ? result : basic_json(value_t::discarded);
} }
/*! /*!
@ -6748,6 +6847,10 @@ class basic_json
@param[in] i an input in UBJSON format convertible to an input adapter @param[in] i an input in UBJSON format convertible to an input adapter
@param[in] strict whether to expect the input to be consumed until EOF @param[in] strict whether to expect the input to be consumed until EOF
(true by default) (true by default)
@param[in] allow_exceptions whether to throw exceptions in case of a
parse error (optional, true by default)
@return deserialized JSON value
@throw parse_error.110 if the given input ends prematurely or the end of @throw parse_error.110 if the given input ends prematurely or the end of
file was not reached when @a strict was set to true file was not reached when @a strict was set to true
@ -6762,24 +6865,36 @@ class basic_json
@sa http://ubjson.org @sa http://ubjson.org
@sa @ref to_ubjson(const basic_json&, const bool, const bool) for the @sa @ref to_ubjson(const basic_json&, const bool, const bool) for the
analogous serialization analogous serialization
@sa @ref from_cbor(detail::input_adapter, const bool) for the related CBOR @sa @ref from_cbor(detail::input_adapter, const bool, const bool) for the
format related CBOR format
@sa @ref from_msgpack(detail::input_adapter, const bool) for the related @sa @ref from_msgpack(detail::input_adapter, const bool, const bool) for
MessagePack format the related MessagePack format
@since version 3.1.0 @since version 3.1.0; added @allow_exceptions parameter since 3.2.0
*/ */
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)
{ {
return binary_reader(i).parse_ubjson(strict); basic_json result;
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
const bool res = binary_reader(detail::input_adapter(i)).sax_parse(input_format_t::ubjson, &sdp, strict);
return res ? result : basic_json(value_t::discarded);
} }
/*!
@copydoc from_ubjson(detail::input_adapter, const bool, const bool)
*/
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>
static basic_json from_ubjson(A1 && a1, A2 && a2, const bool strict = true) static basic_json from_ubjson(A1 && a1, A2 && a2,
const bool strict = true,
const bool allow_exceptions = true)
{ {
return binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).parse_ubjson(strict); basic_json result;
detail::json_sax_dom_parser<basic_json> sdp(result, allow_exceptions);
const bool res = binary_reader(detail::input_adapter(std::forward<A1>(a1), std::forward<A2>(a2))).sax_parse(input_format_t::ubjson, &sdp, strict);
return res ? result : basic_json(value_t::discarded);
} }
/// @} /// @}
@ -7156,11 +7271,13 @@ class basic_json
break; break;
} }
// LCOV_EXCL_START
default: default:
{ {
// if there exists a parent it cannot be primitive // if there exists a parent it cannot be primitive
assert(false); // LCOV_EXCL_LINE assert(false);
} }
// LCOV_EXCL_STOP
} }
} }
}; };
@ -7302,7 +7419,7 @@ class basic_json
// the "path" location must exist - use at() // the "path" location must exist - use at()
success = (result.at(ptr) == get_value("test", "value", false)); success = (result.at(ptr) == get_value("test", "value", false));
} }
JSON_CATCH (out_of_range&) JSON_INTERNAL_CATCH (out_of_range&)
{ {
// ignore out of range errors: success remains false // ignore out of range errors: success remains false
} }
@ -7580,11 +7697,10 @@ namespace std
@since version 1.0.0 @since version 1.0.0
*/ */
template<> template<>
inline void swap(nlohmann::json& j1, inline void swap<nlohmann::json>(nlohmann::json& j1, nlohmann::json& j2) noexcept(
nlohmann::json& j2) noexcept( is_nothrow_move_constructible<nlohmann::json>::value and
is_nothrow_move_constructible<nlohmann::json>::value and is_nothrow_move_assignable<nlohmann::json>::value
is_nothrow_move_assignable<nlohmann::json>::value )
)
{ {
j1.swap(j2); j1.swap(j2);
} }

View file

@ -18,10 +18,10 @@ namespace nlohmann
@brief default JSONSerializer template argument @brief default JSONSerializer template argument
This serializer ignores the template arguments and uses ADL This serializer ignores the template arguments and uses ADL
([argument-dependent lookup](http://en.cppreference.com/w/cpp/language/adl)) ([argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl))
for serialization. for serialization.
*/ */
template<typename = void, typename = void> template<typename T = void, typename SFINAE = void>
struct adl_serializer; struct adl_serializer;
template<template<typename U, typename V, typename... Args> class ObjectType = template<template<typename U, typename V, typename... Args> class ObjectType =

View file

@ -1,7 +1,9 @@
project('nlohmann_json', 'cpp') project('nlohmann_json', 'cpp')
nlohmann_json_inc = include_directories('single_include/nlohmann')
nlohmann_json_dep = declare_dependency( nlohmann_json_dep = declare_dependency(
include_directories : nlohmann_json_inc include_directories: include_directories('single_include')
)
nlohmann_json_multiple_headers = declare_dependency(
include_directories: include_directories('include')
) )

File diff suppressed because it is too large Load diff

View file

@ -6,15 +6,14 @@ option(JSON_Coverage "Build test suite with coverage information" OFF)
if(JSON_Sanitizer) if(JSON_Sanitizer)
message(STATUS "Building test suite with Clang sanitizer") message(STATUS "Building test suite with Clang sanitizer")
if(NOT MSVC) if(NOT MSVC)
set(CMAKE_CXX_FLAGS "-std=c++11 -g -O2 -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer") set(CMAKE_CXX_FLAGS "-g -O2 -fsanitize=address -fsanitize=undefined -fno-omit-frame-pointer")
endif() endif()
endif() endif()
if(JSON_Valgrind) if(JSON_Valgrind)
find_program(CMAKE_MEMORYCHECK_COMMAND valgrind) find_program(CMAKE_MEMORYCHECK_COMMAND valgrind)
message(STATUS "Executing test suite with Valgrind (${CMAKE_MEMORYCHECK_COMMAND})") message(STATUS "Executing test suite with Valgrind (${CMAKE_MEMORYCHECK_COMMAND})")
set(MEMORYCHECK_COMMAND_OPTIONS "--error-exitcode=1 --leak-check=full") set(memcheck_command "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS} --error-exitcode=1 --leak-check=full")
set(memcheck_command "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS}")
separate_arguments(memcheck_command) separate_arguments(memcheck_command)
endif() endif()
@ -62,11 +61,10 @@ add_library(catch_main OBJECT
"src/unit.cpp" "src/unit.cpp"
) )
set_target_properties(catch_main PROPERTIES set_target_properties(catch_main PROPERTIES
CXX_STANDARD 11
CXX_STANDARD_REQUIRED ON
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(catch_main PUBLIC cxx_std_11)
target_include_directories(catch_main PRIVATE "thirdparty/catch") target_include_directories(catch_main PRIVATE "thirdparty/catch")
# https://stackoverflow.com/questions/2368811/how-to-set-warning-level-in-cmake # https://stackoverflow.com/questions/2368811/how-to-set-warning-level-in-cmake
@ -83,6 +81,9 @@ if(MSVC)
# Disable warning C4566: character represented by universal-character-name '\uFF01' cannot be represented in the current code page (1252) # Disable warning C4566: character represented by universal-character-name '\uFF01' cannot be represented in the current code page (1252)
# Disable warning C4996: 'nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::operator <<': was declared deprecated # Disable warning C4996: 'nlohmann::basic_json<std::map,std::vector,std::string,bool,int64_t,uint64_t,double,std::allocator,nlohmann::adl_serializer>::operator <<': was declared deprecated
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4389 /wd4309 /wd4566 /wd4996") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4389 /wd4309 /wd4566 /wd4996")
# https://github.com/nlohmann/json/issues/1114
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj")
endif() endif()
############################################################################# #############################################################################
@ -96,13 +97,12 @@ foreach(file ${files})
add_executable(${testcase} $<TARGET_OBJECTS:catch_main> ${file}) add_executable(${testcase} $<TARGET_OBJECTS:catch_main> ${file})
set_target_properties(${testcase} PROPERTIES set_target_properties(${testcase} PROPERTIES
CXX_STANDARD 11
CXX_STANDARD_REQUIRED ON
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_definitions(${testcase} PRIVATE CATCH_CONFIG_FAST_COMPILE) target_compile_definitions(${testcase} PRIVATE CATCH_CONFIG_FAST_COMPILE)
target_compile_features(${testcase} PRIVATE cxx_std_11)
target_include_directories(${testcase} PRIVATE "thirdparty/catch") target_include_directories(${testcase} PRIVATE "thirdparty/catch")
target_include_directories(${testcase} PRIVATE "thirdparty/fifo_map") target_include_directories(${testcase} PRIVATE "thirdparty/fifo_map")
target_include_directories(${testcase} PRIVATE ${NLOHMANN_JSON_INCLUDE_BUILD_DIR}) target_include_directories(${testcase} PRIVATE ${NLOHMANN_JSON_INCLUDE_BUILD_DIR})

View file

@ -42,7 +42,8 @@ SOURCES = src/unit.cpp \
src/unit-serialization.cpp \ src/unit-serialization.cpp \
src/unit-testsuites.cpp \ src/unit-testsuites.cpp \
src/unit-ubjson.cpp \ src/unit-ubjson.cpp \
src/unit-unicode.cpp src/unit-unicode.cpp \
src/unit-wstring.cpp
OBJECTS = $(SOURCES:.cpp=.o) OBJECTS = $(SOURCES:.cpp=.o)

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 Nicolas Seriot
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,55 @@
# JSON Parsing Test Suite
A comprehensive test suite for RFC 8259 compliant JSON parsers
This repository was created as an appendix to the article [Parsing JSON is a Minefield 💣](http://seriot.ch/parsing_json.php).
**/parsers/**
This directory contains several parsers and tiny wrappers to turn the parsers into JSON validators, by returning a specific value.
- `0` the parser did accept the content
- `1` the parser did reject the content
- `>1` the process did crash
- `timeout` happens after 5 seconds
**/test\_parsing/**
The name of these files tell if their contents should be accepted or rejected.
- `y_` content must be accepted by parsers
- `n_` content must be rejected by parsers
- `i_` parsers are free to accept or reject content
**/test\_transform/**
These files contain weird structures and characters that parsers may understand differently, eg:
- huge numbers
- dictionaries with similar keys
- NULL characters
- escaped invalid strings
These files were used to produce `results/transform.html`.
**/run_tests.py**
Run all parsers with all files:
$ python3 run_tests.py
Run all parsers with a specific file:
$ python3 run_tests.py file.json
Run specific parsers with all files:
$ echo '["Python 2.7.10", "Python 3.5.2"]' > python_only.json
$ python3 run_tests.py --filter=python_only.json
The script writes logs in `results/logs.txt`.
The script then reads `logs.txt` and generates `results/parsing.html`.
**/results/**
<img src="results/pruned_results.png" alt="JSON Parsing Tests" />

View file

@ -0,0 +1 @@
[123.456e-789]

View file

@ -0,0 +1 @@
[0.4e00669999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999969999999006]

View file

@ -0,0 +1 @@
[-1e+9999]

View file

@ -0,0 +1 @@
[1.5e+9999]

View file

@ -0,0 +1 @@
[-123123e100000]

View file

@ -0,0 +1 @@
[123123e100000]

Some files were not shown because too many files have changed in this diff Show more