/src/jsoncons/include/jsoncons/sink.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright 2013-2025 Daniel Parker |
2 | | // Distributed under the Boost license, Version 1.0. |
3 | | // (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) |
4 | | |
5 | | // See https://github.com/danielaparker/jsoncons for latest version |
6 | | |
7 | | #ifndef JSONCONS_SINK_HPP |
8 | | #define JSONCONS_SINK_HPP |
9 | | |
10 | | #include <cmath> |
11 | | #include <cstdint> |
12 | | #include <cstring> // std::memcpy |
13 | | #include <memory> // std::addressof |
14 | | #include <ostream> |
15 | | #include <vector> |
16 | | |
17 | | #include <jsoncons/config/jsoncons_config.hpp> |
18 | | #include <jsoncons/utility/more_type_traits.hpp> |
19 | | |
20 | | namespace jsoncons { |
21 | | |
22 | | // stream_sink |
23 | | |
24 | | template <typename CharT> |
25 | | class stream_sink |
26 | | { |
27 | | public: |
28 | | using value_type = CharT; |
29 | | using container_type = std::basic_ostream<CharT>; |
30 | | |
31 | | private: |
32 | | static constexpr size_t default_buffer_length = 16384; |
33 | | |
34 | | std::basic_ostream<CharT>* stream_ptr_; |
35 | | std::vector<CharT> buffer_; |
36 | | CharT * begin_buffer_; |
37 | | const CharT* end_buffer_; |
38 | | CharT* p_; |
39 | | |
40 | | public: |
41 | | |
42 | | // Noncopyable |
43 | | stream_sink(const stream_sink&) = delete; |
44 | | stream_sink(stream_sink&&) = default; |
45 | | |
46 | | stream_sink(std::basic_ostream<CharT>& os) |
47 | | : stream_ptr_(std::addressof(os)), buffer_(default_buffer_length), begin_buffer_(buffer_.data()), end_buffer_(begin_buffer_+buffer_.size()), p_(begin_buffer_) |
48 | | { |
49 | | } |
50 | | stream_sink(std::basic_ostream<CharT>& os, std::size_t buflen) |
51 | | : stream_ptr_(std::addressof(os)), buffer_(buflen), begin_buffer_(buffer_.data()), end_buffer_(begin_buffer_+buffer_.size()), p_(begin_buffer_) |
52 | | { |
53 | | } |
54 | | ~stream_sink() noexcept |
55 | | { |
56 | | stream_ptr_->write(begin_buffer_, buffer_length()); |
57 | | stream_ptr_->flush(); |
58 | | } |
59 | | |
60 | | // Movable |
61 | | stream_sink& operator=(const stream_sink&) = delete; |
62 | | stream_sink& operator=(stream_sink&&) = default; |
63 | | |
64 | | void flush() |
65 | | { |
66 | | stream_ptr_->write(begin_buffer_, buffer_length()); |
67 | | stream_ptr_->flush(); |
68 | | p_ = buffer_.data(); |
69 | | } |
70 | | |
71 | | void append(const CharT* s, std::size_t length) |
72 | | { |
73 | | std::size_t diff = end_buffer_ - p_; |
74 | | if (diff >= length) |
75 | | { |
76 | | std::memcpy(p_, s, length*sizeof(CharT)); |
77 | | p_ += length; |
78 | | } |
79 | | else |
80 | | { |
81 | | stream_ptr_->write(begin_buffer_, buffer_length()); |
82 | | stream_ptr_->write(s,length); |
83 | | p_ = begin_buffer_; |
84 | | } |
85 | | } |
86 | | |
87 | | void push_back(CharT ch) |
88 | | { |
89 | | if (p_ < end_buffer_) |
90 | | { |
91 | | *p_++ = ch; |
92 | | } |
93 | | else |
94 | | { |
95 | | stream_ptr_->write(begin_buffer_, buffer_length()); |
96 | | p_ = begin_buffer_; |
97 | | push_back(ch); |
98 | | } |
99 | | } |
100 | | private: |
101 | | |
102 | | std::size_t buffer_length() const |
103 | | { |
104 | | return p_ - begin_buffer_; |
105 | | } |
106 | | }; |
107 | | |
108 | | // binary_stream_sink |
109 | | |
110 | | class binary_stream_sink |
111 | | { |
112 | | public: |
113 | | typedef uint8_t value_type; |
114 | | using container_type = std::basic_ostream<char>; |
115 | | private: |
116 | | static constexpr size_t default_buffer_length = 16384; |
117 | | |
118 | | std::basic_ostream<char>* stream_ptr_; |
119 | | std::vector<uint8_t> buffer_; |
120 | | uint8_t * begin_buffer_; |
121 | | const uint8_t* end_buffer_; |
122 | | uint8_t* p_; |
123 | | |
124 | | public: |
125 | | |
126 | | // Noncopyable |
127 | | binary_stream_sink(const binary_stream_sink&) = delete; |
128 | | |
129 | | binary_stream_sink(binary_stream_sink&&) = default; |
130 | | |
131 | | binary_stream_sink(std::basic_ostream<char>& os) |
132 | | : stream_ptr_(std::addressof(os)), |
133 | | buffer_(default_buffer_length), |
134 | | begin_buffer_(buffer_.data()), |
135 | | end_buffer_(begin_buffer_+buffer_.size()), |
136 | | p_(begin_buffer_) |
137 | 0 | { |
138 | 0 | } |
139 | | binary_stream_sink(std::basic_ostream<char>& os, std::size_t buflen) |
140 | | : stream_ptr_(std::addressof(os)), |
141 | | buffer_(buflen), |
142 | | begin_buffer_(buffer_.data()), |
143 | | end_buffer_(begin_buffer_+buffer_.size()), |
144 | | p_(begin_buffer_) |
145 | 0 | { |
146 | 0 | } |
147 | | ~binary_stream_sink() noexcept |
148 | 0 | { |
149 | 0 | stream_ptr_->write((char*)begin_buffer_, buffer_length()); |
150 | 0 | stream_ptr_->flush(); |
151 | 0 | } |
152 | | |
153 | | binary_stream_sink& operator=(const binary_stream_sink&) = delete; |
154 | | binary_stream_sink& operator=(binary_stream_sink&&) = default; |
155 | | |
156 | | void flush() |
157 | 0 | { |
158 | 0 | stream_ptr_->write((char*)begin_buffer_, buffer_length()); |
159 | 0 | p_ = buffer_.data(); |
160 | 0 | } |
161 | | |
162 | | void append(const uint8_t* s, std::size_t length) |
163 | 0 | { |
164 | 0 | std::size_t diff = end_buffer_ - p_; |
165 | 0 | if (diff >= length) |
166 | 0 | { |
167 | 0 | std::memcpy(p_, s, length*sizeof(uint8_t)); |
168 | 0 | p_ += length; |
169 | 0 | } |
170 | 0 | else |
171 | 0 | { |
172 | 0 | stream_ptr_->write((char*)begin_buffer_, buffer_length()); |
173 | 0 | stream_ptr_->write((const char*)s,length); |
174 | 0 | p_ = begin_buffer_; |
175 | 0 | } |
176 | 0 | } |
177 | | |
178 | | void push_back(uint8_t ch) |
179 | 0 | { |
180 | 0 | if (p_ < end_buffer_) |
181 | 0 | { |
182 | 0 | *p_++ = ch; |
183 | 0 | } |
184 | 0 | else |
185 | 0 | { |
186 | 0 | stream_ptr_->write((char*)begin_buffer_, buffer_length()); |
187 | 0 | p_ = begin_buffer_; |
188 | 0 | push_back(ch); |
189 | 0 | } |
190 | 0 | } |
191 | | private: |
192 | | |
193 | | std::size_t buffer_length() const |
194 | 0 | { |
195 | 0 | return p_ - begin_buffer_; |
196 | 0 | } |
197 | | }; |
198 | | |
199 | | // string_sink |
200 | | |
201 | | template <typename StringT> |
202 | | class string_sink |
203 | | { |
204 | | public: |
205 | | using value_type = typename StringT::value_type; |
206 | | using container_type = StringT; |
207 | | private: |
208 | | container_type* buf_ptr{nullptr}; |
209 | | public: |
210 | | |
211 | | // Noncopyable |
212 | | string_sink(const string_sink&) = delete; |
213 | | |
214 | | string_sink(string_sink&& other) noexcept |
215 | 3.67k | { |
216 | 3.67k | std::swap(buf_ptr,other.buf_ptr); |
217 | 3.67k | } |
218 | | |
219 | | string_sink(container_type& buf) |
220 | 3.67k | : buf_ptr(std::addressof(buf)) |
221 | 3.67k | { |
222 | 3.67k | } |
223 | | |
224 | | ~string_sink() = default; |
225 | | |
226 | | string_sink& operator=(const string_sink&) = delete; |
227 | | |
228 | | string_sink& operator=(string_sink&& other) noexcept |
229 | | { |
230 | | // TODO: Shouldn't other.buf_ptr be nullified? |
231 | | // Also see move constructor above. |
232 | | std::swap(buf_ptr,other.buf_ptr); |
233 | | return *this; |
234 | | } |
235 | | |
236 | | void flush() |
237 | 7.29k | { |
238 | 7.29k | } |
239 | | |
240 | | void append(const value_type* s, std::size_t length) |
241 | 14.5M | { |
242 | 14.5M | buf_ptr->insert(buf_ptr->end(), s, s+length); |
243 | 14.5M | } |
244 | | |
245 | | void push_back(value_type ch) |
246 | 13.2M | { |
247 | 13.2M | buf_ptr->push_back(ch); |
248 | 13.2M | } |
249 | | }; |
250 | | |
251 | | // bytes_sink |
252 | | |
253 | | template <typename Container,typename = void> |
254 | | class bytes_sink |
255 | | { |
256 | | }; |
257 | | |
258 | | template <typename Container> |
259 | | class bytes_sink<Container,typename std::enable_if<ext_traits::is_back_insertable_byte_container<Container>::value>::type> |
260 | | { |
261 | | public: |
262 | | using container_type = Container; |
263 | | using value_type = typename Container::value_type; |
264 | | private: |
265 | | container_type* buf_ptr; |
266 | | public: |
267 | | |
268 | | // Noncopyable |
269 | | bytes_sink(const bytes_sink&) = delete; |
270 | | |
271 | | bytes_sink(bytes_sink&&) = default; |
272 | | |
273 | | bytes_sink(container_type& buf) |
274 | | : buf_ptr(std::addressof(buf)) |
275 | | { |
276 | | } |
277 | | |
278 | | ~bytes_sink() = default; |
279 | | |
280 | | bytes_sink& operator=(const bytes_sink&) = delete; |
281 | | bytes_sink& operator=(bytes_sink&&) = default; |
282 | | |
283 | | void flush() |
284 | | { |
285 | | } |
286 | | |
287 | | void push_back(uint8_t ch) |
288 | | { |
289 | | buf_ptr->push_back(static_cast<value_type>(ch)); |
290 | | } |
291 | | }; |
292 | | |
293 | | } // namespace jsoncons |
294 | | |
295 | | #endif // JSONCONS_SINK_HPP |