Coverage Report

Created: 2026-05-20 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/jsoncons/include/jsoncons/sink.hpp
Line
Count
Source
1
// Copyright 2013-2026 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 append(std::size_t count, const CharT ch)
88
        {
89
            if (count <= std::size_t(end_buffer_ - p_))
90
            {
91
                for (std::size_t i = 0; i < count; ++i)
92
                {
93
                    *p_++ = ch;
94
                }
95
            }
96
            else
97
            {
98
                for (std::size_t i = 0; i < count; ++i)
99
                {
100
                    push_back(ch);
101
                }
102
            }
103
        }
104
105
        void push_back(CharT ch)
106
        {
107
            if (p_ < end_buffer_)
108
            {
109
                *p_++ = ch;
110
            }
111
            else
112
            {
113
                stream_ptr_->write(begin_buffer_, buffer_length());
114
                p_ = begin_buffer_;
115
                *p_++ = ch;
116
            }
117
        }
118
    private:
119
120
        std::size_t buffer_length() const
121
        {
122
            return p_ - begin_buffer_;
123
        }
124
    };
125
126
    // binary_stream_sink
127
128
    class binary_stream_sink
129
    {
130
    public:
131
        typedef uint8_t value_type;
132
        using container_type = std::basic_ostream<char>;
133
    private:
134
        static constexpr size_t default_buffer_length = 16384;
135
136
        std::basic_ostream<char>* stream_ptr_;
137
        std::vector<uint8_t> buffer_;
138
        uint8_t * begin_buffer_;
139
        const uint8_t* end_buffer_;
140
        uint8_t* p_;
141
142
    public:
143
144
        // Noncopyable
145
        binary_stream_sink(const binary_stream_sink&) = delete;
146
147
        binary_stream_sink(binary_stream_sink&&) = default;
148
149
        binary_stream_sink(std::basic_ostream<char>& os)
150
            : stream_ptr_(std::addressof(os)), 
151
              buffer_(default_buffer_length), 
152
              begin_buffer_(buffer_.data()), 
153
              end_buffer_(begin_buffer_+buffer_.size()), 
154
              p_(begin_buffer_)
155
0
        {
156
0
        }
157
        binary_stream_sink(std::basic_ostream<char>& os, std::size_t buflen)
158
            : stream_ptr_(std::addressof(os)), 
159
              buffer_(buflen), 
160
              begin_buffer_(buffer_.data()), 
161
              end_buffer_(begin_buffer_+buffer_.size()), 
162
              p_(begin_buffer_)
163
0
        {
164
0
        }
165
        ~binary_stream_sink() noexcept
166
0
        {
167
0
            stream_ptr_->write((char*)begin_buffer_, buffer_length());
168
0
            stream_ptr_->flush();
169
0
        }
170
171
        binary_stream_sink& operator=(const binary_stream_sink&) = delete;
172
        binary_stream_sink& operator=(binary_stream_sink&&) = default;
173
174
        void flush()
175
0
        {
176
0
            stream_ptr_->write((char*)begin_buffer_, buffer_length());
177
0
            p_ = buffer_.data();
178
0
        }
179
180
        void append(const uint8_t* s, std::size_t length)
181
0
        {
182
0
            std::size_t diff = end_buffer_ - p_;
183
0
            if (diff >= length)
184
0
            {
185
0
                std::memcpy(p_, s, length*sizeof(uint8_t));
186
0
                p_ += length;
187
0
            }
188
0
            else
189
0
            {
190
0
                stream_ptr_->write((char*)begin_buffer_, buffer_length());
191
0
                stream_ptr_->write((const char*)s,length);
192
0
                p_ = begin_buffer_;
193
0
            }
194
0
        }
195
196
        void append(std::size_t count, uint8_t ch)
197
0
        {
198
0
            if (count <= std::size_t(end_buffer_ - p_))
199
0
            {
200
0
                for (std::size_t i = 0; i < count; ++i)
201
0
                {
202
0
                    *p_++ = ch;
203
0
                }
204
0
            }
205
0
            else
206
0
            {
207
0
                for (std::size_t i = 0; i < count; ++i)
208
0
                {
209
0
                    push_back(ch);
210
0
                }
211
0
            }
212
0
        }
213
214
        void push_back(uint8_t ch)
215
0
        {
216
0
            if (p_ < end_buffer_)
217
0
            {
218
0
                *p_++ = ch;
219
0
            }
220
0
            else
221
0
            {
222
0
                stream_ptr_->write((char*)begin_buffer_, buffer_length());
223
0
                p_ = begin_buffer_;
224
0
                *p_++ = ch;
225
0
            }
226
0
        }
227
    private:
228
229
        std::size_t buffer_length() const
230
0
        {
231
0
            return p_ - begin_buffer_;
232
0
        }
233
    };
234
235
    // string_sink
236
237
    template <typename StringT>
238
    class string_sink 
239
    {
240
    public:
241
        using value_type = typename StringT::value_type;
242
        using container_type = StringT;
243
    private:
244
        container_type* buf_ptr{nullptr};
245
    public:
246
247
        // Noncopyable
248
        string_sink(const string_sink&) = delete;
249
250
        string_sink(string_sink&& other) noexcept
251
        {
252
            std::swap(buf_ptr,other.buf_ptr);
253
        }
254
255
        string_sink(container_type& buf)
256
            : buf_ptr(std::addressof(buf))
257
        {
258
        }
259
        
260
        ~string_sink() = default;
261
262
        string_sink& operator=(const string_sink&) = delete;
263
264
        string_sink& operator=(string_sink&& other) noexcept
265
        {
266
            // TODO: Shouldn't other.buf_ptr be nullified?
267
            //       Also see move constructor above.
268
            std::swap(buf_ptr,other.buf_ptr);
269
            return *this;
270
        }
271
272
        void flush()
273
        {
274
        }
275
276
        void append(const value_type* s, std::size_t length)
277
        {
278
            buf_ptr->append(s, length);
279
        }
280
281
        void append(std::size_t count, value_type ch)
282
        {
283
            buf_ptr->append(count, ch);
284
        }
285
286
        void push_back(value_type ch)
287
        {
288
            buf_ptr->push_back(ch);
289
        }
290
    };
291
292
    // bytes_sink
293
294
    template <typename Container,typename = void>
295
    class bytes_sink
296
    {
297
    };
298
299
    template <typename Container>
300
    class bytes_sink<Container,typename std::enable_if<ext_traits::is_back_insertable_byte_container<Container>::value>::type> 
301
    {
302
    public:
303
        using container_type = Container;
304
        using value_type = typename Container::value_type;
305
    private:
306
        container_type* buf_ptr;
307
    public:
308
309
        // Noncopyable
310
        bytes_sink(const bytes_sink&) = delete;
311
312
        bytes_sink(bytes_sink&&) = default;
313
314
        bytes_sink(container_type& buf)
315
247
            : buf_ptr(std::addressof(buf))
316
247
        {
317
247
        }
318
        
319
        ~bytes_sink() = default; 
320
321
        bytes_sink& operator=(const bytes_sink&) = delete;
322
        bytes_sink& operator=(bytes_sink&&) = default;
323
324
        void flush()
325
262
        {
326
262
        }
327
328
        void push_back(uint8_t ch)
329
35.0M
        {
330
35.0M
            buf_ptr->push_back(static_cast<value_type>(ch));
331
35.0M
        }
332
    };
333
334
} // namespace jsoncons
335
336
#endif // JSONCONS_SINK_HPP