Coverage Report

Created: 2026-10-14 06:48

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/nonstd/compiler_support.hpp>
22
#include <jsoncons/utility/byte_string.hpp> // jsoncons::byte_traits
23
#include <jsoncons/config/jsoncons_config.hpp>
24
#include <jsoncons/nonstd/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
6.52k
        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
6.52k
      : std::basic_istream<CharT>(&nb_)
58
6.52k
    {
59
6.52k
    }
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_end_{nullptr};
102
    std::size_t remaining_{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_end_ = other.data_end_;
123
        chunk_size_ = other.chunk_size_;
124
        remaining_ = other.remaining_;
125
        other.chunk_ = nullptr;
126
        other.data_end_ = nullptr;
127
        other.chunk_size_ = 0;
128
        other.remaining_ = 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_), remaining_(other.remaining_)
144
    {
145
        if (alloc == other.get_allocator())
146
        {
147
            chunk_ = other.chunk_;
148
            data_end_ = other.data_end_;
149
            remaining_ = other.remaining_;
150
            other.chunk_ = nullptr;
151
            other.data_end_ = nullptr;
152
            other.remaining_ = 0;
153
        }
154
        else if (other.chunk_ != nullptr)
155
        {
156
            chunk_ = std::allocator_traits<char_allocator_type>::allocate(alloc_, chunk_size_);
157
            data_end_ = chunk_ + (other.data_end_ - other.chunk_);
158
            std::memcpy(data_end_, other.data_end_, sizeof(value_type)*other.remaining_);
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
6.52k
        : alloc_(alloc), stream_ptr_(std::addressof(is)), sbuf_(is.rdbuf()),
177
6.52k
          chunk_size_(default_max_chunk_size)
178
6.52k
    {
179
6.52k
        chunk_ = std::allocator_traits<char_allocator_type>::allocate(alloc_, chunk_size_);
180
6.52k
        data_end_ = chunk_;
181
6.52k
    }
182
183
    stream_source(std::basic_istream<char_type>& is, std::size_t chunk_size,
184
        const Allocator& alloc = Allocator())
185
        : alloc_(alloc), stream_ptr_(std::addressof(is)), sbuf_(is.rdbuf()),
186
          chunk_size_(chunk_size)
187
    {
188
        chunk_ = std::allocator_traits<char_allocator_type>::allocate(alloc_, chunk_size_);
189
        data_end_ = chunk_;
190
    }
191
192
    ~stream_source() noexcept
193
6.52k
    {
194
6.52k
        if (chunk_)
195
6.52k
        {
196
6.52k
            std::allocator_traits<char_allocator_type>::deallocate(alloc_, chunk_, chunk_size_);
197
6.52k
        }
198
6.52k
    }
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_end_, other.data_end_);
211
        std::swap(remaining_, other.remaining_);
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_end_ = chunk_ + (other.data_end_ - other.chunk_);
232
        remaining_ = other.remaining_;
233
        std::memcpy(chunk_, other.chunk_, sizeof(value_type)*other.remaining_);
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
4.39k
    {
262
4.39k
        return chunk_size_;
263
4.39k
    }
264
265
    const value_type* data() const
266
    {
267
        return data_end_;
268
    }
269
270
    bool eof() const
271
4.21k
    {
272
4.21k
        return remaining_ == 0 && stream_ptr_->eof();
273
4.21k
    }
274
275
    bool is_error() const
276
38.3M
    {
277
38.3M
        return stream_ptr_->bad();  
278
38.3M
    }
279
280
    std::size_t position() const
281
0
    {
282
0
        return position_;
283
0
    }
284
285
    void ignore(std::size_t length)
286
    {
287
        std::size_t len = 0;
288
        if (remaining_ > 0)
289
        {
290
            len = (std::min)(remaining_, length);
291
            position_ += len;
292
            data_end_ += len;
293
            remaining_ -= len;
294
        }
295
        while (len < length)
296
        {
297
            data_end_ = chunk_;
298
            remaining_ = fill_buffer(chunk_, chunk_size_);
299
            if (remaining_ == 0)
300
            {
301
                break;
302
            }
303
            std::size_t len2 = (std::min)(remaining_, length-len);
304
            position_ += len2;
305
            data_end_ += len2;
306
            remaining_ -= len2;
307
            len += len2;
308
        }
309
    }
310
311
    char_result<value_type> peek() 
312
    {
313
        if (remaining_ == 0)
314
        {
315
            data_end_ = chunk_;
316
            remaining_ = fill_buffer(chunk_, chunk_size_);
317
        }
318
        if (remaining_ > 0)
319
        {
320
            value_type c = *data_end_;
321
            return char_result<value_type>{c, false};
322
        }
323
        else
324
        {
325
            return char_result<value_type>{0, true};
326
        }
327
    }
328
329
    span<const value_type> read_chunk() 
330
    {
331
        if (remaining_ == 0)
332
        {
333
            data_end_ = chunk_;
334
            remaining_ = fill_buffer(chunk_, chunk_size_);
335
        }
336
        const value_type* data = data_end_;
337
        std::size_t length = remaining_;
338
        data_end_ += remaining_;
339
        position_ += remaining_;
340
        remaining_ = 0;
341
342
        return span<const value_type>(data, length);
343
    }
344
345
    std::size_t remaining() const
346
3.70k
    {
347
3.70k
        return remaining_;
348
3.70k
    }
349
350
    template <typename Buffer>
351
    span<const value_type> read_span(std::size_t length, Buffer&& buffer)
352
1.32M
    {
353
1.32M
        if (JSONCONS_UNLIKELY(length == 0))
354
64.8k
        {
355
64.8k
            return span<const value_type>{};
356
64.8k
        }
357
1.26M
        if (remaining_ == 0 && length <= chunk_size_)
358
197
        {
359
197
            remaining_ = fill_buffer(chunk_, chunk_size_);
360
197
            data_end_ = chunk_;
361
197
        }
362
1.26M
        if (length > remaining_)
363
1.08k
        {
364
1.08k
            buffer.clear();
365
1.08k
            source_reader<stream_source_type>::read(*this, std::forward<Buffer>(buffer), length);
366
1.08k
            return span<const value_type>(reinterpret_cast<const value_type*>(buffer.data()), buffer.size());
367
1.08k
        }
368
369
1.26M
        const value_type* data = data_end_;
370
1.26M
        data_end_ += length;
371
1.26M
        remaining_ -= length;
372
1.26M
        position_ += length;
373
1.26M
        return span<const value_type>(data, length);
374
1.26M
    }
375
376
    std::size_t read(value_type* p, std::size_t length)
377
40.4M
    {
378
40.4M
        std::size_t len = 0;
379
40.4M
        if (remaining_ > 0)
380
40.4M
        {
381
40.4M
            len = (std::min)(remaining_, length);
382
40.4M
            std::memcpy(p, data_end_, len*sizeof(value_type));
383
40.4M
            data_end_ += len;
384
40.4M
            remaining_ -= len;
385
40.4M
            position_ += len;
386
40.4M
        }
387
40.4M
        if (length - len == 0)
388
40.3M
        {
389
40.3M
            return len;
390
40.3M
        }
391
15.6k
        else if (length - len < chunk_size_)
392
15.6k
        {
393
15.6k
            data_end_ = chunk_;
394
15.6k
            remaining_ = fill_buffer(chunk_, chunk_size_);
395
15.6k
            if (remaining_ > 0)
396
11.3k
            {
397
11.3k
                std::size_t len2 = (std::min)(remaining_, length-len);
398
11.3k
                std::memcpy(p+len, data_end_, len2*sizeof(value_type));
399
11.3k
                data_end_ += len2;
400
11.3k
                remaining_ -= len2;
401
11.3k
                position_ += len2;
402
11.3k
                len += len2;
403
11.3k
            }
404
15.6k
            return len;
405
15.6k
        }
406
0
        else
407
0
        {
408
0
            if (stream_ptr_->eof())
409
0
            {
410
0
                remaining_ = 0;
411
0
                return 0;
412
0
            }
413
0
            JSONCONS_TRY
414
0
            {
415
0
                std::streamsize count = sbuf_->sgetn(reinterpret_cast<char_type*>(p+len), length-len);
416
0
                std::size_t len2 = static_cast<std::size_t>(count);
417
0
                if (len2 < length-len)
418
0
                {
419
0
                    stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::eofbit);
420
0
                }
421
0
                len += len2;
422
0
                position_ += len2;
423
0
                return len;
424
0
            }
425
0
            JSONCONS_CATCH(const std::exception&)     
426
0
            {
427
0
                stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::badbit | std::ios::eofbit);
428
0
                return 0;
429
0
            }
430
0
        }
431
40.4M
    }
432
private:
433
434
    std::size_t read_buffer(value_type* chunk, std::size_t chunk_size)
435
684
    {
436
684
        auto len = fill_buffer(chunk, chunk_size);
437
684
        position_ += len;
438
684
        return len;
439
684
    }
440
441
    std::size_t fill_buffer(value_type* chunk, std::size_t chunk_size)
442
16.5k
    {
443
16.5k
        if (stream_ptr_->eof())
444
4.38k
        {
445
4.38k
            return 0;
446
4.38k
        }
447
448
12.1k
        JSONCONS_TRY
449
12.1k
        {
450
12.1k
            std::streamsize count = sbuf_->sgetn(reinterpret_cast<char_type*>(chunk), chunk_size);
451
12.1k
            std::size_t length = static_cast<std::size_t>(count);
452
453
12.1k
            if (length < chunk_size)
454
6.51k
            {
455
6.51k
                stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::eofbit);
456
6.51k
            }
457
12.1k
            return length;
458
12.1k
        }
459
12.1k
        JSONCONS_CATCH(const std::exception&)     
460
12.1k
        {
461
0
            stream_ptr_->clear(stream_ptr_->rdstate() | std::ios::badbit | std::ios::eofbit);
462
0
            return 0;
463
0
        }
464
12.1k
    }
465
};
466
467
template <typename CharT,typename Allocator>
468
constexpr std::size_t stream_source<CharT,Allocator>::default_max_chunk_size;
469
470
// chars_source
471
472
template <typename CharT>
473
class chars_source 
474
{
475
public:
476
    using value_type = CharT;
477
private:
478
    const value_type* data_end_{nullptr};
479
    const value_type* current_{nullptr};
480
    const value_type* end_{nullptr};
481
public:
482
    chars_source() noexcept = default;
483
484
    // Noncopyable 
485
    chars_source(const chars_source&) = delete;
486
487
    chars_source(chars_source&& other) = default;
488
489
    template <typename Sourceable,typename ChT=CharT>
490
    chars_source(const Sourceable& s,
491
        typename std::enable_if<nonstd::is_byte<ChT>::value && nonstd::is_byte<typename Sourceable::value_type>::value>::type* = 0)
492
        : data_end_(reinterpret_cast<const value_type*>(s.data())), current_(data_end_), end_(data_end_+s.size())
493
    {
494
    }
495
496
    template <typename Sourceable,typename ChT=CharT>
497
    chars_source(const Sourceable& s,
498
        typename std::enable_if<nonstd::is_wide_character<ChT>::value && nonstd::is_wide_character<typename Sourceable::value_type>::value>::type* = 0)
499
        : data_end_(s.data()), current_(s.data()), end_(s.data()+s.size())
500
    {
501
    }
502
503
    chars_source& operator=(const chars_source&) = delete;
504
    chars_source& operator=(chars_source&& other) = default;
505
506
    bool eof() const
507
    {
508
        return current_ == end_;  
509
    }
510
511
    bool is_error() const
512
    {
513
        return false;  
514
    }
515
516
    std::size_t position() const
517
    {
518
        return (current_ - data_end_)/sizeof(value_type);
519
    }
520
521
    void ignore(std::size_t count)
522
    {
523
        std::size_t len;
524
        if (std::size_t(end_ - current_) < count)
525
        {
526
            len = end_ - current_;
527
        }
528
        else
529
        {
530
            len = count;
531
        }
532
        current_ += len;
533
    }
534
535
    char_result<value_type> peek() 
536
    {
537
        return current_ < end_ ? char_result<value_type>{*current_, false} : char_result<value_type>{0, true};
538
    }
539
540
    std::size_t chunk_size() const
541
    {
542
        return end_ - current_;
543
    }
544
545
    span<const value_type> read_chunk() 
546
    {
547
        const value_type* data = current_;
548
        std::size_t length = end_ - current_;
549
        current_ = end_;
550
551
        return span<const value_type>(data, length);
552
    }
553
554
555
    std::size_t read_buffer(value_type* chunk, std::size_t chunk_size)
556
    {
557
        auto len = fill_buffer(chunk, chunk_size);
558
        //position_ += len;
559
        return len;
560
    }
561
562
    std::size_t fill_buffer(value_type* chunk, std::size_t chunk_size)
563
    {
564
        return read(chunk, chunk_size);
565
    }
566
567
    std::size_t remaining() const
568
    {
569
        return std::size_t(end_ - current_);
570
    }
571
572
    template <typename Buffer>
573
    span<const value_type> read_span(std::size_t length, Buffer&&)
574
    {
575
        if (JSONCONS_UNLIKELY(length == 0))
576
        {
577
            return span<const value_type>{};
578
        }
579
        std::size_t remaining = std::size_t(end_ - current_);
580
        std::size_t len = remaining < length ? remaining : length;
581
582
        const value_type* data = current_;
583
        current_ += len;
584
        return span<const value_type>(data, len);
585
    }
586
587
    std::size_t read(value_type* p, std::size_t length)
588
    {
589
        std::size_t len;
590
        if (std::size_t(end_ - current_) < length)
591
        {
592
            len = end_ - current_;
593
        }
594
        else
595
        {
596
            len = length;
597
        }
598
        std::memcpy(p, current_, len*sizeof(value_type));
599
        current_  += len;
600
        return len;
601
    }
602
};
603
604
// iterator source
605
606
template <typename IteratorT>
607
class iterator_source
608
{
609
public:
610
    using value_type = typename std::iterator_traits<IteratorT>::value_type;
611
private:
612
    static constexpr std::size_t default_max_chunk_size = 16384;
613
614
    IteratorT current_;
615
    IteratorT end_;
616
    std::size_t position_{0};
617
    std::vector<value_type> chunk_; // used by read_chunk to return a whole chunk, nothing is left in the chunk
618
    std::size_t chunk_size_{0};
619
620
    using difference_type = typename std::iterator_traits<IteratorT>::difference_type;
621
    using iterator_category = typename std::iterator_traits<IteratorT>::iterator_category;
622
public:
623
624
    // Noncopyable 
625
    iterator_source(const iterator_source&) = delete;
626
627
    iterator_source(iterator_source&& other) = default;
628
629
    iterator_source(const IteratorT& first, const IteratorT& last, std::size_t chunk_size = default_max_chunk_size)
630
        : current_(first), end_(last), chunk_(chunk_size)
631
    {
632
    }
633
    
634
    ~iterator_source() = default;
635
636
    iterator_source& operator=(const iterator_source&) = delete;
637
    iterator_source& operator=(iterator_source&& other) = default;
638
639
    bool eof() const
640
    {
641
        return !(current_ != end_);  
642
    }
643
644
    bool is_error() const
645
    {
646
        return false;  
647
    }
648
649
    std::size_t position() const
650
    {
651
        return position_;
652
    }
653
654
    void ignore(std::size_t count)
655
    {
656
        while (count-- > 0 && current_ != end_)
657
        {
658
            ++position_;
659
            ++current_;
660
        }
661
    }
662
663
    char_result<value_type> peek() 
664
    {
665
        return current_ != end_ ? char_result<value_type>{*current_, false} : char_result<value_type>{0, true};
666
    }
667
668
    std::size_t chunk_size() const
669
    {
670
        return chunk_.size();
671
    }
672
673
    span<const value_type> read_chunk() 
674
    {
675
        auto len = read(chunk_.data(), chunk_.size());
676
        return span<const value_type>(chunk_.data(), len);
677
    }
678
679
    std::size_t read_buffer(value_type* chunk, std::size_t chunk_size)
680
    {
681
        auto len = fill_buffer(chunk, chunk_size);
682
        position_ += len;
683
        return len;
684
    }
685
686
    std::size_t fill_buffer(value_type* chunk, std::size_t chunk_size)
687
    {
688
        value_type* p = chunk;
689
        value_type* pend = chunk + chunk_size;
690
691
        while (p < pend && current_ != end_)
692
        {
693
            *p = static_cast<value_type>(*current_);
694
            ++p;
695
            ++current_;
696
        }
697
698
        return p - chunk;
699
    }
700
701
    std::size_t remaining() const
702
    {
703
        return 0;
704
    }
705
706
    template <typename Buffer>
707
    span<const value_type> read_span(std::size_t length, Buffer&& buffer)
708
    {
709
        if (JSONCONS_UNLIKELY(length == 0))
710
        {
711
            return span<const value_type>{};
712
        }
713
714
        if (length <= chunk_.size())
715
        {
716
            auto len = fill_buffer(chunk_.data(), length);
717
            position_ += len;
718
            return span<const value_type>(chunk_.data(), len);
719
        }
720
721
        buffer.clear();
722
        source_reader<iterator_source<IteratorT>>::read(*this, buffer, length);
723
        return span<const value_type>(reinterpret_cast<const value_type*>(buffer.data()), buffer.size());
724
    }
725
726
    std::size_t read(value_type* data, std::size_t length)
727
    {
728
        std::size_t len = fill_buffer(data, length);
729
730
        position_ += len;
731
732
        return len;
733
    }
734
};
735
736
template <typename Source>
737
struct source_reader
738
{
739
    using value_type = typename Source::value_type;
740
741
    template <typename Buffer>
742
    static
743
    typename std::enable_if<nonstd::is_byte<value_type>::value &&
744
        nonstd::is_byte<typename Buffer::value_type>::value, std::size_t>::type
745
    read(Source& source, Buffer& buffer, std::size_t length)
746
1.08k
    {
747
1.08k
        std::size_t unread = length;
748
749
4.78k
        while (unread > 0 && !source.eof())
750
3.70k
        {
751
3.70k
            if (source.remaining() == 0 && unread >= source.chunk_size())
752
684
            {
753
684
                std::size_t n = source.chunk_size();
754
684
                std::size_t offset = buffer.size();
755
684
                buffer.resize(offset+n);
756
684
                std::size_t actual = source.read_buffer(reinterpret_cast<value_type*>(&buffer[0]) + offset, n);
757
684
                if (JSONCONS_UNLIKELY(actual != n))
758
78
                {
759
78
                    buffer.resize(offset+actual);
760
78
                }
761
684
                unread -= actual;
762
684
            }
763
3.02k
            else
764
3.02k
            {
765
3.02k
                std::size_t n = (std::min)(source.chunk_size(), unread);
766
3.02k
                std::size_t offset = buffer.size();
767
3.02k
                buffer.resize(offset+n);
768
3.02k
                std::size_t actual = source.read(reinterpret_cast<value_type*>(&buffer[0]) + offset, n);
769
3.02k
                if (JSONCONS_UNLIKELY(actual != n))
770
234
                {
771
234
                    buffer.resize(offset + actual);
772
234
                }
773
3.02k
                unread -= actual;
774
3.02k
            }
775
3.70k
        }
776
1.08k
        return length - unread;
777
1.08k
    }
778
779
    template <typename Buffer>
780
    static
781
    typename std::enable_if<!nonstd::is_byte<value_type>::value &&
782
                            nonstd::has_reserve<Buffer>::value &&
783
                            nonstd::has_data_exact<value_type*,Buffer>::value, std::size_t>::type
784
    read(Source& source, Buffer& buffer, std::size_t length)
785
    {
786
        std::size_t unread = length;
787
788
        while (unread > 0 && !source.eof())
789
        {
790
            if (source.remaining() == 0 && unread >= source.chunk_size())
791
            {
792
                std::size_t n = source.chunk_size();
793
                std::size_t offset = buffer.size();
794
                buffer.resize(offset+n);
795
                std::size_t actual = source.read_buffer(&buffer[0]+offset, n);
796
                if (JSONCONS_UNLIKELY(actual != n))
797
                {
798
                    buffer.resize(offset + actual);
799
                }
800
                unread -= actual;
801
            }
802
            else
803
            {
804
                std::size_t n = (std::min)(source.chunk_size(), unread);
805
                std::size_t offset = buffer.size();
806
                buffer.resize(offset+n);
807
                std::size_t actual = source.read(&buffer[0]+offset, n);
808
                if (JSONCONS_UNLIKELY(actual != n))
809
                {
810
                    buffer.resize(offset + actual);
811
                }
812
                unread -= actual;
813
            }
814
        }
815
816
        return length - unread;
817
    }
818
};
819
820
#if !defined(JSONCONS_NO_DEPRECATED)
821
822
template <typename CharT>
823
using string_source = chars_source<CharT>;
824
825
#endif
826
827
using binary_stream_source = stream_source<uint8_t>;
828
829
using bytes_source = chars_source<uint8_t>;
830
831
} // namespace jsoncons
832
833
#endif // JSONCONS_SOURCE_HPP