Coverage Report

Created: 2026-07-16 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/jsoncons/include/jsoncons/source.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_SOURCE_HPP
8
#define JSONCONS_SOURCE_HPP
9
10
#include <cstdint>
11
#include <cstring> // std::memcpy
12
#include <exception>
13
#include <functional>
14
#include <istream>
15
#include <iterator>
16
#include <memory> // std::addressof
17
#include <string>
18
#include <type_traits> // std::enable_if
19
#include <vector>
20
21
#include <jsoncons/config/compiler_support.hpp>
22
#include <jsoncons/utility/byte_string.hpp> // jsoncons::byte_traits
23
#include <jsoncons/config/jsoncons_config.hpp>
24
#include <jsoncons/utility/more_type_traits.hpp>
25
26
namespace jsoncons { 
27
28
template <typename Source>
29
struct source_reader;
30
31
// The source data must be padded by at least `buffer_padding_size` bytes.
32
JSONCONS_INLINE_CONSTEXPR uint8_t buffer_padding_size = 4;
33
34
template <typename CharT>
35
class basic_null_istream : public std::basic_istream<CharT>
36
{
37
    class null_buffer : public std::basic_streambuf<CharT>
38
    {
39
    public:
40
        using typename std::basic_streambuf<CharT>::int_type;
41
        using typename std::basic_streambuf<CharT>::traits_type;
42
43
4.36k
        null_buffer() = default;
44
        null_buffer(const null_buffer&) = delete;
45
        null_buffer(null_buffer&&) = default;
46
47
        null_buffer& operator=(const null_buffer&) = delete;
48
        null_buffer& operator=(null_buffer&&) = default;
49
50
        int_type overflow( int_type ch = typename std::basic_streambuf<CharT>::traits_type::eof()) override
51
0
        {
52
0
            return ch;
53
0
        }
54
    } nb_;
55
public:
56
    basic_null_istream()
57
4.36k
      : std::basic_istream<CharT>(&nb_)
58
4.36k
    {
59
4.36k
    }
60
61
    basic_null_istream(const null_buffer&) = delete;
62
    basic_null_istream& operator=(const null_buffer&) = delete;
63
    basic_null_istream(basic_null_istream&&) noexcept
64
        : std::basic_istream<CharT>(&nb_)
65
    {
66
    }
67
    basic_null_istream& operator=(basic_null_istream&&) noexcept
68
    {
69
        return *this;
70
    }
71
};
72
73
template <typename CharT>
74
struct char_result
75
{
76
    CharT value;
77
    bool eof;
78
};
79
80
// text sources
81
82
template <typename CharT,typename Allocator = std::allocator<CharT>>
83
class stream_source
84
{
85
    friend struct source_reader<stream_source<CharT,Allocator>>;
86
public:
87
    using value_type = CharT;
88
    static constexpr std::size_t default_max_chunk_size = 16384;
89
private:
90
    using char_type = typename std::conditional<sizeof(CharT) == sizeof(char),char,CharT>::type;
91
    using char_allocator_type = typename std::allocator_traits<Allocator>:: template rebind_alloc<value_type>;
92
    using stream_source_type = stream_source<CharT,Allocator>;
93
94
    Allocator alloc_;
95
    basic_null_istream<char_type> null_is_;
96
    std::basic_istream<char_type>* stream_ptr_;
97
    std::basic_streambuf<char_type>* sbuf_;
98
    std::size_t position_{0};
99
    value_type* chunk_{nullptr};
100
    std::size_t chunk_size_{0};
101
    value_type* data_{nullptr};
102
    std::size_t count_{0};
103
public:
104
105
    const Allocator& get_allocator() const
106
    {
107
        return alloc_;
108
    }
109
110
    stream_source(const Allocator& alloc = Allocator())
111
        : alloc_(alloc), stream_ptr_(&null_is_), sbuf_(null_is_.rdbuf())
112
    {
113
    }
114
115
    // Noncopyable 
116
    stream_source(const stream_source&) = delete;
117
118
    stream_source(stream_source&& other) noexcept
119
        : alloc_(other.alloc_), stream_ptr_(&null_is_), sbuf_(null_is_.rdbuf())
120
    {
121
        chunk_ = other.chunk_;
122
        data_ = other.data_;
123
        chunk_size_ = other.chunk_size_;
124
        count_ = other.count_;
125
        other.chunk_ = nullptr;
126
        other.data_ = nullptr;
127
        other.chunk_size_ = 0;
128
        other.count_ = 0;
129
130
        if (other.stream_ptr_ != &other.null_is_)
131
        {
132
            stream_ptr_ = other.stream_ptr_;
133
            sbuf_ = other.sbuf_;
134
            position_ = other.position_;
135
            other.stream_ptr_ = &other.null_is_;
136
            other.sbuf_ = other.null_is_.rdbuf();
137
            other.position_ = 0;
138
        }
139
    }
140
141
    stream_source(stream_source&& other, const Allocator& alloc) noexcept
142
        : alloc_(alloc), stream_ptr_(&null_is_), sbuf_(null_is_.rdbuf()),
143
          chunk_size_(other.chunk_size_), count_(other.count_)
144
    {
145
        if (alloc == other.get_allocator())
146
        {
147
            chunk_ = other.chunk_;
148
            data_ = other.data_;
149
            count_ = other.count_;
150
            other.chunk_ = nullptr;
151
            other.data_ = nullptr;
152
            other.count_ = 0;
153
        }
154
        else if (other.chunk_ != nullptr)
155
        {
156
            chunk_ = std::allocator_traits<char_allocator_type>::allocate(alloc_, chunk_size_);
157
            data_ = chunk_ + (other.data_ - other.chunk_);
158
            std::memcpy(data_, other.data_, sizeof(value_type)*other.count_);
159
        }
160
        if (other.stream_ptr_ != &other.null_is_)
161
        {
162
            stream_ptr_ = other.stream_ptr_;
163
            sbuf_ = other.sbuf_;
164
            position_ = other.position_;
165
        }
166
        else
167
        {
168
            stream_ptr_ = &null_is_;
169
            sbuf_ = null_is_.rdbuf();
170
            position_ = 0;
171
        }
172
    }
173
174
    stream_source(std::basic_istream<char_type>& is,
175
        const Allocator& alloc = Allocator())
176
4.36k
        : alloc_(alloc), stream_ptr_(std::addressof(is)), sbuf_(is.rdbuf()),
177
4.36k
          chunk_size_(default_max_chunk_size)
178
4.36k
    {
179
4.36k
        chunk_ = std::allocator_traits<char_allocator_type>::allocate(alloc_, chunk_size_);
180
4.36k
        data_ = chunk_;
181
4.36k
    }
182
183
    stream_source(std::basic_istream<char_type>& is, std::size_t buf_size,
184
        const Allocator& alloc = Allocator())
185
        : alloc_(alloc), stream_ptr_(std::addressof(is)), sbuf_(is.rdbuf()),
186
          chunk_size_(buf_size)
187
    {
188
        chunk_ = std::allocator_traits<char_allocator_type>::allocate(alloc_, chunk_size_);
189
        data_ = chunk_;
190
    }
191
192
    ~stream_source() noexcept
193
4.36k
    {
194
4.36k
        if (chunk_)
195
4.36k
        {
196
4.36k
            std::allocator_traits<char_allocator_type>::deallocate(alloc_, chunk_, chunk_size_);
197
4.36k
        }
198
4.36k
    }
199
200
    stream_source& operator=(const stream_source&) = delete;
201
  
202
    void move_assignment(std::true_type, // propagate_on_container_move_assignment
203
        stream_source&& other) noexcept
204
    {
205
        auto alloc = other.alloc_;
206
        other.alloc_ = alloc_;
207
        alloc_ = alloc;
208
        std::swap(chunk_, other.chunk_);
209
        std::swap(chunk_size_, other.chunk_size_);
210
        std::swap(data_, other.data_);
211
        std::swap(count_, other.count_);
212
        if (other.stream_ptr_ != &other.null_is_)
213
        {
214
            stream_ptr_ = other.stream_ptr_;
215
            sbuf_ = other.sbuf_;
216
            position_ = other.position_;
217
        }
218
        else
219
        {
220
            stream_ptr_ = &null_is_;
221
            sbuf_ = null_is_.rdbuf();
222
            position_ = 0;
223
        }
224
    }
225
226
    void move_assignment(std::false_type, // not propagate_on_container_move_assignment
227
        stream_source&& other) noexcept
228
    {
229
        chunk_size_ = other.chunk_size_;
230
        chunk_ = std::allocator_traits<char_allocator_type>::allocate(alloc_, chunk_size_);
231
        data_ = chunk_ + (other.data_ - other.chunk_);
232
        count_ = other.count_;
233
        std::memcpy(chunk_, other.chunk_, sizeof(value_type)*other.count_);
234
        if (other.stream_ptr_ != &other.null_is_)
235
        {
236
            stream_ptr_ = other.stream_ptr_;
237
            sbuf_ = other.sbuf_;
238
            position_ = other.position_;
239
        }
240
        else
241
        {
242
            stream_ptr_ = &null_is_;
243
            sbuf_ = null_is_.rdbuf();
244
            position_ = 0;
245
        }
246
    }
247
248
    stream_source& operator=(stream_source&& other) noexcept
249
    {
250
        move_assignment(typename std::allocator_traits<char_allocator_type>::propagate_on_container_move_assignment(),
251
            std::move(other));
252
        return *this;
253
    }
254
255
    const value_type* buffer() const
256
    {
257
        return chunk_;
258
    }
259
260
    std::size_t chunk_size() const
261
245k
    {
262
245k
        return chunk_size_;
263
245k
    }
264
265
    const value_type* data() const
266
    {
267
        return data_;
268
    }
269
270
    bool eof() const
271
245k
    {
272
245k
        return count_ == 0 && stream_ptr_->eof();
273
245k
    }
274
275
    bool is_error() const
276
    {
277
        return stream_ptr_->bad();  
278
    }
279
280
    std::size_t position() const
281
3.38k
    {
282
3.38k
        return position_;
283
3.38k
    }
284
285
    void ignore(std::size_t length)
286
13.0M
    {
287
13.0M
        std::size_t len = 0;
288
13.0M
        if (count_ > 0)
289
13.0M
        {
290
13.0M
            len = (std::min)(count_, length);
291
13.0M
            position_ += len;
292
13.0M
            data_ += len;
293
13.0M
            count_ -= len;
294
13.0M
        }
295
13.0M
        while (len < length)
296
0
        {
297
0
            data_ = chunk_;
298
0
            count_ = fill_buffer(chunk_, chunk_size_);
299
0
            if (count_ == 0)
300
0
            {
301
0
                break;
302
0
            }
303
0
            std::size_t len2 = (std::min)(count_, length-len);
304
0
            position_ += len2;
305
0
            data_ += len2;
306
0
            count_ -= len2;
307
0
            len += len2;
308
0
        }
309
13.0M
    }
310
311
    char_result<value_type> peek() 
312
177M
    {
313
177M
        if (count_ == 0)
314
10.1k
        {
315
10.1k
            data_ = chunk_;
316
10.1k
            count_ = fill_buffer(chunk_, chunk_size_);
317
10.1k
        }
318
177M
        if (count_ > 0)
319
177M
        {
320
177M
            value_type c = *data_;
321
177M
            return char_result<value_type>{c, false};
322
177M
        }
323
2.05k
        else
324
2.05k
        {
325
2.05k
            return char_result<value_type>{0, true};
326
2.05k
        }
327
177M
    }
328
329
    span<const value_type> read_chunk() 
330
    {
331
        if (count_ == 0)
332
        {
333
            data_ = chunk_;
334
            count_ = fill_buffer(chunk_, chunk_size_);
335
        }
336
        const value_type* data = data_;
337
        std::size_t length = count_;
338
        data_ += count_;
339
        position_ += count_;
340
        count_ = 0;
341
342
        return span<const value_type>(data, length);
343
    }
344
345
    std::size_t count() const
346
244k
    {
347
244k
        return count_;
348
244k
    }
349
350
    template <typename Buffer>
351
    span<const value_type> read_span(std::size_t length, Buffer&& buffer)
352
15.4M
    {
353
15.4M
        if (JSONCONS_UNLIKELY(length == 0))
354
12.5M
        {
355
12.5M
            return span<const value_type>{};
356
12.5M
        }
357
2.91M
        if (length > count_)
358
1.50k
        {
359
1.50k
            buffer.clear();
360
1.50k
            source_reader<stream_source_type>::read(*this, std::forward<Buffer>(buffer), length);
361
1.50k
            return span<const value_type>(reinterpret_cast<const value_type*>(buffer.data()), buffer.size());
362
1.50k
        }
363
364
2.91M
        const value_type* data = data_;
365
2.91M
        data_ += length;
366
2.91M
        count_ -= length;
367
2.91M
        position_ += length;
368
2.91M
        return span<const value_type>(data, length);
369
2.91M
    }
jsoncons::detail::span<unsigned char const, 18446744073709551615ul> jsoncons::stream_source<unsigned char, std::__1::allocator<unsigned char> >::read_span<std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&>(unsigned long, std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&)
Line
Count
Source
352
13.0M
    {
353
13.0M
        if (JSONCONS_UNLIKELY(length == 0))
354
10.3M
        {
355
10.3M
            return span<const value_type>{};
356
10.3M
        }
357
2.78M
        if (length > count_)
358
1.28k
        {
359
1.28k
            buffer.clear();
360
1.28k
            source_reader<stream_source_type>::read(*this, std::forward<Buffer>(buffer), length);
361
1.28k
            return span<const value_type>(reinterpret_cast<const value_type*>(buffer.data()), buffer.size());
362
1.28k
        }
363
364
2.78M
        const value_type* data = data_;
365
2.78M
        data_ += length;
366
2.78M
        count_ -= length;
367
2.78M
        position_ += length;
368
2.78M
        return span<const value_type>(data, length);
369
2.78M
    }
jsoncons::detail::span<unsigned char const, 18446744073709551615ul> jsoncons::stream_source<unsigned char, std::__1::allocator<unsigned char> >::read_span<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&>(unsigned long, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&)
Line
Count
Source
352
2.34M
    {
353
2.34M
        if (JSONCONS_UNLIKELY(length == 0))
354
2.21M
        {
355
2.21M
            return span<const value_type>{};
356
2.21M
        }
357
130k
        if (length > count_)
358
217
        {
359
217
            buffer.clear();
360
217
            source_reader<stream_source_type>::read(*this, std::forward<Buffer>(buffer), length);
361
217
            return span<const value_type>(reinterpret_cast<const value_type*>(buffer.data()), buffer.size());
362
217
        }
363
364
130k
        const value_type* data = data_;
365
130k
        data_ += length;
366
130k
        count_ -= length;
367
130k
        position_ += length;
368
130k
        return span<const value_type>(data, length);
369
130k
    }
370
371
    std::size_t read(value_type* p, std::size_t length)
372
53.3M
    {
373
53.3M
        std::size_t len = 0;
374
53.3M
        if (count_ > 0)
375
53.3M
        {
376
53.3M
            len = (std::min)(count_, length);
377
53.3M
            std::memcpy(p, data_, len*sizeof(value_type));
378
53.3M
            data_ += len;
379
53.3M
            count_ -= len;
380
53.3M
            position_ += len;
381
53.3M
        }
382
53.3M
        if (length - len == 0)
383
53.3M
        {
384
53.3M
            return len;
385
53.3M
        }
386
2.66k
        else if (length - len < chunk_size_)
387
2.66k
        {
388
2.66k
            data_ = chunk_;
389
2.66k
            count_ = fill_buffer(chunk_, chunk_size_);
390
2.66k
            if (count_ > 0)
391
1.89k
            {
392
1.89k
                std::size_t len2 = (std::min)(count_, length-len);
393
1.89k
                std::memcpy(p+len, data_, len2*sizeof(value_type));
394
1.89k
                data_ += len2;
395
1.89k
                count_ -= len2;
396
1.89k
                position_ += len2;
397
1.89k
                len += len2;
398
1.89k
            }
399
2.66k
            return len;
400
2.66k
        }
401
0
        else
402
0
        {
403
0
            if (stream_ptr_->eof())
404
0
            {
405
0
                count_ = 0;
406
0
                return 0;
407
0
            }
408
0
            JSONCONS_TRY
409
0
            {
410
0
                std::streamsize count = sbuf_->sgetn(reinterpret_cast<char_type*>(p+len), length-len);
411
0
                std::size_t len2 = static_cast<std::size_t>(count);
412
0
                if (len2 < length-len)
413
0
                {
414
0
                    stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::eofbit);
415
0
                }
416
0
                len += len2;
417
0
                position_ += len2;
418
0
                return len;
419
0
            }
420
0
            JSONCONS_CATCH(const std::exception&)     
421
0
            {
422
0
                stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::badbit | std::ios::eofbit);
423
0
                return 0;
424
0
            }
425
0
        }
426
53.3M
    }
427
private:
428
429
    std::size_t fill_buffer(value_type* chunk, std::size_t chunk_size)
430
13.1k
    {
431
13.1k
        if (stream_ptr_->eof())
432
2.77k
        {
433
2.77k
            return 0;
434
2.77k
        }
435
436
10.3k
        JSONCONS_TRY
437
10.3k
        {
438
10.3k
            std::streamsize count = sbuf_->sgetn(reinterpret_cast<char_type*>(chunk), chunk_size);
439
10.3k
            std::size_t length = static_cast<std::size_t>(count);
440
441
10.3k
            if (length < chunk_size)
442
4.32k
            {
443
4.32k
                stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::eofbit);
444
4.32k
            }
445
10.3k
            return length;
446
10.3k
        }
447
10.3k
        JSONCONS_CATCH(const std::exception&)     
448
10.3k
        {
449
0
            stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::badbit | std::ios::eofbit);
450
0
            return 0;
451
0
        }
452
10.3k
    }
453
};
454
455
template <typename CharT,typename Allocator>
456
constexpr std::size_t stream_source<CharT,Allocator>::default_max_chunk_size;
457
458
// string_source
459
460
template <typename CharT>
461
class string_source 
462
{
463
public:
464
    using value_type = CharT;
465
    using string_view_type = jsoncons::basic_string_view<value_type>;
466
private:
467
    const value_type* data_{nullptr};
468
    const value_type* current_{nullptr};
469
    const value_type* end_{nullptr};
470
public:
471
    string_source() noexcept = default;
472
473
    // Noncopyable 
474
    string_source(const string_source&) = delete;
475
476
    string_source(string_source&& other) = default;
477
478
    template <typename Sourceable>
479
    string_source(const Sourceable& s,
480
                  typename std::enable_if<ext_traits::is_sequence_of<Sourceable,value_type>::value>::type* = 0)
481
        : data_(s.data()), current_(s.data()), end_(s.data()+s.size())
482
    {
483
    }
484
485
    string_source(const value_type* data)
486
        : data_(data), current_(data), end_(data+std::char_traits<value_type>::length(data))
487
    {
488
    }
489
490
    string_source& operator=(const string_source&) = delete;
491
    string_source& operator=(string_source&& other) = default;
492
493
    bool eof() const
494
    {
495
        return current_ == end_;  
496
    }
497
498
    bool is_error() const
499
    {
500
        return false;  
501
    }
502
503
    std::size_t position() const
504
    {
505
        return (current_ - data_)/sizeof(value_type);
506
    }
507
508
    void ignore(std::size_t count)
509
    {
510
        std::size_t len;
511
        if (std::size_t(end_ - current_) < count)
512
        {
513
            len = end_ - current_;
514
        }
515
        else
516
        {
517
            len = count;
518
        }
519
        current_ += len;
520
    }
521
522
    char_result<value_type> peek() 
523
    {
524
        return current_ < end_ ? char_result<value_type>{*current_, false} : char_result<value_type>{0, true};
525
    }
526
527
    std::size_t chunk_size() const
528
    {
529
        return end_ - current_;
530
    }
531
532
    span<const value_type> read_chunk() 
533
    {
534
        const value_type* data = current_;
535
        std::size_t length = end_ - current_;
536
        current_ = end_;
537
538
        return span<const value_type>(data, length);
539
    }
540
541
542
    std::size_t fill_buffer(value_type* chunk, std::size_t chunk_size)
543
    {
544
        return read(chunk, chunk_size);
545
    }
546
547
    std::size_t count() const
548
    {
549
        return std::size_t(end_ - current_);
550
    }
551
552
    template <typename Buffer>
553
    span<const value_type> read_span(std::size_t length, Buffer&&)
554
    {
555
        if (std::size_t(end_ - current_) < length)
556
        {
557
            return span<const value_type>();
558
        }
559
        const value_type* data = current_;
560
        current_ += length;
561
        return span<const value_type>(data, length);
562
    }
563
564
    std::size_t read(value_type* p, std::size_t length)
565
    {
566
        std::size_t len;
567
        if (std::size_t(end_ - current_) < length)
568
        {
569
            len = end_ - current_;
570
        }
571
        else
572
        {
573
            len = length;
574
        }
575
        std::memcpy(p, current_, len*sizeof(value_type));
576
        current_  += len;
577
        return len;
578
    }
579
};
580
581
// iterator source
582
583
template <typename IteratorT>
584
class iterator_source
585
{
586
public:
587
    using value_type = typename std::iterator_traits<IteratorT>::value_type;
588
private:
589
    static constexpr std::size_t default_max_chunk_size = 16384;
590
591
    IteratorT current_;
592
    IteratorT end_;
593
    std::size_t position_{0};
594
    std::vector<value_type> chunk_;
595
    std::size_t chunk_len_{0};
596
597
    using difference_type = typename std::iterator_traits<IteratorT>::difference_type;
598
    using iterator_category = typename std::iterator_traits<IteratorT>::iterator_category;
599
public:
600
601
    // Noncopyable 
602
    iterator_source(const iterator_source&) = delete;
603
604
    iterator_source(iterator_source&& other) = default;
605
606
    iterator_source(const IteratorT& first, const IteratorT& last, std::size_t buf_size = default_max_chunk_size)
607
        : current_(first), end_(last), chunk_(buf_size)
608
    {
609
    }
610
    
611
    ~iterator_source() = default;
612
613
    iterator_source& operator=(const iterator_source&) = delete;
614
    iterator_source& operator=(iterator_source&& other) = default;
615
616
    bool eof() const
617
    {
618
        return !(current_ != end_);  
619
    }
620
621
    bool is_error() const
622
    {
623
        return false;  
624
    }
625
626
    std::size_t position() const
627
    {
628
        return position_;
629
    }
630
631
    void ignore(std::size_t count)
632
    {
633
        while (count-- > 0 && current_ != end_)
634
        {
635
            ++position_;
636
            ++current_;
637
        }
638
    }
639
640
    char_result<value_type> peek() 
641
    {
642
        return current_ != end_ ? char_result<value_type>{*current_, false} : char_result<value_type>{0, true};
643
    }
644
645
    std::size_t chunk_size() const
646
    {
647
        return chunk_.size();
648
    }
649
650
    span<const value_type> read_chunk() 
651
    {
652
        if (chunk_len_ == 0)
653
        {
654
            chunk_len_ = read(chunk_.data(), chunk_.size());
655
        }
656
        std::size_t length = chunk_len_;
657
        chunk_len_ = 0;
658
659
        return span<const value_type>(chunk_.data(), length);
660
    }
661
662
663
    std::size_t fill_buffer(value_type* chunk, std::size_t chunk_size)
664
    {
665
        return read(chunk, chunk_size);
666
    }
667
668
    std::size_t count() const
669
    {
670
        return chunk_len_;
671
    }
672
673
    template <typename Buffer>
674
    span<const value_type> read_span(std::size_t length, Buffer&& buffer)
675
    {
676
        if (JSONCONS_UNLIKELY(length == 0))
677
        {
678
            return span<const value_type>{};
679
        }
680
        buffer.clear();
681
        source_reader<iterator_source<IteratorT>>::read(*this, buffer, length);
682
        return span<const value_type>(reinterpret_cast<const value_type*>(buffer.data()), buffer.size());
683
    }
684
685
    template <typename Category = iterator_category>
686
    typename std::enable_if<std::is_same<Category,std::random_access_iterator_tag>::value, std::size_t>::type
687
    read(value_type* data, std::size_t length)
688
    {
689
        std::size_t count = (std::min)(length, static_cast<std::size_t>(std::distance(current_, end_)));
690
691
        //JSONCONS_COPY(current_, current_ + count, data);
692
693
        auto end = current_ + count;
694
        value_type* p = data;
695
        while (current_ != end)
696
        {
697
            *p++ = *current_++;
698
        }
699
700
        //current_ += count;
701
        position_ += count;
702
703
        return count;
704
    }
705
706
    template <typename Category = iterator_category>
707
    typename std::enable_if<!std::is_same<Category,std::random_access_iterator_tag>::value, std::size_t>::type
708
    read(value_type* data, std::size_t length)
709
    {
710
        value_type* p = data;
711
        value_type* pend = data + length;
712
713
        while (p < pend && current_ != end_)
714
        {
715
            *p = static_cast<value_type>(*current_);
716
            ++p;
717
            ++current_;
718
        }
719
720
        position_ += (p - data);
721
722
        return p - data;
723
    }
724
};
725
726
// binary sources
727
728
using binary_stream_source = stream_source<uint8_t>;
729
730
class bytes_source 
731
{
732
public:
733
    typedef uint8_t value_type;
734
private:
735
    const value_type* data_{nullptr};
736
    const value_type* current_{nullptr};
737
    const value_type* end_{nullptr};
738
public:
739
    bytes_source() noexcept = default;
740
741
    // Noncopyable 
742
    bytes_source(const bytes_source&) = delete;
743
744
    bytes_source(bytes_source&&) = default;
745
746
    template <typename Sourceable>
747
    bytes_source(const Sourceable& source,
748
                 typename std::enable_if<ext_traits::is_bytes_view_like<Sourceable>::value,int>::type = 0)
749
        : data_(reinterpret_cast<const value_type*>(source.data())), 
750
          current_(data_), 
751
          end_(data_+source.size())
752
    {
753
    }
754
755
    bytes_source& operator=(const bytes_source&) = delete;
756
    bytes_source& operator=(bytes_source&&) = default;
757
758
    bool eof() const
759
0
    {
760
0
        return current_ == end_;  
761
0
    }
762
763
    bool is_error() const
764
0
    {
765
0
        return false;  
766
0
    }
767
768
    std::size_t position() const
769
0
    {
770
0
        return current_ - data_;
771
0
    }
772
773
    void ignore(std::size_t count)
774
0
    {
775
0
        std::size_t len;
776
0
        if (std::size_t(end_ - current_) < count)
777
0
        {
778
0
            len = end_ - current_;
779
0
        }
780
0
        else
781
0
        {
782
0
            len = count;
783
0
        }
784
0
        current_ += len;
785
0
    }
786
787
    char_result<value_type> peek() 
788
0
    {
789
0
        return current_ < end_ ? char_result<value_type>{*current_, false} : char_result<value_type>{0, true};
790
0
    }
791
792
    std::size_t chunk_size() const
793
0
    {
794
0
        return end_ - current_;
795
0
    }
796
797
    span<const value_type> read_chunk() 
798
0
    {
799
0
        const value_type* data = current_;
800
0
        std::size_t length = end_ - current_;
801
0
        current_ = end_;
802
0
803
0
        return span<const value_type>(data, length);
804
0
    }
805
806
    std::size_t fill_buffer(value_type* chunk, std::size_t chunk_size)
807
0
    {
808
0
        return read(chunk, chunk_size);
809
0
    }
810
811
    std::size_t count() const
812
0
    {
813
0
        return std::size_t(end_ - current_);
814
0
    }
815
816
    template <typename Buffer>
817
    span<const value_type> read_span(std::size_t length, Buffer&&)
818
    {
819
        if (std::size_t(end_ - current_) < length)
820
        {
821
            return span<const value_type>();
822
        }
823
        const value_type* data = current_;
824
        current_ += length;
825
        return span<const value_type>(data, length);
826
    }
827
828
    std::size_t read(value_type* p, std::size_t length)
829
0
    {
830
0
        std::size_t len;
831
0
        if (std::size_t(end_ - current_) < length)
832
0
        {
833
0
            len = end_ - current_;
834
0
        }
835
0
        else
836
0
        {
837
0
            len = length;
838
0
        }
839
0
        std::memcpy(p, current_, len*sizeof(value_type));
840
0
        current_  += len;
841
0
        return len;
842
0
    }
843
};
844
845
// binary_iterator source
846
847
template <typename IteratorT>
848
class binary_iterator_source
849
{
850
public:
851
    using value_type = uint8_t;
852
private:
853
    static constexpr std::size_t default_max_chunk_size = 16384;
854
855
    IteratorT current_;
856
    IteratorT end_;
857
    std::size_t position_{0};
858
    std::vector<value_type> chunk_;
859
    std::size_t chunk_len_{0};
860
861
    using difference_type = typename std::iterator_traits<IteratorT>::difference_type;
862
    using iterator_category = typename std::iterator_traits<IteratorT>::iterator_category;
863
public:
864
865
    // Noncopyable 
866
    binary_iterator_source(const binary_iterator_source&) = delete;
867
868
    binary_iterator_source(binary_iterator_source&& other) = default;
869
870
    binary_iterator_source(const IteratorT& first, const IteratorT& last, std::size_t buf_size = default_max_chunk_size)
871
        : current_(first), end_(last), chunk_(buf_size)
872
    {
873
    }
874
875
    binary_iterator_source& operator=(const binary_iterator_source&) = delete;
876
    binary_iterator_source& operator=(binary_iterator_source&& other) = default;
877
878
    bool eof() const
879
    {
880
        return !(current_ != end_);  
881
    }
882
883
    bool is_error() const
884
    {
885
        return false;  
886
    }
887
888
    std::size_t position() const
889
    {
890
        return position_;
891
    }
892
893
    void ignore(std::size_t count)
894
    {
895
        while (count-- > 0 && current_ != end_)
896
        {
897
            ++position_;
898
            ++current_;
899
        }
900
    }
901
902
    char_result<value_type> peek() 
903
    {
904
        return current_ != end_ ? char_result<value_type>{static_cast<value_type>(*current_), false} : char_result<value_type>{0, true};
905
    }
906
907
    std::size_t chunk_size() const
908
    {
909
        return chunk_.size();
910
    }
911
912
    span<const value_type> read_chunk() 
913
    {
914
        if (chunk_len_ == 0)
915
        {
916
            chunk_len_ = read(chunk_.data(), chunk_.size());
917
        }
918
        std::size_t length = chunk_len_;
919
        chunk_len_ = 0;
920
921
        return span<const value_type>(chunk_.data(), length);
922
    }
923
924
    std::size_t fill_buffer(value_type* chunk, std::size_t chunk_size)
925
    {
926
        return read(chunk, chunk_size);
927
    }
928
929
    std::size_t count() const
930
    {
931
        return chunk_len_;
932
    }
933
934
    template <typename Buffer>
935
    span<const value_type> read_span(std::size_t length, Buffer&& buffer)
936
    {
937
        if (JSONCONS_UNLIKELY(length == 0))
938
        {
939
            return span<const value_type>{};
940
        }
941
        buffer.clear();
942
        source_reader<binary_iterator_source<IteratorT>>::read(*this, buffer, length);
943
        return span<const value_type>(reinterpret_cast<const value_type*>(buffer.data()), buffer.size());
944
    }
945
946
    template <typename Category = iterator_category>
947
    typename std::enable_if<std::is_same<Category,std::random_access_iterator_tag>::value, std::size_t>::type
948
    read(value_type* data, std::size_t length)
949
    {
950
        std::size_t count = (std::min)(length, static_cast<std::size_t>(std::distance(current_, end_)));
951
        //JSONCONS_COPY(current_, current_ + count, data);
952
953
        auto end = current_ + count;
954
        value_type* p = data;
955
        while (current_ != end)
956
        {
957
            *p++ = *current_++;
958
        }
959
960
        //current_ += count;
961
        position_ += count;
962
963
        return count;
964
    }
965
966
    template <typename Category = iterator_category>
967
    typename std::enable_if<!std::is_same<Category,std::random_access_iterator_tag>::value, std::size_t>::type
968
    read(value_type* data, std::size_t length)
969
    {
970
        value_type* p = data;
971
        value_type* pend = data + length;
972
973
        while (p < pend && current_ != end_)
974
        {
975
            *p = static_cast<value_type>(*current_);
976
            ++p;
977
            ++current_;
978
        }
979
980
        position_ += (p - data);
981
982
        return p - data;
983
    }
984
};
985
986
template <typename Source>
987
struct source_reader
988
{
989
    using value_type = typename Source::value_type;
990
991
    template <typename Buffer>
992
    static
993
    typename std::enable_if<ext_traits::is_byte<value_type>::value &&
994
        ext_traits::is_byte<typename Buffer::value_type>::value, std::size_t>::type
995
    read(Source& source, Buffer& buffer, std::size_t length)
996
634k
    {
997
634k
        std::size_t unread = length;
998
999
878k
        while (unread > 0 && !source.eof())
1000
244k
        {
1001
244k
            if (source.count() == 0 && unread >= source.chunk_size())
1002
321
            {
1003
321
                std::size_t n = source.chunk_size();
1004
321
                std::size_t offset = buffer.size();
1005
321
                buffer.resize(buffer.size()+n);
1006
321
                std::size_t actual = source.fill_buffer(reinterpret_cast<value_type*>(&buffer[0]) + offset, n);
1007
321
                unread -= actual;
1008
321
            }
1009
244k
            else
1010
244k
            {
1011
244k
                std::size_t n = (std::min)(source.chunk_size(), unread);
1012
244k
                std::size_t offset = buffer.size();
1013
244k
                buffer.resize(buffer.size()+n);
1014
244k
                std::size_t actual = source.read(reinterpret_cast<value_type*>(&buffer[0]) + offset, n);
1015
244k
                unread -= actual;
1016
244k
            }
1017
244k
        }
1018
634k
        return length - unread;
1019
634k
    }
_ZN8jsoncons13source_readerINS_13stream_sourceIhNSt3__19allocatorIhEEEEE4readINS2_6vectorIhS4_EEEENS2_9enable_ifIXaaL_ZNS2_17integral_constantIbLb1EE5valueEEsr10ext_traits7is_byteINT_10value_typeEEE5valueEmE4typeERS5_RSD_m
Line
Count
Source
996
324k
    {
997
324k
        std::size_t unread = length;
998
999
566k
        while (unread > 0 && !source.eof())
1000
241k
        {
1001
241k
            if (source.count() == 0 && unread >= source.chunk_size())
1002
197
            {
1003
197
                std::size_t n = source.chunk_size();
1004
197
                std::size_t offset = buffer.size();
1005
197
                buffer.resize(buffer.size()+n);
1006
197
                std::size_t actual = source.fill_buffer(reinterpret_cast<value_type*>(&buffer[0]) + offset, n);
1007
197
                unread -= actual;
1008
197
            }
1009
241k
            else
1010
241k
            {
1011
241k
                std::size_t n = (std::min)(source.chunk_size(), unread);
1012
241k
                std::size_t offset = buffer.size();
1013
241k
                buffer.resize(buffer.size()+n);
1014
241k
                std::size_t actual = source.read(reinterpret_cast<value_type*>(&buffer[0]) + offset, n);
1015
241k
                unread -= actual;
1016
241k
            }
1017
241k
        }
1018
324k
        return length - unread;
1019
324k
    }
_ZN8jsoncons13source_readerINS_13stream_sourceIhNSt3__19allocatorIhEEEEE4readINS2_12basic_stringIcNS2_11char_traitsIcEENS3_IcEEEEEENS2_9enable_ifIXaaL_ZNS2_17integral_constantIbLb1EE5valueEEsr10ext_traits7is_byteINT_10value_typeEEE5valueEmE4typeERS5_RSG_m
Line
Count
Source
996
310k
    {
997
310k
        std::size_t unread = length;
998
999
312k
        while (unread > 0 && !source.eof())
1000
2.80k
        {
1001
2.80k
            if (source.count() == 0 && unread >= source.chunk_size())
1002
124
            {
1003
124
                std::size_t n = source.chunk_size();
1004
124
                std::size_t offset = buffer.size();
1005
124
                buffer.resize(buffer.size()+n);
1006
124
                std::size_t actual = source.fill_buffer(reinterpret_cast<value_type*>(&buffer[0]) + offset, n);
1007
124
                unread -= actual;
1008
124
            }
1009
2.67k
            else
1010
2.67k
            {
1011
2.67k
                std::size_t n = (std::min)(source.chunk_size(), unread);
1012
2.67k
                std::size_t offset = buffer.size();
1013
2.67k
                buffer.resize(buffer.size()+n);
1014
2.67k
                std::size_t actual = source.read(reinterpret_cast<value_type*>(&buffer[0]) + offset, n);
1015
2.67k
                unread -= actual;
1016
2.67k
            }
1017
2.80k
        }
1018
310k
        return length - unread;
1019
310k
    }
1020
1021
    template <typename Buffer>
1022
    static
1023
    typename std::enable_if<!ext_traits::is_byte<value_type>::value &&
1024
                            ext_traits::has_reserve<Buffer>::value &&
1025
                            ext_traits::has_data_exact<value_type*,Buffer>::value, std::size_t>::type
1026
    read(Source& source, Buffer& buffer, std::size_t length)
1027
    {
1028
        std::size_t unread = length;
1029
1030
        while (unread > 0 && !source.eof())
1031
        {
1032
            if (source.count() == 0 && unread >= source.chunk_size())
1033
            {
1034
                std::size_t n = source.chunk_size();
1035
                std::size_t offset = buffer.size();
1036
                buffer.resize(buffer.size()+n);
1037
                std::size_t actual = source.fill_buffer(&buffer[0]+offset, n);
1038
                unread -= actual;
1039
            }
1040
            else
1041
            {
1042
                std::size_t n = (std::min)(source.chunk_size(), unread);
1043
                std::size_t offset = buffer.size();
1044
                buffer.resize(buffer.size()+n);
1045
                std::size_t actual = source.read(&buffer[0]+offset, n);
1046
                unread -= actual;
1047
            }
1048
        }
1049
1050
        return length - unread;
1051
    }
1052
};
1053
1054
} // namespace jsoncons
1055
1056
#endif // JSONCONS_SOURCE_HPP