scnlib  0.1.2
FormattedinputformodernC++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups
stream.h
Go to the documentation of this file.
1 // Copyright 2017-2019 Elias Kosunen
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // This file is a part of scnlib:
16 // https://github.com/eliaskosunen/scnlib
17 
18 #ifndef SCN_DETAIL_STREAM_H
19 #define SCN_DETAIL_STREAM_H
20 
21 #include "result.h"
22 #include "small_vector.h"
23 #include "string_view.h"
24 
26 SCN_CLANG_IGNORE("-Wpadded")
27 
28 namespace scn {
30 
214  template <typename S>
215  struct is_sized_stream : S::is_sized_stream {
216  };
217 
218  struct stream_base {
219  using is_sized_stream = std::false_type;
220 
221  SCN_CONSTEXPR14 void _set_bad() noexcept
222  {
223  m_bad = true;
224  }
225 
226  SCN_CONSTEXPR bool bad() const noexcept
227  {
228  return m_bad;
229  }
230 
231  SCN_CONSTEXPR explicit operator bool() const noexcept
232  {
233  return !bad();
234  }
235 
236  private:
237  bool m_bad{false};
238  };
239 
240  template <typename Char>
242  public:
243  using char_type = Char;
244 
246  {
247  ++m_read;
248  return error(error::end_of_stream, "Null stream EOF");
249  }
251  {
252  SCN_EXPECT(m_read != 0);
253  --m_read;
254  return {};
255  }
256 
258  {
259  m_read = 0;
260  return {};
261  }
263  {
264  m_read = 0;
265  return {};
266  }
267 
268  SCN_CONSTEXPR size_t rcount() const noexcept
269  {
270  return m_read;
271  }
272 
273  private:
274  size_t m_read{0};
275  };
276  template <typename CharT>
278  {
279  return basic_null_stream<CharT>{};
280  }
281 
282  template <typename Char, typename Source, typename Enable = void>
284 
285  template <typename Char, typename Container>
286  class basic_static_container_stream<Char, Container> : public stream_base {
287  public:
288  using char_type = Char;
289  using source_type = Container;
290  using iterator = typename source_type::const_iterator;
291  using is_sized_stream = std::true_type;
292 
294  const source_type& s) noexcept
295  : m_source(std::addressof(s)), m_begin(_begin(s)), m_next(begin())
296  {
297  }
298 
300  {
301  if (SCN_UNLIKELY(m_next == end())) {
302  return error(error::end_of_stream, "EOF");
303  }
304  auto ch = *m_next;
305  ++m_next;
306  return ch;
307  }
309  {
310  SCN_EXPECT(m_begin != m_next);
311  --m_next;
312  return {};
313  }
314 
316  {
317  SCN_EXPECT(chars_to_read() >= static_cast<size_t>(s.size()));
318  std::copy(m_next, m_next + s.ssize(), s.begin());
319  m_next += s.ssize();
320  }
321 
322  SCN_CONSTEXPR14 void putback_n(size_t n) noexcept
323  {
324  SCN_EXPECT(rcount() >= n);
325  m_next -= static_cast<std::ptrdiff_t>(n);
326  }
327 
329  {
330  m_begin = m_next;
331  return {};
332  }
334  {
335  m_next = begin();
336  return {};
337  }
338 
339  size_t rcount() const noexcept
340  {
341  return static_cast<size_t>(std::distance(m_begin, m_next));
342  }
343 
344  SCN_CONSTEXPR14 size_t chars_to_read() const noexcept
345  {
346  return static_cast<size_t>(std::distance(m_next, end()));
347  }
348 
349  SCN_CONSTEXPR14 void skip(size_t n) noexcept
350  {
351  SCN_EXPECT(chars_to_read() >= n);
352  m_next += static_cast<std::ptrdiff_t>(n);
353  }
354  SCN_CONSTEXPR14 void skip_all() noexcept
355  {
356  m_next = end();
357  }
358 
359  private:
360  SCN_CONSTEXPR iterator begin() const noexcept
361  {
362  return m_begin;
363  }
364  SCN_CONSTEXPR14 iterator end() const noexcept
365  {
366  using std::end;
367  return end(*m_source);
368  }
369 
370  static SCN_CONSTEXPR14 iterator _begin(const source_type& s) noexcept
371  {
372  using std::begin;
373  return begin(s);
374  }
375 
376  const source_type* m_source;
377  iterator m_begin, m_next{};
378  };
379 
380  template <typename ContiguousContainer,
381  typename = decltype(std::declval<ContiguousContainer&>().data(),
382  void())>
383  basic_static_container_stream<typename ContiguousContainer::value_type,
384  ContiguousContainer>
385  make_stream(const ContiguousContainer& c)
386  {
387  return {c};
388  }
389 
390  template <typename Char>
391  class basic_static_container_stream<Char, span<const Char>>
392  : public stream_base {
393  public:
394  using char_type = Char;
397  using is_sized_stream = std::true_type;
398 
400  : m_source(s), m_begin(m_source.begin()), m_next(begin())
401  {
402  }
403 
405  {
406  if (m_next == end()) {
407  return error(error::end_of_stream, "EOF");
408  }
409  auto ch = *m_next;
410  ++m_next;
411  return ch;
412  }
414  {
415  SCN_EXPECT(m_begin != m_next);
416  --m_next;
417  return {};
418  }
419 
421  {
422  SCN_EXPECT(chars_to_read() >= s.size());
423  std::memcpy(s.begin(), m_next, s.size() * sizeof(char_type));
424  /* std::copy(m_next, m_next + s.size(), s.begin()); */
425  m_next += s.size();
426  return {};
427  } // namespace scn
428 
429  error putback_n(size_t n) noexcept
430  {
431  SCN_EXPECT(rcount() >= n);
432  m_next -= n;
433  return {};
434  }
435 
437  {
438  m_begin = m_next;
439  return {};
440  }
442  {
443  m_next = begin();
444  return {};
445  }
446 
447  size_t rcount() const noexcept
448  {
449  return static_cast<size_t>(std::distance(m_begin, m_next));
450  }
451 
452  SCN_CONSTEXPR14 size_t chars_to_read() const noexcept
453  {
454  return static_cast<size_t>(std::distance(m_next, end()));
455  }
456 
457  SCN_CONSTEXPR14 void skip(size_t n) noexcept
458  {
459  SCN_EXPECT(chars_to_read() >= n);
460  m_next += n;
461  }
462  SCN_CONSTEXPR14 void skip_all() noexcept
463  {
464  m_next = end();
465  }
466 
467  private:
468  SCN_CONSTEXPR iterator begin() const noexcept
469  {
470  return m_begin;
471  }
472  SCN_CONSTEXPR iterator end() const noexcept
473  {
474  return m_source.end();
475  }
476 
477  source_type m_source;
478  iterator m_begin{}, m_next{};
479  };
480 
481  template <typename CharT>
483  span<const CharT> s) noexcept
484  {
485  return {s};
486  }
487 
488  template <typename CharT, size_t N>
490  const CharT (&arr)[N])
491  {
492  return {{arr, N - 1}};
493  }
494 
495  template <typename Iterator>
497  using char_type = typename std::iterator_traits<Iterator>::value_type;
498  using is_sized_stream = std::true_type;
499 
501  Iterator end) noexcept
502  : m_begin(begin), m_end(end), m_next(begin)
503  {
504  }
505 
507  {
508  if (m_next == m_end) {
509  return error(error::end_of_stream, "EOF");
510  }
511  auto ch = *m_next;
512  ++m_next;
513  return ch;
514  }
516  {
517  SCN_EXPECT(m_begin != m_next);
518  --m_next;
519  return {};
520  }
521 
523  {
524  SCN_EXPECT(chars_to_read() >= static_cast<size_t>(s.size()));
525  std::copy(m_next, m_next + s.ssize(), s.begin());
526  std::advance(m_next, s.ssize());
527  return {};
528  }
529 
530  error putback_n(size_t n) noexcept
531  {
532  SCN_EXPECT(rcount() >= n);
533  m_next -= static_cast<std::ptrdiff_t>(n);
534  return {};
535  }
536 
538  {
539  m_begin = m_next;
540  return {};
541  }
543  {
544  m_next = m_begin;
545  return {};
546  }
547 
548  size_t rcount() const noexcept
549  {
550  return static_cast<size_t>(std::distance(m_begin, m_next));
551  }
552 
553  SCN_CONSTEXPR14 size_t chars_to_read() const noexcept
554  {
555  return static_cast<size_t>(std::distance(m_next, m_end));
556  }
557 
558  SCN_CONSTEXPR14 void skip(size_t n) noexcept
559  {
560  SCN_EXPECT(chars_to_read() >= n);
561  m_next += static_cast<std::ptrdiff_t>(n);
562  }
563  SCN_CONSTEXPR14 void skip_all() noexcept
564  {
565  m_next = m_end;
566  }
567 
568  private:
569  Iterator m_begin, m_end, m_next;
570  };
571 
572  template <typename Iterator>
574  using char_type = typename std::iterator_traits<Iterator>::value_type;
575 
577  Iterator end) noexcept
578  : m_begin(begin), m_end(end), m_read{}, m_read_it(m_read.begin())
579  {
580  }
581 
583  {
584  if (m_read_it != m_read.end()) {
585  auto ch = *m_read_it;
586  ++m_read_it;
587  return ch;
588  }
589  if (m_begin == m_end) {
590  return error(error::end_of_stream, "EOF");
591  }
592  auto ch = *m_begin;
593  ++m_begin;
594  m_read.push_back(ch);
595  m_read_it = m_read.end();
596  return ch;
597  }
599  {
600  SCN_EXPECT(m_read_it != m_read.begin());
601  --m_read_it;
602  return {};
603  }
604 
605  error set_roll_back() noexcept
606  {
607  m_read.clear();
608  m_read_it = m_read.end();
609  return {};
610  }
611  error roll_back() noexcept
612  {
613  m_read_it = m_read.begin();
614  return {};
615  }
616 
617  size_t rcount() const noexcept
618  {
619  return m_read.size();
620  }
621 
622  private:
624 
625  Iterator m_begin, m_end;
626  buffer_type m_read;
627  typename buffer_type::iterator m_read_it;
628  };
629 
630  namespace detail {
631  template <typename Iterator>
633  using iterator = Iterator;
635 
637  iterator e) noexcept
638  {
639  return {b, e};
640  }
641  };
642  template <typename Iterator>
644  using iterator = Iterator;
646 
647  static type make_stream(iterator b, iterator e) noexcept
648  {
649  return {b, e};
650  }
651  };
652 
653  template <typename Iterator, typename Tag>
655  template <typename Iterator>
656  struct iterator_stream<Iterator, std::forward_iterator_tag>
657  : public fwd_iterator_stream<Iterator> {
658  };
659  template <typename Iterator>
660  struct iterator_stream<Iterator, std::bidirectional_iterator_tag>
661  : public bidir_iterator_stream<Iterator> {
662  };
663  template <typename Iterator>
664  struct iterator_stream<Iterator, std::random_access_iterator_tag>
665  : public bidir_iterator_stream<Iterator> {
666  };
667  } // namespace detail
668 
669  template <typename Iterator,
670  typename StreamHelper = detail::iterator_stream<
671  Iterator,
672  typename std::iterator_traits<Iterator>::iterator_category>>
673  typename StreamHelper::type make_stream(Iterator begin, Iterator end)
674  {
675  return StreamHelper::make_stream(begin, end);
676  }
677 
678  template <typename CharT>
680 
681  template <>
682  struct basic_cstdio_stream<char> : public stream_base {
683  using char_type = char;
684 
685  basic_cstdio_stream(FILE* f) noexcept : m_file(f) {}
686 
687  expected<char_type> read_char();
688  error putback(char_type ch) noexcept;
689 
691  {
692  m_read.clear();
693  return {};
694  }
695  error roll_back() noexcept;
696 
697  size_t rcount() const noexcept
698  {
699  return m_read.size();
700  }
701 
702  private:
703  FILE* m_file;
705  };
706  template <>
707  struct basic_cstdio_stream<wchar_t> : public stream_base {
708  using char_type = wchar_t;
709 
710  basic_cstdio_stream(FILE* f) noexcept : m_file(f) {}
711 
712  expected<char_type> read_char();
713  error putback(char_type ch) noexcept;
714 
715  error set_roll_back() noexcept
716  {
717  m_read.clear();
718  return {};
719  }
720  error roll_back() noexcept;
721 
722  size_t rcount() const noexcept
723  {
724  return m_read.size();
725  }
726 
727  private:
728  FILE* m_file;
730  };
731 
732  template <typename CharT = char>
734  {
735  return {f};
736  }
738  {
739  return {f};
740  }
742  {
743  return {f};
744  }
745 
747 } // namespace scn
748 
750 
751 #if defined(SCN_HEADER_ONLY) && SCN_HEADER_ONLY && !defined(SCN_STREAM_CPP)
752 #include "stream.cpp"
753 #endif
754 
755 #endif // SCN_DETAIL_STREAM_H
SCN_CONSTEXPR bool bad() const noexcept
Definition: stream.h:226
static SCN_CONSTEXPR type make_stream(iterator b, iterator e) noexcept
Definition: stream.h:636
error set_roll_back() noexcept
Definition: stream.h:605
SCN_CONSTEXPR14 void _set_bad() noexcept
Definition: stream.h:221
static type make_stream(iterator b, iterator e) noexcept
Definition: stream.h:647
#define SCN_END_NAMESPACE
Definition: config.h:376
error roll_back() noexcept
Definition: stream.h:611
SCN_CONSTEXPR14 error roll_back() noexcept
Definition: stream.h:542
#define SCN_UNLIKELY(x)
Definition: config.h:337
basic_cstdio_stream(FILE *f) noexcept
Definition: stream.h:710
error putback_n(size_t n) noexcept
Definition: stream.h:530
expected< char_type > read_char() noexcept
Definition: stream.h:582
SCN_CONSTEXPR14 error roll_back() noexcept
Definition: stream.h:333
basic_cstdio_stream< char > make_narrow_stream(FILE *f) noexcept
Definition: stream.h:737
SCN_CONSTEXPR14 void skip(size_t n) noexcept
Definition: stream.h:349
SCN_CONSTEXPR basic_bidirectional_iterator_stream(Iterator begin, Iterator end) noexcept
Definition: stream.h:500
SCN_CONSTEXPR14 expected< char_type > read_char() noexcept
Definition: stream.h:506
SCN_CONSTEXPR14 expected< char_type > read_char() noexcept
Definition: stream.h:299
typename source_type::const_iterator iterator
Definition: stream.h:396
SCN_CONSTEXPR14 void skip_all() noexcept
Definition: stream.h:354
size_t rcount() const noexcept
Definition: stream.h:548
SCN_CONSTEXPR14 void skip_all() noexcept
Definition: stream.h:563
basic_cstdio_stream(FILE *f) noexcept
Definition: stream.h:685
#define SCN_CLANG_IGNORE(x)
Definition: config.h:128
SCN_CONSTEXPR14 void read_sized(span< char_type > s) noexcept
Definition: stream.h:315
std::false_type is_sized_stream
Definition: stream.h:219
SCN_CONSTEXPR14 size_t chars_to_read() const noexcept
Definition: stream.h:344
expected-like type.
Definition: result.h:186
SCN_CONSTEXPR14 error roll_back() noexcept
Definition: stream.h:262
#define SCN_CLANG_POP
Definition: config.h:127
const_pointer const_iterator
Definition: span.h:44
SCN_CONSTEXPR14 error set_roll_back() noexcept
Definition: stream.h:328
SCN_CONSTEXPR14 error set_roll_back() noexcept
Definition: stream.h:257
Error class.
Definition: result.h:32
SCN_CONSTEXPR14 error putback(char_type) noexcept
Definition: stream.h:308
SCN_CONSTEXPR14 error read_sized(span< char_type > s) noexcept
Definition: stream.h:522
SCN_CONSTEXPR14 size_t chars_to_read() const noexcept
Definition: stream.h:452
#define SCN_BEGIN_NAMESPACE
Definition: config.h:375
typename std::iterator_traits< Iterator >::value_type char_type
Definition: stream.h:497
error set_roll_back() noexcept
Definition: stream.h:715
error read_sized(span< char_type > s) noexcept
Definition: stream.h:420
SCN_CONSTEXPR14 error putback(char_type) noexcept
Definition: stream.h:250
SCN_CONSTEXPR14 error set_roll_back() noexcept
Definition: stream.h:537
basic_null_stream< CharT > make_null_stream() noexcept
Definition: stream.h:277
SCN_CONSTEXPR14 error putback(char_type) noexcept
Definition: stream.h:515
SCN_CONSTEXPR basic_static_container_stream(const source_type &s) noexcept
Definition: stream.h:293
SCN_CONSTEXPR size_t rcount() const noexcept
Definition: stream.h:268
SCN_CONSTEXPR basic_forward_iterator_stream(Iterator begin, Iterator end) noexcept
Definition: stream.h:576
SCN_CONSTEXPR basic_static_container_stream(source_type s) noexcept
Definition: stream.h:399
basic_cstdio_stream< CharT > make_stream(FILE *f) noexcept
Definition: stream.h:733
SCN_CONSTEXPR14 error putback(char_type) noexcept
Definition: stream.h:413
SCN_CONSTEXPR14 size_t chars_to_read() const noexcept
Definition: stream.h:553
SCN_CONSTEXPR14 void putback_n(size_t n) noexcept
Definition: stream.h:322
typename std::iterator_traits< Iterator >::value_type char_type
Definition: stream.h:574
SCN_CONSTEXPR14 expected< char_type > read_char() noexcept
Definition: stream.h:245
#define SCN_CONSTEXPR
Definition: config.h:226
SCN_CONSTEXPR14 void skip(size_t n) noexcept
Definition: stream.h:457
SCN_CONSTEXPR14 void skip(size_t n) noexcept
Definition: stream.h:558
size_t rcount() const noexcept
Definition: stream.h:617
SCN_CONSTEXPR14 expected< char_type > read_char() noexcept
Definition: stream.h:404
basic_cstdio_stream< wchar_t > make_wide_stream(FILE *f) noexcept
Definition: stream.h:741
typename source_type::const_iterator iterator
Definition: stream.h:290
#define SCN_EXPECT(cond)
Definition: config.h:371
#define SCN_CLANG_PUSH
Definition: config.h:126
#define SCN_CONSTEXPR14
Definition: config.h:227