scnlib  0.1.2
FormattedinputformodernC++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups
istream.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_ISTREAM_H
19 #define SCN_DETAIL_ISTREAM_H
20 
21 #include "stream.h"
22 #include "types.h"
23 
24 #include <istream>
25 
26 namespace scn {
29  SCN_CLANG_IGNORE("-Wpadded")
30 
31  template <typename CharT>
33  public:
34  using char_type = CharT;
35  using source_type = std::basic_istream<char_type>;
36  using traits = typename source_type::traits_type;
37 
39  : m_is(std::addressof(is)), m_read{}, m_it(m_read.begin())
40  {
41  }
42 
43  expected<char_type> read_char();
44 
46  {
47  SCN_EXPECT(m_it != m_read.begin());
48  --m_it;
49  return {};
50  }
51 
53  {
54  m_read.clear();
55  m_it = m_read.end();
56  return {};
57  }
59  {
60  m_it = m_read.begin();
61  return {};
62  }
63 
64  private:
66  using iterator = typename buffer_type::iterator;
67 
68  source_type* m_is;
69  buffer_type m_read{};
70  iterator m_it;
71  };
72 
74 
75  template <typename CharT>
77  std::basic_istream<CharT>& is) noexcept
78  {
79  return {is};
80  }
81 
82  namespace detail {
84  SCN_CLANG_IGNORE("-Wpadded")
85 
86  template <typename Stream, typename CharT>
87  class stream_std_streambuf : public std::basic_streambuf<CharT> {
88  using base = std::basic_streambuf<CharT>;
89 
90  public:
91  using stream_type = Stream;
92  using char_type = CharT;
93  using traits_type = typename base::traits_type;
94  using int_type = typename base::int_type;
95 
96  explicit stream_std_streambuf(Stream& s)
97  : m_stream(std::addressof(s))
98  {
99  }
100 
101  private:
102  int_type underflow() override
103  {
104  if (m_read) {
105  return traits_type::to_int_type(m_ch);
106  }
107  auto ret = m_stream->read_char();
108  if (!ret) {
109  return traits_type::eof();
110  }
111  m_ch = ret.value();
112  m_read = true;
113  return traits_type::to_int_type(m_ch);
114  }
115  int_type uflow() override
116  {
117  auto ret = underflow();
118  if (ret != traits_type::eof()) {
119  m_read = false;
120  }
121  return ret;
122  }
123  std::streamsize showmanyc() override
124  {
125  return m_read ? 1 : 0;
126  }
127  int_type pbackfail(int_type c = traits_type::eof()) override
128  {
129  if (c == traits_type::eof()) {
130  c = 0;
131  }
132  auto ret = m_stream->putback(traits_type::to_char_type(c));
133  if (!ret) {
134  return traits_type::eof();
135  }
136  return traits_type::to_int_type(m_ch);
137  }
138 
139  Stream* m_stream;
140  char_type m_ch{};
141  bool m_read{false};
142  };
143 
145 
146  // Trick stolen from fmtlib
147  template <typename CharT>
148  struct test_std_stream : std::basic_istream<CharT> {
149  private:
150  struct null;
151  // Hide all operator>> from std::basic_istream<CharT>
152  void operator>>(null);
153  };
154 
155  // Check for user-defined operator>>
156  template <typename CharT, typename T, typename = void>
157  struct is_std_streamable : std::false_type {
158  };
159 
160  template <typename CharT, typename T>
162  CharT,
163  T,
164  void_t<decltype(std::declval<test_std_stream<CharT>&>() >>
165  std::declval<T&>())>> : std::true_type {
166  };
167  } // namespace detail
168 
169  template <typename CharT, typename T>
170  struct scanner<CharT,
171  T,
172  typename std::enable_if<
173  detail::is_std_streamable<CharT, T>::value>::type>
174  : public empty_parser<CharT> {
175  template <typename Context>
176  error scan(T& val, Context& ctx)
177  {
179  streambuf(ctx.stream());
180  std::basic_istream<CharT> stream(std::addressof(streambuf));
181 
182  if (!(stream >> val)) {
183  ctx.stream()._set_bad();
185  "Bad stream after reading");
186  }
187  return {};
188  }
189  };
191 } // namespace scn
192 
193 #if defined(SCN_HEADER_ONLY) && SCN_HEADER_ONLY && !defined(SCN_ISTREAM_CPP)
194 #include "istream.cpp"
195 #endif
196 
197 #endif // SCN_DETAIL_ISTREAM_H
198 
SCN_CLANG_POP basic_std_istream_stream< CharT > make_stream(std::basic_istream< CharT > &is) noexcept
Definition: istream.h:76
typename make_void< Ts...>::type void_t
Definition: util.h:42
#define SCN_END_NAMESPACE
Definition: config.h:376
#define SCN_CLANG_IGNORE(x)
Definition: config.h:128
typename base::int_type int_type
Definition: istream.h:94
typename base::traits_type traits_type
Definition: istream.h:93
#define SCN_CLANG_POP
Definition: config.h:127
std::basic_istream< char_type > source_type
Definition: istream.h:35
error putback(char_type)
Definition: istream.h:45
Error class.
Definition: result.h:32
#define SCN_BEGIN_NAMESPACE
Definition: config.h:375
The stream source emitted an error that cannot be recovered from.
Definition: result.h:61
typename source_type::traits_type traits
Definition: istream.h:36
basic_std_istream_stream(source_type &is)
Definition: istream.h:38
#define SCN_EXPECT(cond)
Definition: config.h:371
#define SCN_CLANG_PUSH
Definition: config.h:126