diff --git a/.gitignore b/.gitignore index 217a2c3a..4c0706d8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ -bin/ -bin64/ +bin +bin64 *.*# +temp # Because of CMake and VS2017 -Win32/ -x64/ +Win32 +x64 diff --git a/Jamfile b/Jamfile index 90f8ec9d..f603e4b3 100644 --- a/Jamfile +++ b/Jamfile @@ -7,4 +7,6 @@ # Official repository: https://github.com/vinniefalco/json # +path-constant LIB_DIR : . ; + build-project test ; diff --git a/README.md b/README.md index 6f291fc3..b8bf9e64 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ Branch | Travis | Appveyor | Azure Pipelines | codecov.io | Docs | Matrix | :-------------: | ------ | -------- | --------------- | ---------- | ---- | ------ | -[`master`](https://github.com/vinniefalco/json/tree/master) | [![Build Status](https://travis-ci.org/vinniefalco/json.svg?branch=master)](https://travis-ci.org/vinniefalco/json) | [![Build status](https://ci.appveyor.com/api/projects/status/github/vinniefalco/json?branch=master&svg=true)](https://ci.appveyor.com/project/vinniefalco/json/branch/master) | [![Build Status](https://dev.azure.com/vinniefalco/json/_apis/build/status/pipeline?branchName=master)](https://dev.azure.com/vinniefalco/json/_build/latest?definitionId=6&branchName=master) | [![codecov](https://codecov.io/gh/vinniefalco/json/branch/master/graph/badge.svg)](https://codecov.io/gh/vinniefalco/json/branch/master) | [![Documentation](https://img.shields.io/badge/docs-master-brightgreen.svg)](http://www.boost.org/doc/libs/master/doc/html/json.html) | [![Matrix](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/json.html) -[`develop`](https://github.com/vinniefalco/json/tree/develop) | [![Build Status](https://travis-ci.org/vinniefalco/json.svg?branch=develop)](https://travis-ci.org/vinniefalco/json) | [![Build status](https://ci.appveyor.com/api/projects/status/github/vinniefalco/json?branch=develop&svg=true)](https://ci.appveyor.com/project/vinniefalco/json/branch/develop) | [![Build Status](https://dev.azure.com/vinniefalco/json/_apis/build/status/pipeline?branchName=develop)](https://dev.azure.com/vinniefalco/json/_build/latest?definitionId=6&branchName=master) | [![codecov](https://codecov.io/gh/vinniefalco/json/branch/develop/graph/badge.svg)](https://codecov.io/gh/vinniefalco/json/branch/develop) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://www.boost.org/doc/libs/develop/doc/html/json.html) | [![Matrix](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/json.html) +[`master`](https://github.com/vinniefalco/json/tree/master) | [![Build Status](https://travis-ci.org/vinniefalco/json.svg?branch=master)](https://travis-ci.org/vinniefalco/json) | [![Build status](https://ci.appveyor.com/api/projects/status/github/vinniefalco/json?branch=master&svg=true)](https://ci.appveyor.com/project/vinniefalco/json/branch/master) | [![Build Status](https://dev.azure.com/vinniefalco/json/_apis/build/status/pipeline?branchName=master)](https://dev.azure.com/vinniefalco/json/_build/latest?definitionId=6&branchName=master) | [![codecov](https://codecov.io/gh/vinniefalco/json/branch/master/graph/badge.svg)](https://codecov.io/gh/vinniefalco/json/branch/master) | [![Documentation](https://img.shields.io/badge/docs-master-brightgreen.svg)](http://vinniefalco.github.com/doc/json/index.html) | [![Matrix](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/json.html) +[`develop`](https://github.com/vinniefalco/json/tree/develop) | [![Build Status](https://travis-ci.org/vinniefalco/json.svg?branch=develop)](https://travis-ci.org/vinniefalco/json) | [![Build status](https://ci.appveyor.com/api/projects/status/github/vinniefalco/json?branch=develop&svg=true)](https://ci.appveyor.com/project/vinniefalco/json/branch/develop) | [![Build Status](https://dev.azure.com/vinniefalco/json/_apis/build/status/pipeline?branchName=develop)](https://dev.azure.com/vinniefalco/json/_build/latest?definitionId=6&branchName=master) | [![codecov](https://codecov.io/gh/vinniefalco/json/branch/develop/graph/badge.svg)](https://codecov.io/gh/vinniefalco/json/branch/develop) | [![Documentation](https://img.shields.io/badge/docs-develop-brightgreen.svg)](http://vinniefalco.github.com/doc/json/index.html) | [![Matrix](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/json.html) ## This is currently **NOT** an official Boost library. diff --git a/doc/Jamfile b/doc/Jamfile index ee9eb056..5839640a 100644 --- a/doc/Jamfile +++ b/doc/Jamfile @@ -16,6 +16,10 @@ import doxygen ; import modules ; import saxonhe ; +local broot = [ os.environ BOOST_ROOT ] ; + +path-constant out : . ; + #------------------------------------------------------------------------------- # # Build the list of header files that Doxygen will scan. We need @@ -78,9 +82,6 @@ make index.xml rule make_doxygen_xml ( targets * : sources * : properties * ) { - LIB_DIR on $(targets) = - [ path.native [ path.parent [ path.root - [ on $(sources[1]) return $(SEARCH) ] [ path.pwd ] ] ] ] ; } if [ os.name ] = NT @@ -145,20 +146,40 @@ install qbk : reference.qbk ; # Produce the Boost.Book XML from the QuickBook # +install stylesheets + : + $(broot)/doc/src/boostbook.css + : + $(out)/html + ; + +explicit stylesheets ; + install images : + [ glob $(broot)/doc/src/images/*.png ] + images/doc-logo.png : - html/json/images + $(out)/html/images ; explicit images ; +install callouts + : + [ glob $(broot)/doc/src/images/callouts/*.png ] + : + $(out)/html/images/callouts + ; + +explicit callout ; + xml json_doc : qbk/main.qbk : - images qbk +# $(broot)/tools/boostbook/dtd ; explicit json_doc ; @@ -173,16 +194,19 @@ boostbook json : json_doc : - boost.root=../../../.. - chapter.autolabel=1 - chunk.section.depth=8 # Depth to which sections should be chunked + boost.image.src=images/doc-logo.png + boost.image.alt="Boost.JSON Logo" + boost.image.w=880 + boost.image.h=80 + boost.graphics.root=images/ + html.stylesheet=boostbook.css + nav.layout=none + chapter.autolabel=0 chunk.first.sections=1 # Chunk the first top-level section? - toc.section.depth=8 # How deep should recursive sections appear in the TOC? - toc.max.depth=8 # How many levels should be created for each TOC? - generate.section.toc.level=8 # Control depth of TOC generation in sections - generate.toc="chapter toc,title section nop reference nop" - ../../../tools/boostbook/dtd + chunk.section.depth=8 # Depth to which sections should be chunked + generate.toc="chapter nop section nop" : + stylesheets images ; diff --git a/doc/images/doc-logo.png b/doc/images/doc-logo.png new file mode 100644 index 00000000..929d59c4 Binary files /dev/null and b/doc/images/doc-logo.png differ diff --git a/doc/qbk/benchmarks.qbk b/doc/qbk/benchmarks.qbk new file mode 100644 index 00000000..284e4cce --- /dev/null +++ b/doc/qbk/benchmarks.qbk @@ -0,0 +1,52 @@ +[/ + Copyright (c) 2019 Vinnie Falco (vinnie dot falco at gmail dot com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + Official repository: https://github.com/vinniefalco/json +] + +[section Benchmarks] +[block''''''] + +[/-----------------------------------------------------------------------------] + +[table +[ [Small Document] [Large Document] ] +[[ +``` +Boost.JSON parse 55952763 bytes in 234ms +Boost.JSON parse 55952763 bytes in 232ms +Boost.JSON parse 55952763 bytes in 231ms +rapidjson parse 55952763 bytes in 239ms +rapidjson parse 55952763 bytes in 240ms +rapidjson parse 55952763 bytes in 239ms +nlohmann parse 55952763 bytes in 495ms +nlohmann parse 55952763 bytes in 491ms +nlohmann parse 55952763 bytes in 494ms +tao-json parse 55952763 bytes in 2178ms +tao-json parse 55952763 bytes in 2069ms +tao-json parse 55952763 bytes in 2056ms +``` +][ +``` +Boost.JSON parse 488889121 bytes in 1820ms +Boost.JSON parse 488889121 bytes in 1831ms +Boost.JSON parse 488889121 bytes in 1835ms +rapidjson parse 488889121 bytes in 1860ms +rapidjson parse 488889121 bytes in 1886ms +rapidjson parse 488889121 bytes in 1828ms +nlohmann parse 488889121 bytes in 4195ms +nlohmann parse 488889121 bytes in 4241ms +nlohmann parse 488889121 bytes in 4320ms +tao-json parse 488889121 bytes in 22952ms +tao-json parse 488889121 bytes in 23265ms +tao-json parse 488889121 bytes in 23117ms +``` +]] +] + +[/-----------------------------------------------------------------------------] + +[endsect] diff --git a/doc/qbk/comparison.qbk b/doc/qbk/comparison.qbk new file mode 100644 index 00000000..5ed80b5b --- /dev/null +++ b/doc/qbk/comparison.qbk @@ -0,0 +1,214 @@ +[/ + Copyright (c) 2019 Vinnie Falco (vinnie dot falco at gmail dot com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + Official repository: https://github.com/vinniefalco/json +] + +[section:comparison Comparison to Other Libraries] +[block''''''] + +We use these criteria for evaluating a library's JSON container (the +"value type") for suitability as a vocabulary type: + +* The value type declaration is completely decoupled + from other facilities such as parsing and serialization. + +* The value type is not a class template + +[/-----------------------------------------------------------------------------] + +[heading Comparison to nlohmann JSON] + +* Value Type: [@https://github.com/nlohmann/json/blob/00cb98a3d170161711ab912ae6acefba31f29f75/include/nlohmann/json.hpp#L165 `nlohmann::basic_json`] + +``` +template< + template class ObjectType, + template class ArrayType, + class StringType, + class BooleanType, + class NumberIntegerType, + class NumberUnsignedType, + class NumberFloatType, + template class AllocatorType, + template class JSONSerializer + > +class basic_json +{ + private: + .... + friend ::nlohmann::detail::parser; + friend ::nlohmann::detail::serializer; +... + +``` + +* __bad__ `basic_json` is a class template. Libraries must agree on + all the template parameters to be fully interoperable. + +* __bad__ Too much customization. We struggle to see a use case for + making `BooleanType` anything other than `bool`. + +* __bad__ Poor separation of concerns. The `basic_json` container + declaration needlessly conflates parsing and serialization APIs. + +* __bad__ Limited allocator support. Only stateless allocators are + allowed, which rules out the most important type of allocator, a + local arena-based implementation. + +* __bad__ No incremental parsing, no incremental serialization. + +* __bad__ Mediocre parsing performance. + +* __good__ Full-featured, including JSON Pointer, CBOR, and others. + +[/-----------------------------------------------------------------------------] + +[heading Comparison to RapidJSON] + +* Value Type: [@https://github.com/Tencent/rapidjson/blob/bb5f966b9939d6cdfbac3462a0410e185099b3af/include/rapidjson/document.h#L608 `rapidjson::GenericValue`] + +``` +template > +class GenericValue; + +template +class GenericArray; + +template +class GenericObject; +``` + +* __bad__ The value type is a class template. + +* __bad__ The value type is not __CopyConstructible__ + +* __bad__ The interface of the array and object types are considerably + different from their standard library equivalents, and not idiomatic. + +* __bad__ No incremental parsing, no incremental serialization. + +* __good__ Parsing performance is excellent. + +[/-----------------------------------------------------------------------------] + +[heading Comparison to TaoCPP JSON] + +* Value Type: [@https://github.com/taocpp/json/blob/e0944b3b2686a6b9749c16dd06f72445bf7eef0a/include/tao/json/basic_value.hpp#L38 `tao::json::basic_value`] + +*https://github.com/taocpp/json + +``` +template< template< typename... > class Traits > +class basic_value +{ + ... +public: + using array_t = std::vector< basic_value >; + using object_t = std::map< std::string, basic_value, std::less<> >; +... +``` + +The `basic_value` type uses the `Traits` as a template parameter, where the +traits provide specializations to convert each supported native or user defined +type to and from JSON. This makes the value type unsuitable as a vocabulary +type because the traits for a `basic_value` exported by two different +libraries which each has added support for their own types, are not the same. + +* __bad__ C++17 or later is required. + +* __bad__ No allocator support. + +* __bad__ The value type is a class template. + +* __bad__ The array and object container interfaces change + depending on which version of the standard C++ library is used. + +* __bad__ The performance of the library changes significantly + depending on which version of the standard library is used. + +* __bad__ Parsing performance is the worst surveyed, by a large margin. + +* __bad__ No incremental parsing, no incremental serialization. + +[/-----------------------------------------------------------------------------] + +[heading Comparison to JSONCPP] + +* Value Type: [@https://github.com/open-source-parsers/jsoncpp/blob/41ffff01d39085222280791a23451d3e852b06c2/include/json/value.h#L188 `Json::Value`] + +[/-----------------------------------------------------------------------------] + +[heading Comparison to Ciere Labs json_spirit] + +* Value Type: [@https://github.com/cierelabs/json_spirit/blob/e885dc55054bf0e6ef250322923396aed4c3ece7/ciere/json/value.hpp#L72 `ciere::json::value`] + + +``` + typedef std::string string_t; + typedef std::map object_t; + typedef std::pair object_member_t; + typedef boost::container::stable_vector array_t; + + class value : public boost::spirit::extended_variant< + null_t, bool_t, string_t, int_t, double_t, object_t, array_t> + { ... }; + +``` + +* No allocator support. + +[/-----------------------------------------------------------------------------] + +[heading Comparison to SIMD JSON] + +https://github.com/lemire/simdjson + +``` +class ParsedJson; +``` + +This is quite an interesting data structure, which is optimized to work well +with the SIMD parser. It makes very good design choices for the intended +use-case. However it is not well suited as a vocabulary type due to the +necessary limitations. + +* Read-only +* Sequential access only, via `ParsedJson::BasicIterator` +* Can only be realistically populated by the provided SIMD JSON parser. + +[/-----------------------------------------------------------------------------] + +[heading Comparison to trial.protocol] + +https://github.com/breese/trial.protocol + +``` +template