Coverage Report

Created: 2025-08-24 06:53

/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