#pragma once #include // copy #include // size_t #include // streamsize #include // back_inserter #include // shared_ptr, make_shared #include // basic_ostream #include // basic_string #include // vector namespace nlohmann { namespace detail { /// abstract output adapter interface template struct output_adapter_protocol { virtual void write_character(CharType c) = 0; virtual void write_characters(const CharType* s, std::size_t length) = 0; virtual void write_characters_at(std::size_t position, const CharType* s, std::size_t length) = 0; virtual std::size_t reserve_characters(std::size_t length) = 0; virtual ~output_adapter_protocol() = default; }; /// a type to simplify interfaces template using output_adapter_t = std::shared_ptr>; /// output adapter for byte vectors template class output_vector_adapter : public output_adapter_protocol { public: explicit output_vector_adapter(std::vector& vec) : v(vec) {} void write_character(CharType c) override { v.push_back(c); } void write_characters(const CharType* s, std::size_t length) override { std::copy(s, s + length, std::back_inserter(v)); } void write_characters_at(std::size_t position, const CharType* s, std::size_t length) override { std::copy(s, s + length, std::begin(v) + position); } std::size_t reserve_characters(std::size_t length) override { const auto position = v.size(); std::fill_n(std::back_inserter(v), length, static_cast(0x00)); return position; } private: std::vector& v; }; /// output adapter for output streams template class output_stream_adapter : public output_adapter_protocol { public: explicit output_stream_adapter(std::basic_ostream& s) : stream(s) {} void write_character(CharType c) override { stream.put(c); } void write_characters(const CharType* s, std::size_t length) override { stream.write(s, static_cast(length)); } void write_characters_at(std::size_t position, const CharType* s, std::size_t length) override { const auto orig_offset = stream.tellp(); stream.seekp(static_cast::pos_type>(position)); stream.write(s, static_cast(length)); stream.seekp(orig_offset); } std::size_t reserve_characters(std::size_t length) override { const auto position = stream.tellp(); std::vector empty(length, static_cast(0)); stream.write(empty.data(), length); return static_cast(position); } private: std::basic_ostream& stream; }; /// output adapter for basic_string template> class output_string_adapter : public output_adapter_protocol { public: explicit output_string_adapter(StringType& s) : str(s) {} void write_character(CharType c) override { str.push_back(c); } void write_characters(const CharType* s, std::size_t length) override { str.append(s, length); } void write_characters_at(std::size_t position, const CharType* s, std::size_t length) override { std::copy(s, s + length, std::begin(str) + position); } std::size_t reserve_characters(std::size_t length) override { const auto position = str.size(); std::fill_n(std::back_inserter(str), length, static_cast(0x00)); return position; } private: StringType& str; }; template> class output_adapter { public: output_adapter(std::vector& vec) : oa(std::make_shared>(vec)) {} output_adapter(std::basic_ostream& s) : oa(std::make_shared>(s)) {} output_adapter(StringType& s) : oa(std::make_shared>(s)) {} operator output_adapter_t() { return oa; } private: output_adapter_t oa = nullptr; }; } }