scnlib  0.2.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
visitor.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_VISITOR_H
19 #define SCN_DETAIL_VISITOR_H
20 
21 #include "reader.h"
22 
23 namespace scn {
25 
26  template <typename Context, typename ParseCtx>
27  class basic_visitor {
28  public:
29  using context_type = Context;
30  using char_type = typename Context::char_type;
31 
32  basic_visitor(Context& ctx, ParseCtx& pctx)
33  : m_ctx(std::addressof(ctx)), m_pctx(std::addressof(pctx))
34  {
35  }
36 
37  template <typename T>
38  auto operator()(T&& val) -> error
39  {
40  return visit(std::forward<T>(val), detail::priority_tag<1>{});
41  }
42 
43  private:
44  auto visit(char_type& val, detail::priority_tag<1>) -> error
45  {
47  auto err = parse(s);
48  if (!err) {
49  return err;
50  }
51  return s.scan(val, *m_ctx);
52  }
53  auto visit(span<char_type>& val, detail::priority_tag<1>) -> error
54  {
55  detail::buffer_scanner s;
56  auto err = parse(s);
57  if (!err) {
58  return err;
59  }
60  return s.scan(val, *m_ctx);
61  }
62  auto visit(bool& val, detail::priority_tag<1>) -> error
63  {
64  detail::bool_scanner s;
65  auto err = parse(s);
66  if (!err) {
67  return err;
68  }
69  return s.scan(val, *m_ctx);
70  }
71 
72 #define SCN_VISIT_INT(T) \
73  error visit(T& val, detail::priority_tag<0>) \
74  { \
75  detail::integer_scanner<T> s; \
76  auto err = parse(s); \
77  if (!err) { \
78  return err; \
79  } \
80  return s.scan(val, *m_ctx); \
81  }
82  SCN_VISIT_INT(short)
83  SCN_VISIT_INT(int)
84  SCN_VISIT_INT(long)
85  SCN_VISIT_INT(long long)
86  SCN_VISIT_INT(unsigned short)
87  SCN_VISIT_INT(unsigned int)
88  SCN_VISIT_INT(unsigned long)
89  SCN_VISIT_INT(unsigned long long)
90 #undef SCN_VISIT_INT
91 
92 #define SCN_VISIT_FLOAT(T) \
93  error visit(T& val, detail::priority_tag<1>) \
94  { \
95  detail::float_scanner<T> s; \
96  auto err = parse(s); \
97  if (!err) { \
98  return err; \
99  } \
100  return s.scan(val, *m_ctx); \
101  }
102  SCN_VISIT_FLOAT(float)
103  SCN_VISIT_FLOAT(double)
104  SCN_VISIT_FLOAT(long double)
105 #undef SCN_VISIT_FLOAT
106 
107  auto visit(std::basic_string<char_type>& val, detail::priority_tag<1>)
108  -> error
109  {
110  detail::string_scanner s;
111  auto err = parse(s);
112  if (!err) {
113  return err;
114  }
115  return s.scan(val, *m_ctx);
116  }
117  auto visit(basic_string_view<char_type>& val, detail::priority_tag<1>)
118  -> error
119  {
120  detail::string_view_scanner s;
121  auto err = parse(s);
122  if (!err) {
123  return err;
124  }
125  return s.scan(val, *m_ctx);
126  }
127  auto visit(typename Context::arg_type::handle val,
128  detail::priority_tag<1>) -> error
129  {
130  return val.scan(*m_ctx, *m_pctx);
131  }
132  auto visit(detail::monostate, detail::priority_tag<0>) -> error
133  {
134  return error(error::invalid_operation, "Cannot scan a monostate");
135  }
136 
137  template <typename Scanner>
138  error parse(Scanner& s)
139  {
140  return m_pctx->parse(s);
141  }
142 
143  Context* m_ctx;
144  ParseCtx* m_pctx;
145  };
146 
147  template <typename Range, typename Base = result<std::ptrdiff_t>>
148  class scan_result : public Base {
149  public:
150  using range_type = Range;
151  using base_type = Base;
152 
153  template <typename R>
154  constexpr scan_result(base_type&& b, R&& r)
155  : base_type(std::move(b)), m_range(std::forward<R>(r))
156  {
157  }
158 
160  {
161  return m_range;
162  }
163  const range_type& range() const&
164  {
165  return m_range;
166  }
168  {
169  return m_range;
170  }
171 
172  auto begin() -> decltype(detail::ranges::begin(range()))
173  {
174  return detail::ranges::begin(m_range);
175  }
176  auto begin() const -> decltype(detail::ranges::begin(range()))
177  {
178  return detail::ranges::begin(m_range);
179  }
180  auto cbegin() const -> decltype(detail::ranges::cbegin(range()))
181  {
182  return detail::ranges::cbegin(m_range);
183  }
184 
185  auto end() -> decltype(detail::ranges::end(range()))
186  {
187  return detail::ranges::end(m_range);
188  }
189  auto end() const -> decltype(detail::ranges::end(range()))
190  {
191  return detail::ranges::end(m_range);
192  }
193  auto cend() const -> decltype(detail::ranges::cend(range()))
194  {
195  return detail::ranges::cend(m_range);
196  }
197 
198  private:
200  };
201  template <typename Context>
204  };
205  template <typename Context>
207 
208  struct wrapped_error {
209  wrapped_error() = default;
211 
213  {
214  return err;
215  }
216 
217  explicit operator bool() const
218  {
219  return err.operator bool();
220  }
221 
223  };
224 
225  template <typename Context, typename ParseCtx>
227  ParseCtx& pctx,
228  basic_args<Context> args)
229  {
230  std::ptrdiff_t args_read = 0;
231 
232  auto reterror = [&args_read,
233  &ctx](error e) -> scan_result_for_t<Context> {
234  return {{args_read, std::move(e)}, ctx.range().get_return()};
235  };
236 
237  auto arg = typename Context::arg_type();
238 
239  {
240  auto ret = skip_range_whitespace(ctx);
241  if (!ret) {
242  return reterror(ret);
243  }
244  }
245 
246  while (pctx) {
247  if (pctx.should_skip_ws()) {
248  // Skip whitespace from format string and from stream
249  // EOF is not an error
250  auto ret = skip_range_whitespace(ctx);
251  if (SCN_UNLIKELY(!ret)) {
252  if (ret == error::end_of_range) {
253  break;
254  }
256  auto rb = ctx.range().reset_to_rollback_point();
257  if (!rb) {
258  return reterror(rb);
259  }
260  return reterror(ret);
261  }
262  // Don't advance pctx, should_skip_ws() does it for us
263  continue;
264  }
265 
266  // Non-brace character, or
267  // Brace followed by another brace, meaning a literal '{'
268  if (pctx.should_read_literal()) {
269  if (SCN_UNLIKELY(!pctx)) {
270  return reterror(error(error::invalid_format_string,
271  "Unexpected end of format string"));
272  }
273  // Check for any non-specifier {foo} characters
274  auto ret = read_char(ctx.range());
276  if (!ret || !pctx.check_literal(ret.value())) {
277  auto rb = ctx.range().reset_to_rollback_point();
278  if (!rb) {
279  // Failed rollback
280  return reterror(rb);
281  }
282  if (!ret) {
283  // Failed read
284  return reterror(ret.error());
285  }
286 
287  // Mismatching characters in scan string and stream
288  return reterror(
290  "Expected character from format string not "
291  "found in the stream"));
292  }
293  // Bump pctx to next char
294  pctx.advance();
295  }
296  else {
297  // Scan argument
298  auto arg_wrapped = [&]() -> expected<typename Context::arg_type>
299  {
300  if (!pctx.has_arg_id()) {
301  return next_arg(args, pctx);
302  }
303  auto id_wrapped = pctx.parse_arg_id();
304  if (!id_wrapped) {
305  return id_wrapped.error();
306  }
307  auto id = id_wrapped.value();
308  SCN_ENSURE(!id.empty());
309  if (ctx.locale().is_digit(id.front())) {
311  s.base = 10;
312  std::ptrdiff_t i{0};
313  auto span = make_span(id.data(), id.size()).as_const();
314  auto ret =
315  s._read_int(i, false, span,
316  typename decltype(span)::value_type{0});
317  if (!ret || ret.value() != span.end()) {
319  "Failed to parse argument id from "
320  "format string");
321  }
322  return get_arg(args, pctx, i);
323  }
324  return get_arg(args, pctx, id);
325  }
326  ();
327  if (!arg_wrapped) {
328  return reterror(arg_wrapped.error());
329  }
330  arg = arg_wrapped.value();
331  SCN_ENSURE(arg);
332  if (!pctx) {
333  return reterror(error(error::invalid_format_string,
334  "Unexpected end of format argument"));
335  }
336  auto ret = visit_arg<Context>(
337  basic_visitor<Context, ParseCtx>(ctx, pctx), arg);
338  if (!ret) {
339  auto rb = ctx.range().reset_to_rollback_point();
340  if (!rb) {
341  return reterror(rb);
342  }
343  return reterror(ret);
344  }
345  // Handle next arg and bump pctx
346  ++args_read;
347  pctx.arg_handled();
348  if (pctx) {
349  pctx.advance();
350  }
351  }
352  }
353  if (pctx) {
354  // Format string not exhausted
355  return reterror(error(error::invalid_format_string,
356  "Format string not exhausted"));
357  }
358  ctx.range().set_rollback_point();
359  return {args_read, ctx.range().get_return()};
360  }
361 
363 } // namespace scn
364 
365 #endif // SCN_DETAIL_VISITOR_H
typename Context::char_type char_type
Definition: visitor.h:30
auto begin() const -> decltype(detail::ranges::begin(range()))
Definition: visitor.h:176
Scanned value was invalid for given type.
Definition: result.h:44
SCN_CONSTEXPR14 iterator end() noexcept
Definition: span.h:258
#define SCN_END_NAMESPACE
Definition: config.h:401
expected< detail::ranges::range_value_t< WrappedRange > > read_char(WrappedRange &r)
Reads a single character from the range.
Definition: reader.h:53
void size(T &&)=delete
#define SCN_UNLIKELY(x)
Definition: config.h:362
error skip_range_whitespace(Context &ctx) noexcept
Reads from the range in ctx as if by repeatedly calling read_char(), until a non-space character is f...
Definition: reader.h:1485
typename remove_cvref< T >::type remove_cvref_t
Definition: util.h:54
auto operator()(T &&val) -> error
Definition: visitor.h:38
auto cend() const -> decltype(detail::ranges::cend(range()))
Definition: visitor.h:193
scan_result_for_t< Context > visit(Context &ctx, ParseCtx &pctx, basic_args< Context > args)
Definition: visitor.h:226
::scn::error error() const
Definition: visitor.h:212
wrapped_error()=default
auto begin() -> decltype(detail::ranges::begin(range()))
Definition: visitor.h:172
constexpr scan_result(base_type &&b, R &&r)
Definition: visitor.h:154
wrapped_error(::scn::error e)
Definition: visitor.h:210
range_type & range()&
Definition: visitor.h:159
typename scan_result_for< Context >::type scan_result_for_t
Definition: visitor.h:206
Format string was invalid.
Definition: result.h:41
Range range_type
Definition: visitor.h:150
expected-like type.
Definition: result.h:180
#define SCN_CLANG_POP_IGNORE_UNDEFINED_TEMPLATE
Definition: config.h:146
auto end() -> decltype(detail::ranges::end(range()))
Definition: visitor.h:185
error scan(typename Context::char_type &val, Context &ctx)
Definition: reader.h:558
#define SCN_VISIT_INT(T)
Definition: visitor.h:72
Stream does not support the performed operation.
Definition: result.h:46
Error class.
Definition: result.h:32
#define SCN_BEGIN_NAMESPACE
Definition: config.h:400
#define SCN_ENSURE(cond)
Definition: config.h:397
range_type && range()&&
Definition: visitor.h:167
auto get_arg(const basic_args< Context > &args, std::ptrdiff_t id) -> expected< basic_arg< Context >>
Definition: context.h:88
auto cbegin() const -> decltype(detail::ranges::cbegin(range()))
Definition: visitor.h:180
basic_visitor(Context &ctx, ParseCtx &pctx)
Definition: visitor.h:32
Context context_type
Definition: visitor.h:29
#define SCN_VISIT_FLOAT(T)
Definition: visitor.h:92
#define SCN_CLANG_PUSH_IGNORE_UNDEFINED_TEMPLATE
Definition: config.h:145
void end(T &&)=delete
::scn::error err
Definition: visitor.h:222
constexpr span< T > make_span(T *ptr, std::size_t count) noexcept
Definition: span.h:383
void begin(T &&)=delete
const range_type & range() const &
Definition: visitor.h:163
auto end() const -> decltype(detail::ranges::end(range()))
Definition: visitor.h:189
A view over a contiguous range.
Definition: span.h:29
auto next_arg(const basic_args< Context > &args, ParseCtx &pctx) -> expected< basic_arg< Context >>
Definition: context.h:117