From 4414f94cd5b6f1f5d46677b96f4bee7096b64f59 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Sun, 23 Jul 2017 23:02:24 +0200 Subject: [PATCH 01/10] :hammer: using input/output adapters for CBOR and MessagePack - You can now pass a reference to a vector to the to_cbor and to_msgpack functions. The output will be written (appended) to the vector. #476 - You can now pass an output stream with uint8_t character type to the to_cbor and to_msgpack functions. #477 - You can now read from uint8_t */size in the to_cbor and to_msgpack functions. An input adapter will be created from this pair, so you need to use braces. #478 --- src/json.hpp | 90 ++++++++++++++++++++++++----------- test/src/unit-cbor.cpp | 62 ++++++++++++++++++++---- test/src/unit-convenience.cpp | 2 +- test/src/unit-msgpack.cpp | 61 ++++++++++++++++++++---- 4 files changed, 168 insertions(+), 47 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 63f5d2b8..7c4fec5b 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -1443,8 +1443,15 @@ class input_adapter : ia(std::make_shared>(i)) {} /// input adapter for buffer - input_adapter(const char* b, std::size_t l) - : ia(std::make_shared(b, l)) {} + template ::value and + std::is_integral< + typename std::remove_pointer::type>::value and + sizeof(typename std::remove_pointer::type) == 1, + int>::type = 0> + input_adapter(CharT b, std::size_t l) + : ia(std::make_shared(reinterpret_cast(b), l)) {} // derived support @@ -4546,21 +4553,20 @@ class json_reverse_iterator : public std::reverse_iterator ///////////////////// /// abstract output adapter interface -template class output_adapter +template struct output_adapter_protocol { - public: virtual void write_character(CharType c) = 0; virtual void write_characters(const CharType* s, std::size_t length) = 0; - virtual ~output_adapter() = default; + virtual ~output_adapter_protocol() = default; }; /// a type to simplify interfaces template -using output_adapter_t = std::shared_ptr>; +using output_adapter_t = std::shared_ptr>; /// output adapter for byte vectors template -class output_vector_adapter : public output_adapter +class output_vector_adapter : public output_adapter_protocol { public: explicit output_vector_adapter(std::vector& vec) : v(vec) {} @@ -4581,7 +4587,7 @@ class output_vector_adapter : public output_adapter /// output adapter for output streams template -class output_stream_adapter : public output_adapter +class output_stream_adapter : public output_adapter_protocol { public: explicit output_stream_adapter(std::basic_ostream& s) : stream(s) {} @@ -4602,10 +4608,10 @@ class output_stream_adapter : public output_adapter /// output adapter for basic_string template -class output_string_adapter : public output_adapter +class output_string_adapter : public output_adapter_protocol { public: - explicit output_string_adapter(std::string& s) : str(s) {} + explicit output_string_adapter(std::basic_string& s) : str(s) {} void write_character(CharType c) override { @@ -4621,23 +4627,26 @@ class output_string_adapter : public output_adapter std::basic_string& str; }; -template struct output_adapter_factory +template +class output_adapter { - static std::shared_ptr> - create(std::vector& vec) + public: + output_adapter(std::vector& vec) + : oa(std::make_shared>(vec)) {} + + output_adapter(std::basic_ostream& s) + : oa(std::make_shared>(s)) {} + + output_adapter(std::basic_string& s) + : oa(std::make_shared>(s)) {} + + operator output_adapter_t() { - return std::make_shared>(vec); + return oa; } - static std::shared_ptr> create(std::ostream& s) - { - return std::make_shared>(s); - } - - static std::shared_ptr> create(std::string& s) - { - return std::make_shared>(s); - } + private: + output_adapter_t oa = nullptr; }; ////////////////////////////// @@ -9109,7 +9118,7 @@ class basic_json const bool ensure_ascii = false) const { string_t result; - serializer s(detail::output_adapter_factory::create(result), indent_char); + serializer s(detail::output_adapter(result), indent_char); if (indent >= 0) { @@ -12783,7 +12792,7 @@ class basic_json o.width(0); // do the actual serialization - serializer s(detail::output_adapter_factory::create(o), o.fill()); + serializer s(detail::output_adapter(o), o.fill()); s.dump(j, pretty_print, false, static_cast(indentation)); return o; } @@ -13162,11 +13171,15 @@ class basic_json static std::vector to_cbor(const basic_json& j) { std::vector result; - binary_writer bw(detail::output_adapter_factory::create(result)); - bw.write_cbor(j); + to_cbor(j, result); return result; } + static void to_cbor(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_cbor(j); + } + /*! @brief create a MessagePack serialization of a given JSON value @@ -13244,11 +13257,20 @@ class basic_json static std::vector to_msgpack(const basic_json& j) { std::vector result; - binary_writer bw(detail::output_adapter_factory::create(result)); - bw.write_msgpack(j); + to_msgpack(j, result); return result; } + static void to_msgpack(const basic_json& j, detail::output_adapter o) + { + binary_writer(o).write_msgpack(j); + } + + static void to_msgpack(const basic_json& j, std::vector& result) + { + binary_writer((detail::output_adapter(result))).write_msgpack(j); + } + /*! @brief create a JSON value from a byte vector in CBOR format @@ -13343,6 +13365,11 @@ class basic_json return br.parse_cbor(); } + static basic_json from_cbor(detail::input_adapter i) + { + return binary_reader(i).parse_cbor(); + } + /*! @brief create a JSON value from a byte vector in MessagePack format @@ -13418,6 +13445,11 @@ class basic_json return br.parse_msgpack(); } + static basic_json from_msgpack(detail::input_adapter i) + { + return binary_reader(i).parse_msgpack(); + } + /// @} ////////////////////////// diff --git a/test/src/unit-cbor.cpp b/test/src/unit-cbor.cpp index 5ab6a2e2..934ce55f 100644 --- a/test/src/unit-cbor.cpp +++ b/test/src/unit-cbor.cpp @@ -1519,16 +1519,60 @@ TEST_CASE("CBOR roundtrips", "[hide]") std::ifstream f_json(filename); json j1 = json::parse(f_json); - // parse CBOR file - std::ifstream f_cbor(filename + ".cbor", std::ios::binary); - std::vector packed( - (std::istreambuf_iterator(f_cbor)), - std::istreambuf_iterator()); - json j2; - CHECK_NOTHROW(j2 = json::from_cbor(packed)); + SECTION("std::vector") + { + // parse CBOR file + std::ifstream f_cbor(filename + ".cbor", std::ios::binary); + std::vector packed( + (std::istreambuf_iterator(f_cbor)), + std::istreambuf_iterator()); + json j2; + CHECK_NOTHROW(j2 = json::from_cbor(packed)); - // compare parsed JSON values - CHECK(j1 == j2); + // compare parsed JSON values + CHECK(j1 == j2); + } + + SECTION("std::ifstream") + { + // parse CBOR file + std::ifstream f_cbor(filename + ".cbor", std::ios::binary); + json j2; + CHECK_NOTHROW(j2 = json::from_cbor(f_cbor)); + + // compare parsed JSON values + CHECK(j1 == j2); + } + + SECTION("uint8_t* and size") + { + // parse CBOR file + std::ifstream f_cbor(filename + ".cbor", std::ios::binary); + std::vector packed( + (std::istreambuf_iterator(f_cbor)), + std::istreambuf_iterator()); + json j2; + CHECK_NOTHROW(j2 = json::from_cbor({packed.data(), packed.size()})); + + // compare parsed JSON values + CHECK(j1 == j2); + } + + SECTION("output to output adapters") + { + // parse CBOR file + std::ifstream f_cbor(filename + ".cbor", std::ios::binary); + std::vector packed( + (std::istreambuf_iterator(f_cbor)), + std::istreambuf_iterator()); + + SECTION("std::vector") + { + std::vector vec; + json::to_cbor(j1, vec); + CHECK(vec == packed); + } + } } } } diff --git a/test/src/unit-convenience.cpp b/test/src/unit-convenience.cpp index cd4f9e3f..1faecce8 100644 --- a/test/src/unit-convenience.cpp +++ b/test/src/unit-convenience.cpp @@ -36,7 +36,7 @@ void check_escaped(const char* original, const char* escaped, const bool ensure_ void check_escaped(const char* original, const char* escaped, const bool ensure_ascii) { std::stringstream ss; - json::serializer s(nlohmann::detail::output_adapter_factory::create(ss), ' '); + json::serializer s(nlohmann::detail::output_adapter(ss), ' '); s.dump_escaped(original, ensure_ascii); CHECK(ss.str() == escaped); } diff --git a/test/src/unit-msgpack.cpp b/test/src/unit-msgpack.cpp index baef3e35..f4b40354 100644 --- a/test/src/unit-msgpack.cpp +++ b/test/src/unit-msgpack.cpp @@ -1292,15 +1292,60 @@ TEST_CASE("MessagePack roundtrips", "[hide]") std::ifstream f_json(filename); json j1 = json::parse(f_json); - // parse MessagePack file - std::ifstream f_msgpack(filename + ".msgpack", std::ios::binary); - std::vector packed((std::istreambuf_iterator(f_msgpack)), - std::istreambuf_iterator()); - json j2; - CHECK_NOTHROW(j2 = json::from_msgpack(packed)); + SECTION("std::vector") + { + // parse MessagePack file + std::ifstream f_msgpack(filename + ".msgpack", std::ios::binary); + std::vector packed( + (std::istreambuf_iterator(f_msgpack)), + std::istreambuf_iterator()); + json j2; + CHECK_NOTHROW(j2 = json::from_msgpack(packed)); - // compare parsed JSON values - CHECK(j1 == j2); + // compare parsed JSON values + CHECK(j1 == j2); + } + + SECTION("std::ifstream") + { + // parse MessagePack file + std::ifstream f_msgpack(filename + ".msgpack", std::ios::binary); + json j2; + CHECK_NOTHROW(j2 = json::from_msgpack(f_msgpack)); + + // compare parsed JSON values + CHECK(j1 == j2); + } + + SECTION("uint8_t* and size") + { + // parse MessagePack file + std::ifstream f_msgpack(filename + ".msgpack", std::ios::binary); + std::vector packed( + (std::istreambuf_iterator(f_msgpack)), + std::istreambuf_iterator()); + json j2; + CHECK_NOTHROW(j2 = json::from_msgpack({packed.data(), packed.size()})); + + // compare parsed JSON values + CHECK(j1 == j2); + } + + SECTION("output to output adapters") + { + // parse MessagePack file + std::ifstream f_msgpack(filename + ".msgpack", std::ios::binary); + std::vector packed( + (std::istreambuf_iterator(f_msgpack)), + std::istreambuf_iterator()); + + SECTION("std::vector") + { + std::vector vec; + json::to_msgpack(j1, vec); + CHECK(vec == packed); + } + } } } } From e6aa7003608dd0607f304f506303fafebbc65094 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 26 Jul 2017 23:44:55 +0200 Subject: [PATCH 02/10] :hammer: cleanup --- src/json.hpp | 885 +++++++++++++++++++++++---------------------------- 1 file changed, 398 insertions(+), 487 deletions(-) diff --git a/src/json.hpp b/src/json.hpp index 7c4fec5b..69ecab0f 100644 --- a/src/json.hpp +++ b/src/json.hpp @@ -119,28 +119,28 @@ template struct adl_serializer; // forward declaration of basic_json (required to split the class) -template