1 #pragma once
2 
3 #include <algorithm> // copy
4 #include <cstddef> // size_t
5 #include <ios> // streamsize
6 #include <iterator> // back_inserter
7 #include <memory> // shared_ptr, make_shared
8 #include <ostream> // basic_ostream
9 #include <string> // basic_string
10 #include <vector> // vector
11 #include <nlohmann/detail/macro_scope.hpp>
12 
13 namespace nlohmann
14 {
15 namespace detail
16 {
17 /// abstract output adapter interface
18 template<typename CharType> struct output_adapter_protocol
19 {
20     virtual void write_character(CharType c) = 0;
21     virtual void write_characters(const CharType* s, std::size_t length) = 0;
22     virtual ~output_adapter_protocol() = default;
23 };
24 
25 /// a type to simplify interfaces
26 template<typename CharType>
27 using output_adapter_t = std::shared_ptr<output_adapter_protocol<CharType>>;
28 
29 /// output adapter for byte vectors
30 template<typename CharType>
31 class output_vector_adapter : public output_adapter_protocol<CharType>
32 {
33   public:
output_vector_adapter(std::vector<CharType> & vec)34     explicit output_vector_adapter(std::vector<CharType>& vec) noexcept
35         : v(vec)
36     {}
37 
write_character(CharType c)38     void write_character(CharType c) override
39     {
40         v.push_back(c);
41     }
42 
43     JSON_HEDLEY_NON_NULL(2)
write_characters(const CharType * s,std::size_t length)44     void write_characters(const CharType* s, std::size_t length) override
45     {
46         std::copy(s, s + length, std::back_inserter(v));
47     }
48 
49   private:
50     std::vector<CharType>& v;
51 };
52 
53 /// output adapter for output streams
54 template<typename CharType>
55 class output_stream_adapter : public output_adapter_protocol<CharType>
56 {
57   public:
output_stream_adapter(std::basic_ostream<CharType> & s)58     explicit output_stream_adapter(std::basic_ostream<CharType>& s) noexcept
59         : stream(s)
60     {}
61 
write_character(CharType c)62     void write_character(CharType c) override
63     {
64         stream.put(c);
65     }
66 
67     JSON_HEDLEY_NON_NULL(2)
write_characters(const CharType * s,std::size_t length)68     void write_characters(const CharType* s, std::size_t length) override
69     {
70         stream.write(s, static_cast<std::streamsize>(length));
71     }
72 
73   private:
74     std::basic_ostream<CharType>& stream;
75 };
76 
77 /// output adapter for basic_string
78 template<typename CharType, typename StringType = std::basic_string<CharType>>
79 class output_string_adapter : public output_adapter_protocol<CharType>
80 {
81   public:
output_string_adapter(StringType & s)82     explicit output_string_adapter(StringType& s) noexcept
83         : str(s)
84     {}
85 
write_character(CharType c)86     void write_character(CharType c) override
87     {
88         str.push_back(c);
89     }
90 
91     JSON_HEDLEY_NON_NULL(2)
write_characters(const CharType * s,std::size_t length)92     void write_characters(const CharType* s, std::size_t length) override
93     {
94         str.append(s, length);
95     }
96 
97   private:
98     StringType& str;
99 };
100 
101 template<typename CharType, typename StringType = std::basic_string<CharType>>
102 class output_adapter
103 {
104   public:
output_adapter(std::vector<CharType> & vec)105     output_adapter(std::vector<CharType>& vec)
106         : oa(std::make_shared<output_vector_adapter<CharType>>(vec)) {}
107 
output_adapter(std::basic_ostream<CharType> & s)108     output_adapter(std::basic_ostream<CharType>& s)
109         : oa(std::make_shared<output_stream_adapter<CharType>>(s)) {}
110 
output_adapter(StringType & s)111     output_adapter(StringType& s)
112         : oa(std::make_shared<output_string_adapter<CharType, StringType>>(s)) {}
113 
operator output_adapter_t<CharType>()114     operator output_adapter_t<CharType>()
115     {
116         return oa;
117     }
118 
119   private:
120     output_adapter_t<CharType> oa = nullptr;
121 };
122 }  // namespace detail
123 }  // namespace nlohmann
124