Coverage Report

Created: 2026-01-10 06:46

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