// // Copyright (c) 2018-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 // //#define RAPIDJSON_SSE42 #include "lib/nlohmann/single_include/nlohmann/json.hpp" #include "lib/rapidjson/include/rapidjson/rapidjson.h" #include "lib/rapidjson/include/rapidjson/document.h" #include "lib/rapidjson/include/rapidjson/writer.h" #include "lib/rapidjson/include/rapidjson/stringbuffer.h" #include #include #include #include #include #include #include /* References https://github.com/nst/JSONTestSuite http://seriot.ch/parsing_json.php */ namespace beast = boost::beast; namespace boost { namespace json { using clock_type = std::chrono::steady_clock; using string_view = boost::string_view; beast::unit_test::dstream dout{std::cerr}; //---------------------------------------------------------- class any_impl { public: virtual ~any_impl() = default; virtual string_view name() const noexcept = 0; virtual void parse(string_view s, int repeat) const = 0; virtual void serialize(string_view s, int repeat) const = 0; }; //---------------------------------------------------------- class boost_impl : public any_impl { public: string_view name() const noexcept override { return "boost(block)"; } void parse( string_view s, int repeat) const override { while(repeat--) { scoped_storage< block_storage> ss; json::parse(s, ss); } } void serialize( string_view s, int repeat) const override { scoped_storage< block_storage> ss; auto jv = json::parse(s, ss); while(repeat--) to_string(jv); } }; //---------------------------------------------------------- class boost_default_impl : public any_impl { public: string_view name() const noexcept override { return "boost(default)"; } void parse( string_view s, int repeat) const override { while(repeat--) json::parse(s); } void serialize( string_view s, int repeat) const override { auto jv = json::parse(s); while(repeat--) to_string(jv); } }; //---------------------------------------------------------- class boost_vec_impl : public any_impl { struct vec_parser : basic_parser { std::size_t n_ = std::size_t(-1); char buf[256]; std::vector vec_; void on_stack_info( stack& s) noexcept override { s.base = buf; s.capacity = sizeof(buf); } void on_stack_grow( stack&, unsigned, error_code& ec) override { ec = error::too_deep; } void on_document_begin( error_code&) override { } void on_object_begin( error_code&) override { } void on_object_end( error_code&) override { } void on_array_begin( error_code&) override { } void on_array_end( error_code&) override { } void on_key_data( string_view, error_code&) override { } void on_key_end( string_view, error_code&) override { } void on_string_data( string_view, error_code&) override { } void on_string_end( string_view, error_code&) override { } void on_number( ieee_decimal dec, error_code&) override { vec_.emplace_back(dec); } void on_bool( bool, error_code&) override { } void on_null(error_code&) override { } public: vec_parser() = default; explicit vec_parser( std::size_t n) : n_(n) { } }; public: string_view name() const noexcept override { return "boost(vector)"; } void parse( string_view s, int repeat) const override { while(repeat--) { vec_parser p; error_code ec; p.write(s.data(), s.size(), ec); } } void serialize( string_view, int) const override { } }; //---------------------------------------------------------- struct rapidjson_impl : public any_impl { string_view name() const noexcept override { return "rapidjson"; } void parse(string_view s, int repeat) const override { while(repeat--) { rapidjson::Document d; d.Parse(s.data(), s.size()); } } void serialize(string_view s, int repeat) const override { rapidjson::Document d; d.Parse(s.data(), s.size()); while(repeat--) { rapidjson::StringBuffer st; st.Clear(); rapidjson::Writer< rapidjson::StringBuffer> wr(st); d.Accept(wr); } } }; //---------------------------------------------------------- struct nlohmann_impl : public any_impl { string_view name() const noexcept override { return "nlohmann"; } void parse(string_view s, int repeat) const override { while(repeat--) nlohmann::json::parse( s.begin(), s.end()); } void serialize(string_view, int) const override { } }; //---------------------------------------------------------- struct file_item { string_view name; std::string text; }; using file_list = std::vector; std::string load_file(char const* path) { FILE* f = fopen(path, "rb"); fseek(f, 0, SEEK_END); auto const size = ftell(f); std::string s; s.resize(size); fseek(f, 0, SEEK_SET); fread(&s[0], 1, size, f); fclose(f); return s; } void benchParse( file_list const& vs, std::vector> const& vi) { for(unsigned i = 0; i < vs.size(); ++i) { dout << "Parse File " << std::to_string(i+1) << " " << vs[i].name << " (" << std::to_string(vs[i].text.size()) << " bytes)" << std::endl; for(unsigned j = 0; j < vi.size(); ++j) { for(unsigned k = 0; k < 15; ++k) { auto const when = clock_type::now(); vi[j]->parse(vs[i].text, 250); auto const ms = std::chrono::duration_cast< std::chrono::milliseconds>( clock_type::now() - when).count(); if(k > 9) dout << " " << vi[j]->name() << ": " << std::to_string(ms) << "ms" << std::endl; } } dout << std::endl; } } void benchSerialize( file_list const& vs, std::vector> const& vi) { for(unsigned i = 0; i < vs.size(); ++i) { dout << "Serialize File " << std::to_string(i+1) << " " << vs[i].name << " (" << std::to_string(vs[i].text.size()) << " bytes)" << std::endl; for(unsigned j = 0; j < vi.size(); ++j) { for(unsigned k = 0; k < 15; ++k) { auto const when = clock_type::now(); vi[j]->serialize(vs[i].text, 1000); auto const ms = std::chrono::duration_cast< std::chrono::milliseconds>( clock_type::now() - when).count(); if(k > 9) dout << " " << vi[j]->name() << ": " << std::to_string(ms) << "ms" << std::endl; } } dout << std::endl; } } } // json } // boost int main( int const argc, char const* const* const argv) { using namespace boost::json; file_list vs; if(argc > 1) { vs.reserve(argc - 1); for(int i = 1; i < argc; ++i) vs.emplace_back( file_item{argv[i], load_file(argv[i])}); } try { std::vector> vi; vi.reserve(10); //vi.emplace_back(new boost_vec_impl); //vi.emplace_back(new boost_default_impl); vi.emplace_back(new boost_impl); vi.emplace_back(new rapidjson_impl); //vi.emplace_back(new nlohmann_impl); benchParse(vs, vi); benchSerialize(vs, vi); } catch(system_error const& se) { dout << se.what() << std::endl; } return 0; } /* Parse File 1 array.json (609414 bytes) boost(block): 397ms boost(block): 398ms boost(block): 393ms boost(block): 394ms boost(block): 396ms rapidjson: 380ms rapidjson: 378ms rapidjson: 381ms rapidjson: 378ms rapidjson: 378ms Parse File 2 arrays.json (1461524 bytes) boost(block): 1517ms boost(block): 1517ms boost(block): 1512ms boost(block): 1521ms boost(block): 1511ms rapidjson: 937ms rapidjson: 936ms rapidjson: 937ms rapidjson: 936ms rapidjson: 938ms Parse File 3 strings.json (1016132 bytes) boost(block): 49ms boost(block): 49ms boost(block): 49ms boost(block): 49ms boost(block): 49ms rapidjson: 451ms rapidjson: 449ms rapidjson: 451ms rapidjson: 450ms rapidjson: 452ms Parse File 4 twitter.json (646995 bytes) boost(block): 762ms boost(block): 762ms boost(block): 762ms boost(block): 761ms boost(block): 761ms rapidjson: 434ms rapidjson: 436ms rapidjson: 453ms rapidjson: 432ms rapidjson: 434ms Parse File 5 citm_catalog.json (1777672 bytes) boost(block): 1487ms boost(block): 1495ms boost(block): 1488ms boost(block): 1492ms boost(block): 1490ms rapidjson: 903ms rapidjson: 903ms rapidjson: 903ms rapidjson: 902ms rapidjson: 903ms Parse File 6 canada.json (2251060 bytes) boost(block): 4282ms boost(block): 4247ms boost(block): 4252ms boost(block): 4234ms boost(block): 4257ms rapidjson: 1418ms rapidjson: 1417ms rapidjson: 1417ms rapidjson: 1417ms rapidjson: 1417ms Serialize File 1 array.json (609414 bytes) boost(block): 854ms boost(block): 853ms boost(block): 851ms boost(block): 853ms boost(block): 853ms rapidjson: 785ms rapidjson: 785ms rapidjson: 783ms rapidjson: 785ms rapidjson: 785ms Serialize File 2 arrays.json (1461524 bytes) boost(block): 1269ms boost(block): 1259ms boost(block): 1257ms boost(block): 1259ms boost(block): 1260ms rapidjson: 3112ms rapidjson: 3110ms rapidjson: 3109ms rapidjson: 3109ms rapidjson: 3114ms Serialize File 3 strings.json (1016132 bytes) boost(block): 582ms boost(block): 584ms boost(block): 582ms boost(block): 585ms boost(block): 584ms rapidjson: 2072ms rapidjson: 2072ms rapidjson: 2073ms rapidjson: 2074ms rapidjson: 2074ms Serialize File 4 twitter.json (646995 bytes) boost(block): 658ms boost(block): 659ms boost(block): 659ms boost(block): 659ms boost(block): 659ms rapidjson: 871ms rapidjson: 871ms rapidjson: 872ms rapidjson: 872ms rapidjson: 872ms Serialize File 5 citm_catalog.json (1777672 bytes) boost(block): 1049ms boost(block): 1049ms boost(block): 1048ms boost(block): 1047ms boost(block): 1047ms rapidjson: 898ms rapidjson: 896ms rapidjson: 898ms rapidjson: 898ms rapidjson: 898ms Serialize File 6 canada.json (2251060 bytes) boost(block): 10521ms boost(block): 10616ms boost(block): 10560ms boost(block): 10553ms boost(block): 10446ms rapidjson: 10788ms rapidjson: 10776ms rapidjson: 10784ms rapidjson: 10805ms rapidjson: 10789ms */