From 91e003285312167ad8365f387438ea371b465a7e Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Tue, 29 Aug 2017 23:46:26 +0200 Subject: [PATCH 1/5] :memo: improved documentation --- doc/Doxyfile | 25 +- doc/examples/basic_json__CompatibleType.cpp | 6 + doc/examples/basic_json__CompatibleType.link | 2 +- .../basic_json__CompatibleType.output | 1 + doc/examples/dump.cpp | 28 +- doc/examples/dump.link | 2 +- doc/examples/dump.output | 5 + doc/examples/exception.cpp | 20 ++ doc/examples/exception.link | 1 + doc/examples/exception.output | 2 + doc/examples/invalid_iterator.cpp | 21 ++ doc/examples/invalid_iterator.link | 1 + doc/examples/invalid_iterator.output | 2 + doc/examples/operator__value_t.cpp | 5 +- doc/examples/operator__value_t.link | 2 +- doc/examples/operator__value_t.output | 1 + doc/examples/other_error.cpp | 29 ++ doc/examples/other_error.link | 1 + doc/examples/other_error.output | 2 + doc/examples/out_of_range.cpp | 20 ++ doc/examples/out_of_range.link | 1 + doc/examples/out_of_range.output | 2 + doc/examples/parse_error.cpp | 20 ++ doc/examples/parse_error.link | 1 + doc/examples/parse_error.output | 3 + doc/examples/type.cpp | 4 +- doc/examples/type.link | 2 +- doc/examples/type.output | 1 + doc/examples/type_error.cpp | 20 ++ doc/examples/type_error.link | 1 + doc/examples/type_error.output | 2 + doc/examples/type_name.cpp | 18 +- doc/examples/type_name.link | 2 +- doc/examples/type_name.output | 15 +- src/json.hpp | 305 +++++++++++++++--- test/src/unit-concepts.cpp | 1 + test/src/unit-constructor1.cpp | 31 +- test/src/unit-modifiers.cpp | 20 ++ test/src/unit-regression.cpp | 8 +- 39 files changed, 532 insertions(+), 101 deletions(-) create mode 100644 doc/examples/exception.cpp create mode 100644 doc/examples/exception.link create mode 100644 doc/examples/exception.output create mode 100644 doc/examples/invalid_iterator.cpp create mode 100644 doc/examples/invalid_iterator.link create mode 100644 doc/examples/invalid_iterator.output create mode 100644 doc/examples/other_error.cpp create mode 100644 doc/examples/other_error.link create mode 100644 doc/examples/other_error.output create mode 100644 doc/examples/out_of_range.cpp create mode 100644 doc/examples/out_of_range.link create mode 100644 doc/examples/out_of_range.output create mode 100644 doc/examples/parse_error.cpp create mode 100644 doc/examples/parse_error.link create mode 100644 doc/examples/parse_error.output create mode 100644 doc/examples/type_error.cpp create mode 100644 doc/examples/type_error.link create mode 100644 doc/examples/type_error.output diff --git a/doc/Doxyfile b/doc/Doxyfile index 27806a69..e61f3024 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.8.9.1 +# Doxyfile 1.8.14 #--------------------------------------------------------------------------- # Project related configuration options @@ -6,7 +6,7 @@ DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = "JSON for Modern C++" PROJECT_NUMBER = 2.1.1 -PROJECT_BRIEF = +PROJECT_BRIEF = PROJECT_LOGO = OUTPUT_DIRECTORY = . CREATE_SUBDIRS = NO @@ -27,10 +27,10 @@ MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = YES TAB_SIZE = 4 -ALIASES = "complexity=@par Complexity\n" -ALIASES += liveexample{2}="@par Example\n \1 \n @includelineno \2.cpp \n Output (play with this example @htmlinclude \2.link):\n @verbinclude \2.output \n The example code above can be translated with @verbatim g++ -std=c++11 -Isrc doc/examples/\2.cpp -o \2 @endverbatim" -ALIASES += requirement="@par Requirements\n" -ALIASES += exceptionsafety="@par Exception safety\n" +ALIASES = "complexity=@par Complexity\n" \ + "liveexample{2}=@par Example\n \1 \n @includelineno \2.cpp \n Output (play with this example @htmlinclude \2.link):\n @verbinclude \2.output \n The example code above can be translated with @verbatim g++ -std=c++11 -Isrc doc/examples/\2.cpp -o \2 @endverbatim" \ + "requirement=@par Requirements\n" \ + "exceptionsafety=@par Exception safety\n" TCL_SUBST = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO @@ -38,12 +38,14 @@ OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES +TOC_INCLUDE_HEADINGS = 0 AUTOLINK_SUPPORT = NO BUILTIN_STL_SUPPORT = YES CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO +GROUP_NESTED_COMPOUNDS = NO SUBGROUPING = YES INLINE_GROUPED_CLASSES = NO INLINE_SIMPLE_STRUCTS = NO @@ -97,12 +99,14 @@ WARNINGS = YES WARN_IF_UNDOCUMENTED = YES WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = YES +WARN_AS_ERROR = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- -INPUT = ../src/json.hpp index.md +INPUT = ../src/json.hpp \ + index.md INPUT_ENCODING = UTF-8 FILE_PATTERNS = RECURSIVE = NO @@ -131,6 +135,8 @@ REFERENCES_LINK_SOURCE = NO SOURCE_TOOLTIPS = YES USE_HTAGS = NO VERBATIM_HEADERS = NO +CLANG_ASSISTED_PARSING = YES +CLANG_OPTIONS = -std=c++11 #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- @@ -152,13 +158,14 @@ HTML_COLORSTYLE_HUE = 220 HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = YES +HTML_DYNAMIC_MENUS = YES HTML_DYNAMIC_SECTIONS = YES HTML_INDEX_NUM_ENTRIES = 100 GENERATE_DOCSET = YES DOCSET_FEEDNAME = "Doxygen generated docs" DOCSET_BUNDLE_ID = me.nlohmann.json DOCSET_PUBLISHER_ID = me.nlohmann -DOCSET_PUBLISHER_NAME = Niels Lohmann +DOCSET_PUBLISHER_NAME = NielsLohmann GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = @@ -215,6 +222,7 @@ LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain +LATEX_TIMESTAMP = NO #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- @@ -308,6 +316,7 @@ DOTFILE_DIRS = MSCFILE_DIRS = DIAFILE_DIRS = PLANTUML_JAR_PATH = +PLANTUML_CFG_FILE = PLANTUML_INCLUDE_PATH = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 diff --git a/doc/examples/basic_json__CompatibleType.cpp b/doc/examples/basic_json__CompatibleType.cpp index 1066795b..69493559 100644 --- a/doc/examples/basic_json__CompatibleType.cpp +++ b/doc/examples/basic_json__CompatibleType.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include "json.hpp" using json = nlohmann::json; @@ -67,6 +68,10 @@ int main() std::vector c_vector {1, 2, 3, 4}; json j_vec(c_vector); + // create an array from std::valarray + std::valarray c_valarray {10, 9, 8, 7}; + json j_valarray(c_valarray); + // create an array from std::deque std::deque c_deque {1.2, 2.3, 3.4, 5.6}; json j_deque(c_deque); @@ -102,6 +107,7 @@ int main() // serialize the JSON arrays std::cout << j_array_t << '\n'; std::cout << j_vec << '\n'; + std::cout << j_valarray << '\n'; std::cout << j_deque << '\n'; std::cout << j_list << '\n'; std::cout << j_flist << '\n'; diff --git a/doc/examples/basic_json__CompatibleType.link b/doc/examples/basic_json__CompatibleType.link index af1157b7..a6e786ab 100644 --- a/doc/examples/basic_json__CompatibleType.link +++ b/doc/examples/basic_json__CompatibleType.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/basic_json__CompatibleType.output b/doc/examples/basic_json__CompatibleType.output index d69ff44f..cd5923b8 100644 --- a/doc/examples/basic_json__CompatibleType.output +++ b/doc/examples/basic_json__CompatibleType.output @@ -6,6 +6,7 @@ ["one","two",3,4.5,false] [1,2,3,4] +[10,9,8,7] [1.2,2.3,3.4,5.6] [true,true,false,true] [12345678909876,23456789098765,34567890987654,45678909876543] diff --git a/doc/examples/dump.cpp b/doc/examples/dump.cpp index 4ffd2aa4..4440f91c 100644 --- a/doc/examples/dump.cpp +++ b/doc/examples/dump.cpp @@ -8,16 +8,24 @@ int main() // create JSON values json j_object = {{"one", 1}, {"two", 2}}; json j_array = {1, 2, 4, 8, 16}; + json j_string = "Hellö 😀!"; // call dump() - std::cout << j_object.dump() << "\n\n"; - std::cout << j_object.dump(-1) << "\n\n"; - std::cout << j_object.dump(0) << "\n\n"; - std::cout << j_object.dump(4) << "\n\n"; - std::cout << j_object.dump(1, '\t') << "\n\n"; - std::cout << j_array.dump() << "\n\n"; - std::cout << j_array.dump(-1) << "\n\n"; - std::cout << j_array.dump(0) << "\n\n"; - std::cout << j_array.dump(4) << "\n\n"; - std::cout << j_array.dump(1, '\t') << "\n\n"; + std::cout << "objects:" << '\n' + << j_object.dump() << "\n\n" + << j_object.dump(-1) << "\n\n" + << j_object.dump(0) << "\n\n" + << j_object.dump(4) << "\n\n" + << j_object.dump(1, '\t') << "\n\n"; + + std::cout << "arrays:" << '\n' + << j_array.dump() << "\n\n" + << j_array.dump(-1) << "\n\n" + << j_array.dump(0) << "\n\n" + << j_array.dump(4) << "\n\n" + << j_array.dump(1, '\t') << "\n\n"; + + std::cout << "strings:" << '\n' + << j_string.dump() << '\n' + << j_string.dump(-1, ' ', true) << '\n'; } diff --git a/doc/examples/dump.link b/doc/examples/dump.link index 2e3fee96..c02a4126 100644 --- a/doc/examples/dump.link +++ b/doc/examples/dump.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/dump.output b/doc/examples/dump.output index bc38c5ea..8c6998bb 100644 --- a/doc/examples/dump.output +++ b/doc/examples/dump.output @@ -1,3 +1,4 @@ +objects: {"one":1,"two":2} {"one":1,"two":2} @@ -17,6 +18,7 @@ "two": 2 } +arrays: [1,2,4,8,16] [1,2,4,8,16] @@ -45,3 +47,6 @@ 16 ] +strings: +"Hellö 😀!" +"Hell\u00f6 \ud83d\ude00!" diff --git a/doc/examples/exception.cpp b/doc/examples/exception.cpp new file mode 100644 index 00000000..13926b25 --- /dev/null +++ b/doc/examples/exception.cpp @@ -0,0 +1,20 @@ +#include +#include "json.hpp" + +using json = nlohmann::json; + +int main() +{ + try + { + // calling at() for a non-existing key + json j = {{"foo", "bar"}}; + json k = j.at("non-existing"); + } + catch (json::exception& e) + { + // output exception information + std::cout << "message: " << e.what() << '\n' + << "exception id: " << e.id << std::endl; + } +} diff --git a/doc/examples/exception.link b/doc/examples/exception.link new file mode 100644 index 00000000..7043792b --- /dev/null +++ b/doc/examples/exception.link @@ -0,0 +1 @@ +online \ No newline at end of file diff --git a/doc/examples/exception.output b/doc/examples/exception.output new file mode 100644 index 00000000..fa20df6e --- /dev/null +++ b/doc/examples/exception.output @@ -0,0 +1,2 @@ +message: [json.exception.out_of_range.403] key 'non-existing' not found +exception id: 403 diff --git a/doc/examples/invalid_iterator.cpp b/doc/examples/invalid_iterator.cpp new file mode 100644 index 00000000..2d613597 --- /dev/null +++ b/doc/examples/invalid_iterator.cpp @@ -0,0 +1,21 @@ +#include +#include "json.hpp" + +using json = nlohmann::json; + +int main() +{ + try + { + // calling iterator::key() on non-object iterator + json j = "string"; + json::iterator it = j.begin(); + auto k = it.key(); + } + catch (json::invalid_iterator& e) + { + // output exception information + std::cout << "message: " << e.what() << '\n' + << "exception id: " << e.id << std::endl; + } +} diff --git a/doc/examples/invalid_iterator.link b/doc/examples/invalid_iterator.link new file mode 100644 index 00000000..0bb86950 --- /dev/null +++ b/doc/examples/invalid_iterator.link @@ -0,0 +1 @@ +online \ No newline at end of file diff --git a/doc/examples/invalid_iterator.output b/doc/examples/invalid_iterator.output new file mode 100644 index 00000000..8668c16d --- /dev/null +++ b/doc/examples/invalid_iterator.output @@ -0,0 +1,2 @@ +message: [json.exception.invalid_iterator.207] cannot use key() for non-object iterators +exception id: 207 diff --git a/doc/examples/operator__value_t.cpp b/doc/examples/operator__value_t.cpp index 246243c1..087910a4 100644 --- a/doc/examples/operator__value_t.cpp +++ b/doc/examples/operator__value_t.cpp @@ -8,7 +8,8 @@ int main() // create JSON values json j_null; json j_boolean = true; - json j_number_integer = 17; + json j_number_integer = -17; + json j_number_unsigned = 42u; json j_number_float = 23.42; json j_object = {{"one", 1}, {"two", 2}}; json j_array = {1, 2, 4, 8, 16}; @@ -18,6 +19,7 @@ int main() json::value_t t_null = j_null; json::value_t t_boolean = j_boolean; json::value_t t_number_integer = j_number_integer; + json::value_t t_number_unsigned = j_number_unsigned; json::value_t t_number_float = j_number_float; json::value_t t_object = j_object; json::value_t t_array = j_array; @@ -28,6 +30,7 @@ int main() std::cout << (t_null == json::value_t::null) << '\n'; std::cout << (t_boolean == json::value_t::boolean) << '\n'; std::cout << (t_number_integer == json::value_t::number_integer) << '\n'; + std::cout << (t_number_unsigned == json::value_t::number_unsigned) << '\n'; std::cout << (t_number_float == json::value_t::number_float) << '\n'; std::cout << (t_object == json::value_t::object) << '\n'; std::cout << (t_array == json::value_t::array) << '\n'; diff --git a/doc/examples/operator__value_t.link b/doc/examples/operator__value_t.link index 94d67cfd..7c22cd4a 100644 --- a/doc/examples/operator__value_t.link +++ b/doc/examples/operator__value_t.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/operator__value_t.output b/doc/examples/operator__value_t.output index 814ccfee..310e632a 100644 --- a/doc/examples/operator__value_t.output +++ b/doc/examples/operator__value_t.output @@ -5,3 +5,4 @@ true true true true +true diff --git a/doc/examples/other_error.cpp b/doc/examples/other_error.cpp new file mode 100644 index 00000000..16b9657a --- /dev/null +++ b/doc/examples/other_error.cpp @@ -0,0 +1,29 @@ +#include +#include "json.hpp" + +using json = nlohmann::json; + +int main() +{ + try + { + // executing a failing JSON Patch operation + json value = R"({ + "best_biscuit": { + "name": "Oreo" + } + })"_json; + json patch = R"([{ + "op": "test", + "path": "/best_biscuit/name", + "value": "Choco Leibniz" + }])"_json; + value.patch(patch); + } + catch (json::other_error& e) + { + // output exception information + std::cout << "message: " << e.what() << '\n' + << "exception id: " << e.id << std::endl; + } +} diff --git a/doc/examples/other_error.link b/doc/examples/other_error.link new file mode 100644 index 00000000..a8dd89bc --- /dev/null +++ b/doc/examples/other_error.link @@ -0,0 +1 @@ +online \ No newline at end of file diff --git a/doc/examples/other_error.output b/doc/examples/other_error.output new file mode 100644 index 00000000..b80f1cb3 --- /dev/null +++ b/doc/examples/other_error.output @@ -0,0 +1,2 @@ +message: [json.exception.other_error.501] unsuccessful: {"op":"test","path":"/best_biscuit/name","value":"Choco Leibniz"} +exception id: 501 diff --git a/doc/examples/out_of_range.cpp b/doc/examples/out_of_range.cpp new file mode 100644 index 00000000..adec741e --- /dev/null +++ b/doc/examples/out_of_range.cpp @@ -0,0 +1,20 @@ +#include +#include "json.hpp" + +using json = nlohmann::json; + +int main() +{ + try + { + // calling at() for an invalid index + json j = {1, 2, 3, 4}; + j.at(4) = 10; + } + catch (json::out_of_range& e) + { + // output exception information + std::cout << "message: " << e.what() << '\n' + << "exception id: " << e.id << std::endl; + } +} diff --git a/doc/examples/out_of_range.link b/doc/examples/out_of_range.link new file mode 100644 index 00000000..3daa44ef --- /dev/null +++ b/doc/examples/out_of_range.link @@ -0,0 +1 @@ +online \ No newline at end of file diff --git a/doc/examples/out_of_range.output b/doc/examples/out_of_range.output new file mode 100644 index 00000000..29ec76b3 --- /dev/null +++ b/doc/examples/out_of_range.output @@ -0,0 +1,2 @@ +message: [json.exception.out_of_range.401] array index 4 is out of range +exception id: 401 diff --git a/doc/examples/parse_error.cpp b/doc/examples/parse_error.cpp new file mode 100644 index 00000000..6802e7da --- /dev/null +++ b/doc/examples/parse_error.cpp @@ -0,0 +1,20 @@ +#include +#include "json.hpp" + +using json = nlohmann::json; + +int main() +{ + try + { + // parsing input with a syntax error + json::parse("[1,2,3,]"); + } + catch (json::parse_error& e) + { + // output exception information + std::cout << "message: " << e.what() << '\n' + << "exception id: " << e.id << '\n' + << "byte position of error: " << e.byte << std::endl; + } +} diff --git a/doc/examples/parse_error.link b/doc/examples/parse_error.link new file mode 100644 index 00000000..89a31ea5 --- /dev/null +++ b/doc/examples/parse_error.link @@ -0,0 +1 @@ +online \ No newline at end of file diff --git a/doc/examples/parse_error.output b/doc/examples/parse_error.output new file mode 100644 index 00000000..96ab5bb5 --- /dev/null +++ b/doc/examples/parse_error.output @@ -0,0 +1,3 @@ +message: [json.exception.parse_error.101] parse error at 8: syntax error - unexpected ']'; expected '[', '{', or a literal +exception id: 101 +byte position of error: 8 diff --git a/doc/examples/type.cpp b/doc/examples/type.cpp index b712a852..5979d025 100644 --- a/doc/examples/type.cpp +++ b/doc/examples/type.cpp @@ -8,7 +8,8 @@ int main() // create JSON values json j_null; json j_boolean = true; - json j_number_integer = 17; + json j_number_integer = -17; + json j_number_unsigned = 42u; json j_number_float = 23.42; json j_object = {{"one", 1}, {"two", 2}}; json j_array = {1, 2, 4, 8, 16}; @@ -19,6 +20,7 @@ int main() std::cout << (j_null.type() == json::value_t::null) << '\n'; std::cout << (j_boolean.type() == json::value_t::boolean) << '\n'; std::cout << (j_number_integer.type() == json::value_t::number_integer) << '\n'; + std::cout << (j_number_unsigned.type() == json::value_t::number_unsigned) << '\n'; std::cout << (j_number_float.type() == json::value_t::number_float) << '\n'; std::cout << (j_object.type() == json::value_t::object) << '\n'; std::cout << (j_array.type() == json::value_t::array) << '\n'; diff --git a/doc/examples/type.link b/doc/examples/type.link index 3fedc680..a81ee122 100644 --- a/doc/examples/type.link +++ b/doc/examples/type.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/type.output b/doc/examples/type.output index 814ccfee..310e632a 100644 --- a/doc/examples/type.output +++ b/doc/examples/type.output @@ -5,3 +5,4 @@ true true true true +true diff --git a/doc/examples/type_error.cpp b/doc/examples/type_error.cpp new file mode 100644 index 00000000..6df39f51 --- /dev/null +++ b/doc/examples/type_error.cpp @@ -0,0 +1,20 @@ +#include +#include "json.hpp" + +using json = nlohmann::json; + +int main() +{ + try + { + // calling push_back() on a string value + json j = "string"; + j.push_back("another string"); + } + catch (json::type_error& e) + { + // output exception information + std::cout << "message: " << e.what() << '\n' + << "exception id: " << e.id << std::endl; + } +} diff --git a/doc/examples/type_error.link b/doc/examples/type_error.link new file mode 100644 index 00000000..fc160d07 --- /dev/null +++ b/doc/examples/type_error.link @@ -0,0 +1 @@ +online \ No newline at end of file diff --git a/doc/examples/type_error.output b/doc/examples/type_error.output new file mode 100644 index 00000000..1a673390 --- /dev/null +++ b/doc/examples/type_error.output @@ -0,0 +1,2 @@ +message: [json.exception.type_error.308] cannot use push_back() with string +exception id: 308 diff --git a/doc/examples/type_name.cpp b/doc/examples/type_name.cpp index 470d0a65..dccbd7b7 100644 --- a/doc/examples/type_name.cpp +++ b/doc/examples/type_name.cpp @@ -8,18 +8,20 @@ int main() // create JSON values json j_null; json j_boolean = true; - json j_number_integer = 17; + json j_number_integer = -17; + json j_number_unsigned = 42u; json j_number_float = 23.42; json j_object = {{"one", 1}, {"two", 2}}; json j_array = {1, 2, 4, 8, 16}; json j_string = "Hello, world"; // call type_name() - std::cout << j_null.type_name() << '\n'; - std::cout << j_boolean.type_name() << '\n'; - std::cout << j_number_integer.type_name() << '\n'; - std::cout << j_number_float.type_name() << '\n'; - std::cout << j_object.type_name() << '\n'; - std::cout << j_array.type_name() << '\n'; - std::cout << j_string.type_name() << '\n'; + std::cout << j_null << " is a " << j_null.type_name() << '\n'; + std::cout << j_boolean << " is a " << j_boolean.type_name() << '\n'; + std::cout << j_number_integer << " is a " << j_number_integer.type_name() << '\n'; + std::cout << j_number_unsigned << " is a " << j_number_unsigned.type_name() << '\n'; + std::cout << j_number_float << " is a " << j_number_float.type_name() << '\n'; + std::cout << j_object << " is an " << j_object.type_name() << '\n'; + std::cout << j_array << " is an " << j_array.type_name() << '\n'; + std::cout << j_string << " is a " << j_string.type_name() << '\n'; } diff --git a/doc/examples/type_name.link b/doc/examples/type_name.link index 7f50a398..dad7eebf 100644 --- a/doc/examples/type_name.link +++ b/doc/examples/type_name.link @@ -1 +1 @@ -online \ No newline at end of file +online \ No newline at end of file diff --git a/doc/examples/type_name.output b/doc/examples/type_name.output index ad906a49..f394e819 100644 --- a/doc/examples/type_name.output +++ b/doc/examples/type_name.output @@ -1,7 +1,8 @@ -null -boolean -number -number -object -array -string +null is a null +true is a boolean +-17 is a number +42 is a number +23.42 is a number +{"one":1,"two":2} is an object +[1,2,4,8,16] is an array +"Hello, world" is a string diff --git a/src/json.hpp b/src/json.hpp index ef55a93c..9adf6245 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -166,12 +166,28 @@ namespace detail /*! @brief general exception of the @ref basic_json class -Extension of std::exception objects with a member @a id for exception ids. +This class is an extension of `std::exception` objects with a member @a id for +exception ids. It is used as the base class for all exceptions thrown by the +@ref basic_json class. This class can hence be used as "wildcard" to catch +exceptions. +Subclasses: +- @ref parse_error for exceptions indicating a parse error +- @ref invalid_iterator for exceptions indicating errors with iterators +- @ref type_error for exceptions indicating executing a member function with + a wrong type +- @ref out_of_range for exceptions indicating access out of the defined range +- @ref other_error for exceptions indicating other library errors + +@internal @note To have nothrow-copy-constructible exceptions, we internally use - std::runtime_error which can cope with arbitrary-length error messages. + `std::runtime_error` which can cope with arbitrary-length error messages. Intermediate strings are built with static functions and then passed to the actual constructor. +@endinternal + +@liveexample{The following code shows how arbitrary library exceptions can be +caught.,exception} @since version 3.0.0 */ @@ -204,8 +220,8 @@ class exception : public std::exception @brief exception indicating a parse error This excpetion is thrown by the library when a parse error occurs. Parse errors -can occur during the deserialization of JSON text as well as when using JSON -Patch. +can occur during the deserialization of JSON text, CBOR, MessagePack, as well +as when using JSON Patch. Member @a byte holds the byte index of the last read character in the input file. @@ -231,6 +247,16 @@ json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vect json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xf8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. +@liveexample{The following code shows how a `parse_error` exception can be +caught.,parse_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + @since version 3.0.0 */ class parse_error : public exception @@ -271,6 +297,9 @@ class parse_error : public exception /*! @brief exception indicating errors with iterators +This exception is thrown if iterators passed to a library function do not match +the expected semantics. + Exceptions have ids 2xx. name / id | example message | description @@ -290,6 +319,16 @@ json.exception.invalid_iterator.212 | cannot compare iterators of different cont json.exception.invalid_iterator.213 | cannot compare order of object iterators | The order of object iterators cannot be compared, because JSON objects are unordered. json.exception.invalid_iterator.214 | cannot get value | Cannot get value for iterator: Either the iterator belongs to a null value or it is an iterator to a primitive type (number, boolean, or string), but the iterator is different to @ref begin(). +@liveexample{The following code shows how an `invalid_iterator` exception can be +caught.,invalid_iterator} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + @since version 3.0.0 */ class invalid_iterator : public exception @@ -309,6 +348,9 @@ class invalid_iterator : public exception /*! @brief exception indicating executing a member function with a wrong type +This exception is thrown in case of a type error; that is, a library function is +executed on a JSON value whose type does not match the expected semantics. + Exceptions have ids 3xx. name / id | example message | description @@ -329,6 +371,15 @@ json.exception.type_error.313 | invalid value to unflatten | The @ref unflatten json.exception.type_error.314 | only objects can be unflattened | The @ref unflatten function only works for an object whose keys are JSON Pointers. json.exception.type_error.315 | values in object must be primitive | The @ref unflatten function only works for an object whose keys are JSON Pointers and whose values are primitive. +@liveexample{The following code shows how a `type_error` exception can be +caught.,type_error} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref out_of_range for exceptions indicating access out of the defined range +@sa @ref other_error for exceptions indicating other library errors + @since version 3.0.0 */ class type_error : public exception @@ -347,6 +398,10 @@ class type_error : public exception /*! @brief exception indicating access out of the defined range +This exception is thrown in case a library function is called on an input +parameter that exceeds the expected range, for instance in case of array +indices or nonexisting object keys. + Exceptions have ids 4xx. name / id | example message | description @@ -358,6 +413,16 @@ json.exception.out_of_range.404 | unresolved reference token 'foo' | A reference json.exception.out_of_range.405 | JSON pointer has no parent | The JSON Patch operations 'remove' and 'add' can not be applied to the root element of the JSON value. json.exception.out_of_range.406 | number overflow parsing '10E1000' | A parsed number could not be stored as without changing it to NaN or INF. +@liveexample{The following code shows how an `out_of_range` exception can be +caught.,out_of_range} + +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref other_error for exceptions indicating other library errors + @since version 3.0.0 */ class out_of_range : public exception @@ -374,7 +439,10 @@ class out_of_range : public exception }; /*! -@brief exception indicating other errors +@brief exception indicating other library errors + +This exception is thrown in case of errors that cannot be classified with the +other exception types. Exceptions have ids 5xx. @@ -383,6 +451,16 @@ name / id | example message | description json.exception.other_error.501 | unsuccessful: {"op":"test","path":"/baz", "value":"bar"} | A JSON Patch operation 'test' failed. The unsuccessful operation is also printed. json.exception.other_error.502 | invalid object size for conversion | Some conversions to user-defined types impose constraints on the object size (e.g. std::pair) +@sa @ref exception for the base class of the library exceptions +@sa @ref parse_error for exceptions indicating a parse error +@sa @ref invalid_iterator for exceptions indicating errors with iterators +@sa @ref type_error for exceptions indicating executing a member function with + a wrong type +@sa @ref out_of_range for exceptions indicating access out of the defined range + +@liveexample{The following code shows how an `other_error` exception can be +caught.,other_error} + @since version 3.0.0 */ class other_error : public exception @@ -1743,7 +1821,7 @@ class lexer checks if it is inside the range. If a violation was detected, set up an error message and return false. Otherwise, return true. - @return true iff no range violation was detected + @return true if and only if no range violation was detected */ bool next_byte_in_range(std::initializer_list ranges) { @@ -4489,7 +4567,7 @@ class binary_reader /*! @brief determine system byte order - @return true iff system's byte order is little endian + @return true if and only if system's byte order is little endian @note from http://stackoverflow.com/a/1001328/266378 */ @@ -7382,6 +7460,9 @@ class basic_json @liveexample{The following code shows an example output of the `meta()` function.,meta} + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + @complexity Constant. @since 2.1.0 @@ -8188,9 +8269,14 @@ class basic_json @complexity Constant. + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + @liveexample{The following code shows the constructor for different @ref value_t values,basic_json__value_t} + @sa @ref clear() -- restores the postcondition of this constructor + @since version 1.0.0 */ basic_json(const value_t v) @@ -8235,9 +8321,9 @@ class basic_json following types: - **arrays**: @ref array_t and all kinds of compatible containers such as `std::vector`, `std::deque`, `std::list`, `std::forward_list`, - `std::array`, `std::set`, `std::unordered_set`, `std::multiset`, and - `unordered_multiset` with a `value_type` from which a @ref basic_json - value can be constructed. + `std::array`, `std::valarray`, `std::set`, `std::unordered_set`, + `std::multiset`, and `std::unordered_multiset` with a `value_type` from + which a @ref basic_json value can be constructed. - **objects**: @ref object_t and all kinds of compatible associative containers such as `std::map`, `std::unordered_map`, `std::multimap`, and `std::unordered_multimap` with a `key_type` compatible to @@ -8263,13 +8349,16 @@ class basic_json @tparam U = `uncvref_t` - @param[in] val the value to be forwarded + @param[in] val the value to be forwarded to the respective constructor @complexity Usually linear in the size of the passed @a val, also depending on the implementation of the called `to_json()` method. - @throw what `json_serializer::to_json()` throws + @exceptionsafety Depends on the called constructor. For types directly + supported by the library (i.e., all types for which no `to_json()` function + was provided), strong guarantee holds: if an exception is thrown, there are + no changes to any JSON value. @liveexample{The following code shows the constructor with several compatible types.,basic_json__CompatibleType} @@ -8309,7 +8398,7 @@ class basic_json 1. The empty initializer list is written as `{}` which is exactly an empty JSON object. - 2. C++ has now way of describing mapped types other than to list a list of + 2. C++ has no way of describing mapped types other than to list a list of pairs. As JSON requires that keys must be of type string, rule 2 is the weakest constraint one can pose on initializer lists to interpret them as an object. @@ -8351,6 +8440,9 @@ class basic_json @complexity Linear in the size of the initializer list @a init. + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + @liveexample{The example below shows how JSON values are created from initializer lists.,basic_json__list_init_t} @@ -8437,6 +8529,9 @@ class basic_json @complexity Linear in the size of @a init. + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + @liveexample{The following code shows an example for the `array` function.,array} @@ -8477,6 +8572,9 @@ class basic_json @complexity Linear in the size of @a init. + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + @liveexample{The following code shows an example for the `object` function.,object} @@ -8496,14 +8594,18 @@ class basic_json @brief construct an array with count copies of given value Constructs a JSON array value by creating @a cnt copies of a passed value. - In case @a cnt is `0`, an empty array is created. As postcondition, - `std::distance(begin(),end()) == cnt` holds. + In case @a cnt is `0`, an empty array is created. @param[in] cnt the number of JSON copies of @a val to create @param[in] val the JSON value to copy + @post `std::distance(begin(),end()) == cnt` holds. + @complexity Linear in @a cnt. + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + @liveexample{The following code shows examples for the @ref basic_json(size_type\, const basic_json&) constructor.,basic_json__size_type_basic_json} @@ -8522,12 +8624,13 @@ class basic_json Constructs the JSON value with the contents of the range `[first, last)`. The semantics depends on the different types a JSON value can have: - - In case of primitive types (number, boolean, or string), @a first must - be `begin()` and @a last must be `end()`. In this case, the value is + - In case of a null type, invalid_iterator.206 is thrown. + - In case of other primitive types (number, boolean, or string), @a first + must be `begin()` and @a last must be `end()`. In this case, the value is copied. Otherwise, invalid_iterator.204 is thrown. - In case of structured types (array, object), the constructor behaves as - similar versions for `std::vector`. - - In case of a null type, invalid_iterator.206 is thrown. + similar versions for `std::vector` or `std::map`; that is, a JSON array + or object is constructed from the values in the range. @tparam InputIT an input iterator type (@ref iterator or @ref const_iterator) @@ -8536,11 +8639,20 @@ class basic_json @param[in] last end of the range to copy from (excluded) @pre Iterators @a first and @a last must be initialized. **This - precondition is enforced with an assertion.** + precondition is enforced with an assertion (see warning).** If + assertions are switched off, a violation of this precondition yields + undefined behavior. @pre Range `[first, last)` is valid. Usually, this precondition cannot be checked efficiently. Only certain edge cases are detected; see the - description of the exceptions below. + description of the exceptions below. A violation of this precondition + yields undefined behavior. + + @warning A precondition is enforced with a runtime assertion that will + result in calling `std::abort` if this precondition is not met. + Assertions can be disabled by defining `NDEBUG` at compile time. + See http://en.cppreference.com/w/cpp/error/assert for more + information. @throw invalid_iterator.201 if iterators @a first and @a last are not compatible (i.e., do not belong to the same JSON value). In this case, @@ -8554,6 +8666,9 @@ class basic_json @complexity Linear in distance between @a first and @a last. + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + @liveexample{The example below shows several ways to create JSON values by specifying a subrange with iterators.,basic_json__InputIt_InputIt} @@ -8656,6 +8771,7 @@ class basic_json // other constructors and destructor // /////////////////////////////////////// + /// @private basic_json(const detail::json_ref& ref) : basic_json(ref.moved_or_copied()) {} @@ -8667,8 +8783,13 @@ class basic_json @param[in] other the JSON value to copy + @post `*this == other` + @complexity Linear in the size of @a other. + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes to any JSON value. + @requirement This function helps `basic_json` satisfying the [Container](http://en.cppreference.com/w/cpp/concept/Container) requirements: @@ -8746,10 +8867,18 @@ class basic_json @param[in,out] other value to move to this object - @post @a other is a JSON null value + @post `*this` has the same value as @a other before the call. + @post @a other is a JSON null value. @complexity Constant. + @exceptionsafety No-throw guarantee: this constructor never throws + exceptions. + + @requirement This function helps `basic_json` satisfying the + [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible) + requirements. + @liveexample{The code below shows the move constructor explicitly called via std::move.,basic_json__moveconstructor} @@ -8774,7 +8903,7 @@ class basic_json Copy assignment operator. Copies a JSON value via the "copy and swap" strategy: It is expressed in terms of the copy constructor, destructor, - and the swap() member function. + and the `swap()` member function. @param[in] other value to copy from @@ -8855,7 +8984,7 @@ class basic_json representation. @param[in] indent_char The character to use for indentation if @a indent is greater than `0`. The default is ` ` (space). - @param[in] ensure_ascii If ensure_ascii is true, all non-ASCII characters + @param[in] ensure_ascii If @a ensure_ascii is true, all non-ASCII characters in the output are escaped with \uXXXX sequences, and the result consists of ASCII characters only. @@ -8863,12 +8992,17 @@ class basic_json @complexity Linear. - @liveexample{The following example shows the effect of different @a indent - parameters to the result of the serialization.,dump} + @exceptionsafety Strong guarantee: if an exception is thrown, there are no + changes in the JSON value. + + @liveexample{The following example shows the effect of different @a indent\, + @a indent_char\, and @a ensure_ascii parameters to the result of the + serialization.,dump} @see https://docs.python.org/2/library/json.html#json.dump - @since version 1.0.0; indentation character added in version 3.0.0 + @since version 1.0.0; indentation character @a indent_char and option + @a ensure_ascii added in version 3.0.0 */ string_t dump(const int indent = -1, const char indent_char = ' ', const bool ensure_ascii = false) const @@ -8895,6 +9029,17 @@ class basic_json enumeration. @return the type of the JSON value + Value type | return value + ------------------------- | ------------------------- + null | value_t::null + boolean | value_t::boolean + string | value_t::string + number (integer) | value_t::number_integer + number (unsigned integer) | value_t::number_unsigned + number (foating-point) | value_t::number_float + object | value_t::object + array | value_t::array + discarded | value_t::discarded @complexity Constant. @@ -8904,6 +9049,9 @@ class basic_json @liveexample{The following code exemplifies `type()` for all JSON types.,type} + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + @sa @ref type_name() -- return the type as string + @since version 1.0.0 */ constexpr value_t type() const noexcept @@ -8914,8 +9062,8 @@ class basic_json /*! @brief return whether type is primitive - This function returns true iff the JSON type is primitive (string, number, - boolean, or null). + This function returns true if and only if the JSON type is primitive + (string, number, boolean, or null). @return `true` if type is primitive (string, number, boolean, or null), `false` otherwise. @@ -8944,8 +9092,8 @@ class basic_json /*! @brief return whether type is structured - This function returns true iff the JSON type is structured (array or - object). + This function returns true if and only if the JSON type is structured + (array or object). @return `true` if type is structured (array or object), `false` otherwise. @@ -8971,7 +9119,7 @@ class basic_json /*! @brief return whether value is null - This function returns true iff the JSON value is null. + This function returns true if and only if the JSON value is null. @return `true` if type is null, `false` otherwise. @@ -8993,7 +9141,7 @@ class basic_json /*! @brief return whether value is a boolean - This function returns true iff the JSON value is a boolean. + This function returns true if and only if the JSON value is a boolean. @return `true` if type is boolean, `false` otherwise. @@ -9015,8 +9163,8 @@ class basic_json /*! @brief return whether value is a number - This function returns true iff the JSON value is a number. This includes - both integer and floating-point values. + This function returns true if and only if the JSON value is a number. This + includes both integer (signed and unsigned) and floating-point values. @return `true` if type is number (regardless whether integer, unsigned integer or floating-type), `false` otherwise. @@ -9045,8 +9193,8 @@ class basic_json /*! @brief return whether value is an integer number - This function returns true iff the JSON value is an integer or unsigned - integer number. This excludes floating-point values. + This function returns true if and only if the JSON value is a signed or + unsigned integer number. This excludes floating-point values. @return `true` if type is an integer or unsigned integer number, `false` otherwise. @@ -9074,8 +9222,8 @@ class basic_json /*! @brief return whether value is an unsigned integer number - This function returns true iff the JSON value is an unsigned integer - number. This excludes floating-point and (signed) integer values. + This function returns true if and only if the JSON value is an unsigned + integer number. This excludes floating-point and signed integer values. @return `true` if type is an unsigned integer number, `false` otherwise. @@ -9102,8 +9250,8 @@ class basic_json /*! @brief return whether value is a floating-point number - This function returns true iff the JSON value is a floating-point number. - This excludes integer and unsigned integer values. + This function returns true if and only if the JSON value is a + floating-point number. This excludes signed and unsigned integer values. @return `true` if type is a floating-point number, `false` otherwise. @@ -9130,7 +9278,7 @@ class basic_json /*! @brief return whether value is an object - This function returns true iff the JSON value is an object. + This function returns true if and only if the JSON value is an object. @return `true` if type is object, `false` otherwise. @@ -9152,7 +9300,7 @@ class basic_json /*! @brief return whether value is an array - This function returns true iff the JSON value is an array. + This function returns true if and only if the JSON value is an array. @return `true` if type is array, `false` otherwise. @@ -9174,7 +9322,7 @@ class basic_json /*! @brief return whether value is a string - This function returns true iff the JSON value is a string. + This function returns true if and only if the JSON value is a string. @return `true` if type is string, `false` otherwise. @@ -9196,8 +9344,8 @@ class basic_json /*! @brief return whether value is discarded - This function returns true iff the JSON value was discarded during parsing - with a callback function (see @ref parser_callback_t). + This function returns true if and only if the JSON value was discarded + during parsing with a callback function (see @ref parser_callback_t). @note This function will always be `false` for JSON values after parsing. That is, discarded values can only occur during parsing, but will be @@ -9236,6 +9384,9 @@ class basic_json @liveexample{The following code exemplifies the @ref value_t operator for all JSON types.,operator__value_t} + @sa @ref type() -- return the type of the JSON value (explicit) + @sa @ref type_name() -- return the type as string + @since version 1.0.0 */ constexpr operator value_t() const noexcept @@ -11336,7 +11487,8 @@ class basic_json @brief clears the contents Clears the content of a JSON value and resets it to the default value as - if @ref basic_json(value_t) would have been called: + if @ref basic_json(value_t) would have been called with the current value + type from @ref type(): Value type | initial value ----------- | ------------- @@ -11347,11 +11499,20 @@ class basic_json object | `{}` array | `[]` + @post Has the same effect as calling + @code {.cpp} + *this = basic_json(type()); + @endcode + @complexity Linear in the size of the JSON value. + @exceptionsafety No-throw guarantee: this function never throws exceptions. + @liveexample{The example below shows the effect of `clear()` to different JSON types.,clear} + @sa @ref basic_json(value_t) -- constructor that creates + @since version 1.0.0 */ void clear() noexcept @@ -12189,12 +12350,27 @@ class basic_json comparison. Note than two NaN values are always treated as unequal. - Two JSON null values are equal. + @note Floating-point inside JSON values numbers are compared with + `json::number_float_t::operator==` which is `double::operator==` by + default. To compare floating-point while respecting an epsilon, an alternative + [comparison function](https://github.com/mariokonrad/marnav/blob/master/src/marnav/math/floatingpoint.hpp#L34-#L39) + could be used, for instance + @code {.cpp} + template ::value, T>::type> + inline bool is_same(T a, T b, T epsilon = std::numeric_limits::epsilon()) noexcept + { + return std::abs(a - b) <= epsilon; + } + @endcode + @note NaN values never compare equal to themselves or to other NaN values. @param[in] lhs first JSON value to consider @param[in] rhs second JSON value to consider @return whether the values @a lhs and @a rhs are equal + @exceptionsafety No-throw guarantee: this function never throws exceptions. + @complexity Linear. @liveexample{The example demonstrates comparing several JSON @@ -12300,6 +12476,8 @@ class basic_json @complexity Linear. + @exceptionsafety No-throw guarantee: this function never throws exceptions. + @liveexample{The example demonstrates comparing several JSON types.,operator__notequal} @@ -12351,6 +12529,8 @@ class basic_json @complexity Linear. + @exceptionsafety No-throw guarantee: this function never throws exceptions. + @liveexample{The example demonstrates comparing several JSON types.,operator__less} @@ -12458,6 +12638,8 @@ class basic_json @complexity Linear. + @exceptionsafety No-throw guarantee: this function never throws exceptions. + @liveexample{The example demonstrates comparing several JSON types.,operator__greater} @@ -12502,6 +12684,8 @@ class basic_json @complexity Linear. + @exceptionsafety No-throw guarantee: this function never throws exceptions. + @liveexample{The example demonstrates comparing several JSON types.,operator__lessequal} @@ -12546,6 +12730,8 @@ class basic_json @complexity Linear. + @exceptionsafety No-throw guarantee: this function never throws exceptions. + @liveexample{The example demonstrates comparing several JSON types.,operator__greaterequal} @@ -12634,7 +12820,7 @@ class basic_json @brief serialize to stream @deprecated This stream operator is deprecated and will be removed in a future version of the library. Please use - @ref std::ostream& operator<<(std::ostream&, const basic_json&) + @ref operator<<(std::ostream&, const basic_json&) instead; that is, replace calls like `j >> o;` with `o << j;`. */ JSON_DEPRECATED @@ -12817,7 +13003,7 @@ class basic_json @brief deserialize from stream @deprecated This stream operator is deprecated and will be removed in a future version of the library. Please use - @ref std::istream& operator>>(std::istream&, basic_json&) + @ref operator>>(std::istream&, basic_json&) instead; that is, replace calls like `j << i;` with `i >> j;`. */ JSON_DEPRECATED @@ -12869,16 +13055,31 @@ class basic_json Returns the type name as string to be used in error messages - usually to indicate that a function was called on a wrong JSON type. - @return basically a string representation of a the @a m_type member + @return a string representation of a the @a m_type member: + Value type | return value + ----------- | ------------- + null | `"null"` + boolean | `"boolean"` + string | `"string"` + number | `"number"` (for all number types) + object | `"object"` + array | `"array"` + discarded | `"discarded"` + + @exceptionsafety No-throw guarantee: this function never throws exceptions. @complexity Constant. @liveexample{The following code exemplifies `type_name()` for all JSON types.,type_name} - @since version 1.0.0, public since 2.1.0, const char* since 3.0.0 + @sa @ref type() -- return the type of the JSON value + @sa @ref operator value_t() -- return the type of the JSON value (implicit) + + @since version 1.0.0, public since 2.1.0, `const char*` and `noexcept` + since 3.0.0 */ - const char* type_name() const + const char* type_name() const noexcept { { switch (m_type) diff --git a/test/src/unit-concepts.cpp b/test/src/unit-concepts.cpp index d2c24866..971651e0 100644 --- a/test/src/unit-concepts.cpp +++ b/test/src/unit-concepts.cpp @@ -94,6 +94,7 @@ TEST_CASE("concepts") SECTION("MoveConstructible") { + CHECK(std::is_move_constructible::value); CHECK(std::is_nothrow_move_constructible::value); } diff --git a/test/src/unit-constructor1.cpp b/test/src/unit-constructor1.cpp index 10b5216d..ec096dcd 100644 --- a/test/src/unit-constructor1.cpp +++ b/test/src/unit-constructor1.cpp @@ -1181,12 +1181,33 @@ TEST_CASE("constructors") SECTION("create an array of n copies of a given value") { - json v = {1, "foo", 34.23, {1, 2, 3}, {{"A", 1}, {"B", 2u}}}; - json arr(3, v); - CHECK(arr.size() == 3); - for (auto& x : arr) + SECTION("cnt = 0") { - CHECK(x == v); + json v = {1, "foo", 34.23, {1, 2, 3}, {{"A", 1}, {"B", 2u}}}; + json arr(0, v); + CHECK(arr.size() == 0); + } + + SECTION("cnt = 1") + { + json v = {1, "foo", 34.23, {1, 2, 3}, {{"A", 1}, {"B", 2u}}}; + json arr(1, v); + CHECK(arr.size() == 1); + for (auto& x : arr) + { + CHECK(x == v); + } + } + + SECTION("cnt = 3") + { + json v = {1, "foo", 34.23, {1, 2, 3}, {{"A", 1}, {"B", 2u}}}; + json arr(3, v); + CHECK(arr.size() == 3); + for (auto& x : arr) + { + CHECK(x == v); + } } } diff --git a/test/src/unit-modifiers.cpp b/test/src/unit-modifiers.cpp index 7db4153b..94494c6e 100644 --- a/test/src/unit-modifiers.cpp +++ b/test/src/unit-modifiers.cpp @@ -38,17 +38,21 @@ TEST_CASE("modifiers") SECTION("boolean") { json j = true; + json k = j; j.clear(); CHECK(j == json(json::value_t::boolean)); + CHECK(j == json(k.type())); } SECTION("string") { json j = "hello world"; + json k = j; j.clear(); CHECK(j == json(json::value_t::string)); + CHECK(j == json(k.type())); } SECTION("array") @@ -56,19 +60,23 @@ TEST_CASE("modifiers") SECTION("empty array") { json j = json::array(); + json k = j; j.clear(); CHECK(j.empty()); CHECK(j == json(json::value_t::array)); + CHECK(j == json(k.type())); } SECTION("filled array") { json j = {1, 2, 3}; + json k = j; j.clear(); CHECK(j.empty()); CHECK(j == json(json::value_t::array)); + CHECK(j == json(k.type())); } } @@ -77,52 +85,64 @@ TEST_CASE("modifiers") SECTION("empty object") { json j = json::object(); + json k = j; j.clear(); CHECK(j.empty()); CHECK(j == json(json::value_t::object)); + CHECK(j == json(k.type())); } SECTION("filled object") { json j = {{"one", 1}, {"two", 2}, {"three", 3}}; + json k = j; j.clear(); CHECK(j.empty()); CHECK(j == json(json::value_t::object)); + CHECK(j == json(k.type())); } } SECTION("number (integer)") { json j = 23; + json k = j; j.clear(); CHECK(j == json(json::value_t::number_integer)); + CHECK(j == json(k.type())); } SECTION("number (unsigned)") { json j = 23u; + json k = j; j.clear(); CHECK(j == json(json::value_t::number_integer)); + CHECK(j == json(k.type())); } SECTION("number (float)") { json j = 23.42; + json k = j; j.clear(); CHECK(j == json(json::value_t::number_float)); + CHECK(j == json(k.type())); } SECTION("null") { json j = nullptr; + json k = j; j.clear(); CHECK(j == json(json::value_t::null)); + CHECK(j == json(k.type())); } } diff --git a/test/src/unit-regression.cpp b/test/src/unit-regression.cpp index 3aeee814..0c0d148d 100644 --- a/test/src/unit-regression.cpp +++ b/test/src/unit-regression.cpp @@ -1209,9 +1209,9 @@ TEST_CASE("regression tests") { SECTION("original example") { - std::valarray v; - nlohmann::json j; - j["test"] = v; + std::valarray v; + nlohmann::json j; + j["test"] = v; } SECTION("full example") @@ -1230,7 +1230,7 @@ TEST_CASE("regression tests") CHECK_THROWS_AS(json().get>(), json::type_error&); CHECK_THROWS_WITH(json().get>(), - "[json.exception.type_error.302] type must be array, but is null"); + "[json.exception.type_error.302] type must be array, but is null"); } } } From c607b5c2ac3851f91431a062e17d74bec349d1b2 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 6 Sep 2017 17:14:06 +0200 Subject: [PATCH 2/5] :memo: improved documentation --- doc/Doxyfile | 3 ++- src/json.hpp | 68 ++++++++++++++++++++++++++++++++-------------------- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/doc/Doxyfile b/doc/Doxyfile index e61f3024..8dfc0dcd 100644 --- a/doc/Doxyfile +++ b/doc/Doxyfile @@ -30,7 +30,8 @@ TAB_SIZE = 4 ALIASES = "complexity=@par Complexity\n" \ "liveexample{2}=@par Example\n \1 \n @includelineno \2.cpp \n Output (play with this example @htmlinclude \2.link):\n @verbinclude \2.output \n The example code above can be translated with @verbatim g++ -std=c++11 -Isrc doc/examples/\2.cpp -o \2 @endverbatim" \ "requirement=@par Requirements\n" \ - "exceptionsafety=@par Exception safety\n" + "exceptionsafety=@par Exception safety\n" \ + "iterators=@par Iterator validity\n" TCL_SUBST = OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO diff --git a/src/json.hpp b/src/json.hpp index 9adf6245..e7c42920 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -226,10 +226,6 @@ as when using JSON Patch. Member @a byte holds the byte index of the last read character in the input file. -@note For an input with n bytes, 1 is the index of the first character and n+1 - is the index of the terminating null byte or the end of file. This also - holds true when reading a byte vector (CBOR or MessagePack). - Exceptions have ids 1xx. name / id | example message | description @@ -247,6 +243,10 @@ json.exception.parse_error.110 | parse error at 1: cannot read 2 bytes from vect json.exception.parse_error.112 | parse error at 1: error reading CBOR; last byte: 0xf8 | Not all types of CBOR or MessagePack are supported. This exception occurs if an unsupported byte was read. json.exception.parse_error.113 | parse error at 2: expected a CBOR string; last byte: 0x98 | While parsing a map key, a value that is not a string has been read. +@note For an input with n bytes, 1 is the index of the first character and n+1 + is the index of the terminating null byte or the end of file. This also + holds true when reading a byte vector (CBOR or MessagePack). + @liveexample{The following code shows how a `parse_error` exception can be caught.,parse_error} @@ -11279,9 +11279,9 @@ class basic_json /// @{ /*! - @brief checks whether the container is empty + @brief checks whether the container is empty. - Checks if a JSON value has no elements. + Checks if a JSON value has no elements (i.e. whether its @ref size is `0`). @return The return value depends on the different types and is defined as follows: @@ -11294,23 +11294,27 @@ class basic_json object | result of function `object_t::empty()` array | result of function `array_t::empty()` - @note This function does not return whether a string stored as JSON value - is empty - it returns whether the JSON container itself is empty which is - false in the case of a string. + @liveexample{The following code uses `empty()` to check if a JSON + object contains any elements.,empty} @complexity Constant, as long as @ref array_t and @ref object_t satisfy the Container concept; that is, their `empty()` functions have constant complexity. + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return whether a string stored as JSON value + is empty - it returns whether the JSON container itself is empty which is + false in the case of a string. + @requirement This function helps `basic_json` satisfying the [Container](http://en.cppreference.com/w/cpp/concept/Container) requirements: - The complexity is constant. - Has the semantics of `begin() == end()`. - @liveexample{The following code uses `empty()` to check if a JSON - object contains any elements.,empty} - @sa @ref size() -- returns the number of elements @since version 1.0.0 @@ -11361,23 +11365,27 @@ class basic_json object | result of function object_t::size() array | result of function array_t::size() - @note This function does not return the length of a string stored as JSON - value - it returns the number of elements in the JSON value which is 1 in - the case of a string. + @liveexample{The following code calls `size()` on the different value + types.,size} @complexity Constant, as long as @ref array_t and @ref object_t satisfy the Container concept; that is, their size() functions have constant complexity. + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @note This function does not return the length of a string stored as JSON + value - it returns the number of elements in the JSON value which is 1 in + the case of a string. + @requirement This function helps `basic_json` satisfying the [Container](http://en.cppreference.com/w/cpp/concept/Container) requirements: - The complexity is constant. - Has the semantics of `std::distance(begin(), end())`. - @liveexample{The following code calls `size()` on the different value - types.,size} - @sa @ref empty() -- checks whether the container is empty @sa @ref max_size() -- returns the maximal number of elements @@ -11431,10 +11439,17 @@ class basic_json object | result of function `object_t::max_size()` array | result of function `array_t::max_size()` + @liveexample{The following code calls `max_size()` on the different value + types. Note the output is implementation specific.,max_size} + @complexity Constant, as long as @ref array_t and @ref object_t satisfy the Container concept; that is, their `max_size()` functions have constant complexity. + @iterators No changes. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + @requirement This function helps `basic_json` satisfying the [Container](http://en.cppreference.com/w/cpp/concept/Container) requirements: @@ -11442,9 +11457,6 @@ class basic_json - Has the semantics of returning `b.size()` where `b` is the largest possible JSON value. - @liveexample{The following code calls `max_size()` on the different value - types. Note the output is implementation specific.,max_size} - @sa @ref size() -- returns the number of elements @since version 1.0.0 @@ -11504,14 +11516,18 @@ class basic_json *this = basic_json(type()); @endcode - @complexity Linear in the size of the JSON value. - - @exceptionsafety No-throw guarantee: this function never throws exceptions. - @liveexample{The example below shows the effect of `clear()` to different JSON types.,clear} - @sa @ref basic_json(value_t) -- constructor that creates + @complexity Linear in the size of the JSON value. + + @iterators All iterators, pointers and references related to this container + are invalidated. + + @exceptionsafety No-throw guarantee: this function never throws exceptions. + + @sa @ref basic_json(value_t) -- constructor that creates an object with the + same value than calling `clear()` @since version 1.0.0 */ From da14286abb94daf7a8d3281a49e1e46dbc049006 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 6 Sep 2017 18:13:35 +0200 Subject: [PATCH 3/5] :construction_worker: try to use MSVC 2017 again --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 50331a1f..4f423e2f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,7 +2,7 @@ version: '{build}' os: - Visual Studio 2015 - - Previous Visual Studio 2017 + - Visual Studio 2017 environment: matrix: From 5c08b84decac48df624bde332c1ffee308b41bbf Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 6 Sep 2017 18:26:52 +0200 Subject: [PATCH 4/5] :rewind: back to previous MSVC 2017 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 4f423e2f..50331a1f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,7 +2,7 @@ version: '{build}' os: - Visual Studio 2015 - - Visual Studio 2017 + - Previous Visual Studio 2017 environment: matrix: From fd250ae2b1738ddafee77a0ca7feb74b155c4437 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sat, 9 Sep 2017 11:04:58 +0200 Subject: [PATCH 5/5] :white_check_mark: improved test coverage --- test/src/unit-class_parser.cpp | 32 +++++++++++++++++++++++++++++++ test/src/unit-deserialization.cpp | 2 ++ 2 files changed, 34 insertions(+) diff --git a/test/src/unit-class_parser.cpp b/test/src/unit-class_parser.cpp index f5415552..f375d851 100644 --- a/test/src/unit-class_parser.cpp +++ b/test/src/unit-class_parser.cpp @@ -173,6 +173,38 @@ TEST_CASE("parser class") CHECK_THROWS_AS(parser_helper("\"\x1d\""), json::parse_error&); CHECK_THROWS_AS(parser_helper("\"\x1e\""), json::parse_error&); CHECK_THROWS_AS(parser_helper("\"\x1f\""), json::parse_error&); + CHECK_THROWS_WITH(parser_helper("\"\x00\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: missing closing quote; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x01\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x02\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x03\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x04\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x05\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x06\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x07\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x08\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x09\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x0a\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x0b\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x0c\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x0d\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x0e\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x0f\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x10\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x11\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x12\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x13\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x14\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x15\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x16\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x17\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x18\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x19\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x1a\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x1b\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x1c\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x1d\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x1e\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); + CHECK_THROWS_WITH(parser_helper("\"\x1f\""), "[json.exception.parse_error.101] parse error at 2: syntax error - invalid string: control character must be escaped; last read: '\"'"); } SECTION("escaped") diff --git a/test/src/unit-deserialization.cpp b/test/src/unit-deserialization.cpp index da406391..bb52cd6c 100644 --- a/test/src/unit-deserialization.cpp +++ b/test/src/unit-deserialization.cpp @@ -323,6 +323,8 @@ TEST_CASE("deserialization") { uint8_t v[] = {'\"', 0x7F, 0xDF, 0x7F}; CHECK_THROWS_AS(json::parse(std::begin(v), std::end(v)), json::parse_error&); + CHECK_THROWS_WITH(json::parse(std::begin(v), std::end(v)), + "[json.exception.parse_error.101] parse error at 4: syntax error - invalid string: ill-formed UTF-8 byte; last read: '\"\x7f\xdf\x7f'"); CHECK(not json::accept(std::begin(v), std::end(v))); json j_error;