diff --git a/bench/Jamfile b/bench/Jamfile index 21f8e0649..d05a6ba06 100644 --- a/bench/Jamfile +++ b/bench/Jamfile @@ -35,6 +35,7 @@ exe bench : /boost/json//boost_json : ../test + ../example $(has_nlohmann_json)BOOST_JSON_HAS_NLOHMANN_JSON $(has_rapidjson)BOOST_JSON_HAS_RAPIDJSON ; diff --git a/bench/bench.cpp b/bench/bench.cpp index 2f4337443..eedb1d6e1 100644 --- a/bench/bench.cpp +++ b/bench/bench.cpp @@ -39,6 +39,8 @@ #include #include "test_suite.hpp" +#include "canada.hpp" +#include "citm_catalog.hpp" /* References @@ -48,7 +50,7 @@ */ std::string s_tests = "ps"; -std::string s_impls = "busorn"; +std::string s_impls = "busodrn"; std::size_t s_trials = 6; std::string s_branch = ""; std::string s_alloc = "p"; @@ -747,6 +749,173 @@ class boost_operator_impl : public any_impl } }; +class boost_direct_impl : public any_impl +{ +private: + struct canada_support + { + using type = canada; + static constexpr char const* const name = "canada.json"; + }; + struct citm_catalog_support + { + using type = citm_catalog; + static constexpr char const* const name = "citm_catalog.json"; + }; + using supported_files = mp11::mp_list< + canada_support, citm_catalog_support>; + + static + int + find_supported_file(file_item const& fi) + { + int result = -1; + using N = mp11::mp_size; + mp11::mp_for_each>([&](auto index) + { + using supported_file = mp11::mp_at_c; + std::size_t const name_len = std::strlen(supported_file::name); + + std::size_t pos = fi.name.rfind( + supported_file::name, string_view::npos, name_len); + if(pos == string_view::npos) + return; + if( pos + name_len != fi.name.size() ) + return; + if( pos != 0 && fi.name[pos - 1] != '/' + && fi.name[pos - 1] != '\\' ) + { + return; + } + + result = static_cast(index); + }); + return result; + } + +public: + boost_direct_impl(bool with_file_io, parse_options const& popts) + : any_impl("boost (direct)", true, false, with_file_io, popts) + {} + + clock_type::duration + parse_string(file_item const& fi, std::size_t repeat) const override + { + auto const i = find_supported_file(fi); + if( i < 0 ) + return clock_type::duration::zero(); + + using N = mp11::mp_size; + return mp11::mp_with_index(i, [&](auto index) + { + using supported_file = mp11::mp_at_c; + + auto const start = clock_type::now(); + while(repeat--) + { + using data_type = typename supported_file::type; + data_type v; + system::error_code ec; + parser_for p(get_parse_options(), &v); + + auto const n = p.write_some( + false, fi.text.data(), fi.text.size(), ec ); + if( !ec.failed() && n < fi.text.size() ) + ec = error::extra_data; + if( ec.failed() ) + throw system::system_error( ec ); + } + return clock_type::now() - start; + }); + } + + clock_type::duration + parse_file(file_item const& fi, std::size_t repeat) const override + { + auto const i = find_supported_file(fi); + if( i < 0 ) + return clock_type::duration::zero(); + + using N = mp11::mp_size; + return mp11::mp_with_index(i, [&](auto index) + { + using supported_file = mp11::mp_at_c; + + auto const start = clock_type::now(); + char s[ BOOST_JSON_STACK_BUFFER_SIZE]; + while(repeat--) + { + using data_type = typename supported_file::type; + data_type v; + system::error_code ec; + parser_for p(get_parse_options(), &v); + + FILE* f = fopen(fi.name.data(), "rb"); + + while( true ) + { + std::size_t const sz = fread(s, 1, sizeof(s), f); + if( ferror(f) ) + break; + + p.write_some(true, s, sz, ec); + if( ec.failed() ) + throw system::system_error(ec); + + if( feof(f) ) + break; + } + + if( !p.done() ) + { + p.write_some(false, nullptr, 0, ec); + if( ec.failed() ) + throw system::system_error(ec); + } + + fclose(f); + } + return clock_type::now() - start; + }); + } + + clock_type::duration + serialize_string(file_item const& fi, std::size_t repeat) const override + { + auto const i = find_supported_file(fi); + if( i < 0 ) + return clock_type::duration::zero(); + + using N = mp11::mp_size; + return mp11::mp_with_index(i, [&](auto index) + { + using supported_file = mp11::mp_at_c; + typename supported_file::type v; + json::parse_into(v, fi.text); + + auto const start = clock_type::now(); + serializer sr; + string out; + out.reserve(512); + while(repeat--) + { + sr.reset(&v); + out.clear(); + for(;;) + { + auto const sv = sr.read( + out.end(), out.capacity() - out.size() ); + out.grow( sv.size() ); + if( sr.done() ) + break; + out.reserve( out.capacity() + 1 ); + } + } + return clock_type::now() - start; + }); + } +}; + //---------------------------------------------------------- #ifdef BOOST_JSON_HAS_RAPIDJSON @@ -988,6 +1157,10 @@ bool add_impl(impl_list & vi, char kind, char alloc, char io, char num) is_pool, with_file_io, popts); break; + case 'd': + impl = std::make_unique(with_file_io, popts); + break; + #ifdef BOOST_JSON_HAS_RAPIDJSON case 'r': if(is_pool) @@ -1058,35 +1231,36 @@ main( std::cerr << "Usage: bench [options...] ...\n" "\n" - "Options: -t:[p][s] Test parsing, serialization or both\n" - " (default both)\n" - " -i:[b][u][s][o][r][n] Test the specified implementations\n" - " (b: Boost.JSON)\n" - " (u: Boost.JSON, null parser)\n" - " (s: Boost.JSON, convenient functions)\n" - " (o: Boost.JSON, stream operators)\n" + "Options: -t:[p][s] Test parsing, serialization or both\n" + " (default both)\n" + " -i:[b][u][s][o][d][r][n] Test the specified implementations\n" + " (b: Boost.JSON)\n" + " (u: Boost.JSON, null parser)\n" + " (s: Boost.JSON, convenient functions)\n" + " (o: Boost.JSON, stream operators)\n" + " (d: Boost.JSON, direct conversion)\n" #ifdef BOOST_JSON_HAS_RAPIDJSON - " (r: RapidJSON)\n" + " (r: RapidJSON)\n" #endif // BOOST_JSON_HAS_RAPIDJSON #ifdef BOOST_JSON_HAS_NLOHMANN_JSON - " (n: nlohmann/json)\n" + " (n: nlohmann/json)\n" #endif // BOOST_JSON_HAS_NLOHMANN_JSON - " (default all)\n" - " -a:(p|d) Memory allocation strategy\n" - " (p: memory pool)\n" - " (d: default strategy)\n" - " (default memory pool)\n" - " -n: Number of trials (default 6)\n" - " -b: Branch label for boost implementations\n" - " -m:(i|p|n) Number parsing mode\n" - " (i: imprecise)\n" - " (p: precise)\n" - " (n: none)\n" - " (default imprecise)\n" - " -f:(y|n) Include file IO into consideration when testing parsers\n" - " (y: yes)\n" - " (n: no)\n" - " (default no)\n" + " (default all)\n" + " -a:[p][d] Memory allocation strategy\n" + " (p: memory pool)\n" + " (d: default strategy)\n" + " (default memory pool)\n" + " -n: Number of trials (default 6)\n" + " -b: Branch label for boost implementations\n" + " -m:[i][p][n] Number parsing mode\n" + " (i: imprecise)\n" + " (p: precise)\n" + " (n: none)\n" + " (default imprecise)\n" + " -f:[y][n] Include file IO into consideration when testing parsers\n" + " (y: yes)\n" + " (n: no)\n" + " (default no)\n" ; return 4; diff --git a/example/canada.hpp b/example/canada.hpp new file mode 100644 index 000000000..29d184802 --- /dev/null +++ b/example/canada.hpp @@ -0,0 +1,45 @@ +// +// Copyright (c) 2021 Peter Dimov +// +// 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/boostorg/json +// + +#ifndef BOOST_JSON_EXAMPLE_CANADA_HPP +#define BOOST_JSON_EXAMPLE_CANADA_HPP + +#include + +#include +#include +#include +#include + +struct geometry_type +{ + std::string type; + std::vector< std::vector> > coordinates; +}; + +BOOST_DESCRIBE_STRUCT(geometry_type, (), (type, coordinates)) + +struct feature +{ + std::string type; + std::map properties; + geometry_type geometry; +}; + +BOOST_DESCRIBE_STRUCT(feature, (), (type, properties, geometry)) + +struct canada +{ + std::string type; + std::vector features; +}; + +BOOST_DESCRIBE_STRUCT(canada, (), (type, features)) + +#endif // BOOST_JSON_EXAMPLE_CANADA_HPP diff --git a/example/citm_catalog.hpp b/example/citm_catalog.hpp new file mode 100644 index 000000000..20139e3b9 --- /dev/null +++ b/example/citm_catalog.hpp @@ -0,0 +1,91 @@ +// +// Copyright (c) 2021 Peter Dimov +// +// 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/boostorg/json +// + +#ifndef BOOST_JSON_EXAMPLE_CITM_CATALOG_HPP +#define BOOST_JSON_EXAMPLE_CITM_CATALOG_HPP + +#include +#include +#include +#include + +struct event +{ + std::nullptr_t description; + unsigned long long id; + boost::variant2::variant logo; + std::string name; + std::vector subTopicIds; + std::nullptr_t subjectCode; + std::nullptr_t subtitle; + std::vector topicIds; +}; + +BOOST_DESCRIBE_STRUCT(event, (), (description, id, logo, name, subTopicIds, subjectCode, subtitle, topicIds)) + +struct price +{ + unsigned amount; + unsigned long long audienceSubCategoryId; + unsigned long long seatCategoryId; +}; + +BOOST_DESCRIBE_STRUCT(price, (), (amount, audienceSubCategoryId, seatCategoryId)) + +struct area +{ + unsigned long long areaId; + std::vector blockIds; +}; + +BOOST_DESCRIBE_STRUCT(area, (), (areaId, blockIds)) + +struct seatCategory +{ + std::vector areas; + unsigned long long seatCategoryId; +}; + +BOOST_DESCRIBE_STRUCT(seatCategory, (), (areas, seatCategoryId)) + +struct performance +{ + unsigned long long eventId; + unsigned long long id; + boost::variant2::variant logo; + std::nullptr_t name; + std::vector prices; + std::vector seatCategories; + std::nullptr_t seatMapImage; + unsigned long long start; + std::string venueCode; +}; + +BOOST_DESCRIBE_STRUCT(performance, (), (eventId, id, logo, name, prices, seatCategories, seatMapImage, start, venueCode)) + +struct citm_catalog +{ + std::map areaNames; + std::map audienceSubCategoryNames; + std::map blockNames; + std::map events; + std::vector performances; + std::map seatCategoryNames; + std::map subTopicNames; + std::map subjectNames; + std::map topicNames; + std::map> topicSubTopics; + std::map venueNames; +}; + +BOOST_DESCRIBE_STRUCT(citm_catalog, (), + (areaNames, audienceSubCategoryNames, blockNames, events, performances, + seatCategoryNames, subTopicNames, subjectNames, topicNames, topicSubTopics, venueNames)) + +#endif // BOOST_JSON_EXAMPLE_CITM_CATALOG_HPP diff --git a/example/parse_into_canada.cpp b/example/parse_into_canada.cpp index 7489f43ff..d705753da 100644 --- a/example/parse_into_canada.cpp +++ b/example/parse_into_canada.cpp @@ -29,35 +29,8 @@ int main() {} #include #include #include -#include -#include -#include -#include -struct geometry_type -{ - std::string type; - std::vector< std::vector> > coordinates; -}; - -BOOST_DESCRIBE_STRUCT(geometry_type, (), (type, coordinates)) - -struct feature -{ - std::string type; - std::map properties; - geometry_type geometry; -}; - -BOOST_DESCRIBE_STRUCT(feature, (), (type, properties, geometry)) - -struct canada -{ - std::string type; - std::vector features; -}; - -BOOST_DESCRIBE_STRUCT(canada, (), (type, features)) +#include "canada.hpp" using namespace std::chrono_literals; diff --git a/example/parse_into_citm_catalog.cpp b/example/parse_into_citm_catalog.cpp index 7b1c8ee19..dcc941a81 100644 --- a/example/parse_into_citm_catalog.cpp +++ b/example/parse_into_citm_catalog.cpp @@ -28,83 +28,7 @@ int main() {} #include #include #include -#include -#include -#include -#include - -struct event -{ - std::nullptr_t description; - unsigned long long id; - boost::variant2::variant logo; - std::string name; - std::vector subTopicIds; - std::nullptr_t subjectCode; - std::nullptr_t subtitle; - std::vector topicIds; -}; - -BOOST_DESCRIBE_STRUCT(event, (), (description, id, logo, name, subTopicIds, subjectCode, subtitle, topicIds)) - -struct price -{ - unsigned amount; - unsigned long long audienceSubCategoryId; - unsigned long long seatCategoryId; -}; - -BOOST_DESCRIBE_STRUCT(price, (), (amount, audienceSubCategoryId, seatCategoryId)) - -struct area -{ - unsigned long long areaId; - std::vector blockIds; -}; - -BOOST_DESCRIBE_STRUCT(area, (), (areaId, blockIds)) - -struct seatCategory -{ - std::vector areas; - unsigned long long seatCategoryId; -}; - -BOOST_DESCRIBE_STRUCT(seatCategory, (), (areas, seatCategoryId)) - -struct performance -{ - unsigned long long eventId; - unsigned long long id; - boost::variant2::variant logo; - std::nullptr_t name; - std::vector prices; - std::vector seatCategories; - std::nullptr_t seatMapImage; - unsigned long long start; - std::string venueCode; -}; - -BOOST_DESCRIBE_STRUCT(performance, (), (eventId, id, logo, name, prices, seatCategories, seatMapImage, start, venueCode)) - -struct citm_catalog -{ - std::map areaNames; - std::map audienceSubCategoryNames; - std::map blockNames; - std::map events; - std::vector performances; - std::map seatCategoryNames; - std::map subTopicNames; - std::map subjectNames; - std::map topicNames; - std::map> topicSubTopics; - std::map venueNames; -}; - -BOOST_DESCRIBE_STRUCT(citm_catalog, (), - (areaNames, audienceSubCategoryNames, blockNames, events, performances, - seatCategoryNames, subTopicNames, subjectNames, topicNames, topicSubTopics, venueNames)) +#include "citm_catalog.hpp" using namespace std::chrono_literals;