scnlib  0.2.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
scan.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_SCAN_H
19 #define SCN_DETAIL_SCAN_H
20 
21 #include "vscan.h"
22 
23 #include <vector>
24 
25 namespace scn {
27 
28  namespace detail {
29  template <typename Range, typename E = result<ptrdiff_t>>
31  using type = scan_result<
33  E>;
34  };
35  template <typename Range, typename E = result<ptrdiff_t>>
38  } // namespace detail
39 
64 
66  // scan
67 
72  template <typename Range, typename Format, typename... Args>
73  auto scan(Range&& r, const Format& f, Args&... a)
75  {
76  static_assert(sizeof...(Args) > 0,
77  "Have to scan at least a single argument");
78 
79  using range_type = detail::range_wrapper_for_t<Range>;
80  using context_type = basic_context<range_type>;
81  using parse_context_type =
83 
84  auto args = make_args<context_type, parse_context_type>(a...);
85  auto ctx = context_type(detail::wrap(std::forward<Range>(r)));
86  auto pctx = parse_context_type(f, ctx);
87  return vscan(ctx, pctx, {args});
88  }
89 
90  // scan localized
91 
100  template <typename Locale,
101  typename Range,
102  typename Format,
103  typename... Args>
104  auto scan_localized(const Locale& loc,
105  Range&& r,
106  const Format& f,
108  {
109  static_assert(sizeof...(Args) > 0,
110  "Have to scan at least a single argument");
111 
112  using range_type = detail::range_wrapper_for_t<Range>;
114  using context_type = basic_context<range_type, locale_type>;
115  using parse_context_type =
117 
118  auto args = make_args<context_type, parse_context_type>(a...);
119  auto ctx = context_type(detail::wrap(std::forward<Range>(r)),
120  {std::addressof(loc)});
121  auto pctx = parse_context_type(f, ctx);
122  return vscan(ctx, pctx, {args});
123  }
124 
125  // default format
126 
135  template <typename Range, typename... Args>
136  auto scan(Range&& r, detail::default_t, Args&... a)
138  {
139  static_assert(sizeof...(Args) > 0,
140  "Have to scan at least a single argument");
141 
142  using range_type = detail::range_wrapper_for_t<Range>;
143  using context_type = basic_context<range_type>;
144  using parse_context_type =
146 
147  auto args = make_args<context_type, parse_context_type>(a...);
148  auto ctx = context_type(detail::wrap(std::forward<Range>(r)));
149  auto pctx = parse_context_type(static_cast<int>(sizeof...(Args)), ctx);
150  return vscan(ctx, pctx, {args});
151  }
152 
153  // value
154 
168  template <typename T, typename Range>
169  auto scan_value(Range&& r)
171  {
172  using range_type = detail::range_wrapper_for_t<Range>;
173  using context_type = basic_context<range_type>;
174  using parse_context_type =
176 
177  T value;
178  auto args = make_args<context_type, parse_context_type>(value);
179  auto ctx = context_type(detail::wrap(std::forward<Range>(r)));
180 
181 #if 0
182  using char_type = typename context_type::char_type;
183  auto e = skip_range_whitespace(ctx);
184  if (!e) {
185  ctx.range().reset_to_rollback_point();
186  return {e, ctx.range().get_return()};
187  }
188 
190  e = s.scan(value, ctx);
191  if (!e) {
192  ctx.range().reset_to_rollback_point();
193  return {e, ctx.range().get_return()};
194  }
195  return {std::move(value), ctx.range().get_return()};
196 #else
197  auto pctx = parse_context_type(1, ctx);
198  auto ret = vscan(ctx, pctx, {args});
199  if (!ret) {
200  return {ret.error(), ret.range()};
201  }
202  return {value, ret.range()};
203 #endif
204  }
205 
206  // scanf
207 
212  template <typename Range, typename Format, typename... Args>
213  auto scanf(Range&& r, const Format& f, Args&... a)
215  {
216  static_assert(sizeof...(Args) > 0,
217  "Have to scan at least a single argument");
218 
220  using parse_context_type =
222 
223  auto args = make_args<context_type, parse_context_type>(a...);
224  auto ctx = context_type(detail::wrap(std::forward<Range>(r)));
225  auto pctx = parse_context_type(f, ctx);
226  return vscan(ctx, pctx, {args});
227  }
228 
229  // input
230 
240  template <typename Format,
241  typename... Args,
242  typename CharT = detail::ranges::range_value_t<Format>>
243  auto input(const Format& f, Args&... a)
245  {
246  static_assert(sizeof...(Args) > 0,
247  "Have to scan at least a single argument");
248 
249  using context_type = basic_context<
251  using parse_context_type =
253 
254  auto args = make_args<context_type, parse_context_type>(a...);
255  auto ctx = context_type(detail::wrap(stdin_range<CharT>()));
256  auto pctx = parse_context_type(f, ctx);
257  return vscan(ctx, pctx, {args});
258  }
259 
260  // prompt
261 
273  template <typename Format,
274  typename... Args,
275  typename CharT = detail::ranges::range_value_t<Format>>
276  auto prompt(const CharT* p, const Format& f, Args&... a)
278  {
279  static_assert(sizeof...(Args) > 0,
280  "Have to scan at least a single argument");
281  SCN_EXPECT(p != nullptr);
282 
283  std::fputs(p, stdout);
284 
285  using context_type = basic_context<
287  using parse_context_type =
289 
290  auto args = make_args<context_type, parse_context_type>(a...);
291  auto ctx = context_type(detail::wrap(stdin_range<CharT>()));
292  auto pctx = parse_context_type(f, ctx);
293  return vscan(ctx, pctx, {args});
294  }
295 
305  template <typename T, typename CharT>
307  T& val,
308  int base = 10)
309  {
310  SCN_EXPECT(!str.empty());
311  auto s = scanner<CharT, T>{base};
312  bool minus_sign = false;
313  if (str[0] == detail::ascii_widen<CharT>('-')) {
314  minus_sign = true;
315  }
316  auto ret = s._read_int(val, minus_sign,
317  make_span(str.data(), str.size()).as_const(),
318  detail::ascii_widen<CharT>('\0'));
319  if (!ret) {
320  return ret.error();
321  }
322  return {ret.value()};
323  }
324 
325  // scanning api
327 
338  // getline
339 
340  namespace detail {
341  template <typename WrappedRange, typename String, typename CharT>
342  auto getline_impl(WrappedRange& r, String& str, CharT until)
344  {
345  auto until_pred = [until](CharT ch) { return ch == until; };
346  auto s = read_until_space_zero_copy(r, until_pred, true);
347  if (!s) {
348  return {std::move(s.error()), r.get_return()};
349  }
350  if (s.value().size() != 0) {
351  auto size = s.value().size();
352  if (until_pred(s.value()[size - 1])) {
353  --size;
354  }
355  str.clear();
356  str.resize(size);
357  std::copy(s.value().begin(), s.value().begin() + size,
358  str.begin());
359  return {{}, r.get_return()};
360  }
361 
362  String tmp;
363  auto out = std::back_inserter(tmp);
364  auto e = read_until_space(r, out, until_pred, true);
365  if (!e) {
366  return {std::move(e), r.get_return()};
367  }
368  if (until_pred(tmp.back())) {
369  tmp.pop_back();
370  }
371  str = std::move(tmp);
372  return {{}, r.get_return()};
373  }
374  template <typename WrappedRange, typename CharT>
375  auto getline_impl(WrappedRange& r,
377  CharT until)
379  {
380  auto until_pred = [until](CharT ch) { return ch == until; };
381  auto s = read_until_space_zero_copy(r, until_pred, true);
382  if (!s) {
383  return {std::move(s.error()), r.get_return()};
384  }
385  if (s.value().size() != 0) {
386  auto size = s.value().size();
387  if (until_pred(s.value()[size - 1])) {
388  --size;
389  }
390  str = basic_string_view<CharT>{s.value().data(), size};
391  return {{}, r.get_return()};
392  }
393  // TODO: Compile-time error?
394  return {
395  error(
397  "Cannot getline a string_view from a non-contiguous range"),
398  r.get_return()};
399  }
400  } // namespace detail
401 
417  template <typename Range, typename String, typename CharT>
418  auto getline(Range&& r, String& str, CharT until)
419  -> decltype(detail::getline_impl(
420  std::declval<decltype(detail::wrap(std::forward<Range>(r)))&>(),
421  str,
422  until))
423  {
424  auto wrapped = detail::wrap(std::forward<Range>(r));
425  return getline_impl(wrapped, str, until);
426  }
427 
437  template <typename Range,
438  typename String,
439  typename CharT =
440  typename detail::extract_char_type<detail::ranges::iterator_t<
441  detail::range_wrapper_for_t<Range>>>::type>
442  auto getline(Range&& r, String& str) -> decltype(
443  getline(std::forward<Range>(r), str, detail::ascii_widen<CharT>('\n')))
444  {
445  return getline(std::forward<Range>(r), str,
446  detail::ascii_widen<CharT>('\n'));
447  }
448 
449  // ignore
450 
451  namespace detail {
452  template <typename CharT>
454  using value_type = CharT;
455  using pointer = value_type*;
457  using difference_type = std::ptrdiff_t;
458  using iterator_category = std::output_iterator_tag;
459 
460  constexpr ignore_iterator() = default;
461 
462  constexpr const ignore_iterator& operator=(CharT) const noexcept
463  {
464  return *this;
465  }
466 
467  constexpr const ignore_iterator& operator*() const noexcept
468  {
469  return *this;
470  }
471  constexpr const ignore_iterator& operator++() const noexcept
472  {
473  return *this;
474  }
475  };
476 
477  template <typename CharT>
479  using value_type = CharT;
480  using pointer = value_type*;
482  using difference_type = std::ptrdiff_t;
483  using iterator_category = std::output_iterator_tag;
484 
485  ignore_iterator_n() = default;
487 
488  constexpr const ignore_iterator_n& operator=(CharT) const noexcept
489  {
490  return *this;
491  }
492 
493  constexpr const ignore_iterator_n& operator*() const noexcept
494  {
495  return *this;
496  }
497 
499  {
500  ++i;
501  return *this;
502  }
503 
504  constexpr bool operator==(const ignore_iterator_n& o) const noexcept
505  {
506  return i == o.i;
507  }
508  constexpr bool operator!=(const ignore_iterator_n& o) const noexcept
509  {
510  return !(*this == o);
511  }
512 
514  };
515 
516  template <typename WrappedRange,
517  typename CharT = typename detail::extract_char_type<
519  typename WrappedRange::iterator>>::type>
520  auto ignore_until_impl(WrappedRange& r, CharT until)
522  {
523  auto until_pred = [until](CharT ch) { return ch == until; };
525  auto e = read_until_space(r, it, until_pred, false);
526  if (!e) {
527  return {std::move(e), r.get_return()};
528  }
529  return {{}, r.get_return()};
530  }
531 
532  template <typename WrappedRange,
533  typename CharT = typename detail::extract_char_type<
535  typename WrappedRange::iterator>>::type>
536  auto ignore_until_n_impl(WrappedRange& r,
538  CharT until)
540  {
541  auto until_pred = [until](CharT ch) { return ch == until; };
543  auto e = read_until_space_ranged(r, begin, end, until_pred, false);
544  if (!e) {
545  return {std::move(e), r.get_return()};
546  }
547  return {{}, r.get_return()};
548  }
549  } // namespace detail
550 
557  template <typename Range, typename CharT>
558  auto ignore_until(Range&& r, CharT until)
559  -> decltype(detail::ignore_until_impl(
560  std::declval<decltype(detail::wrap(std::forward<Range>(r)))&>(),
561  until))
562  {
563  auto wrapped = detail::wrap(std::forward<Range>(r));
564  auto ret = detail::ignore_until_impl(wrapped, until);
565  if (!ret) {
566  auto e = wrapped.reset_to_rollback_point();
567  if (!e) {
568  return {std::move(e), wrapped.get_return()};
569  }
570  }
571  return ret;
572  }
573 
581  template <typename Range, typename CharT>
582  auto ignore_until_n(Range&& r,
584  CharT until)
585  -> decltype(detail::ignore_until_n_impl(
586  std::declval<decltype(detail::wrap(std::forward<Range>(r)))&>(),
587  n,
588  until))
589  {
590  auto wrapped = detail::wrap(std::forward<Range>(r));
591  auto ret = detail::ignore_until_n_impl(wrapped, n, until);
592  if (!ret) {
593  auto e = wrapped.reset_to_rollback_point();
594  if (!e) {
595  return {std::move(e), wrapped.get_return()};
596  }
597  }
598  return ret;
599  }
600 
610  template <typename Range, typename Container, typename CharT>
611  auto scan_list(Range&& r, Container& c, CharT separator)
613  {
614  using value_type = typename Container::value_type;
615  using range_type = detail::range_wrapper_for_t<Range>;
616  using context_type = basic_context<range_type>;
617  using parse_context_type =
619 
620  value_type value;
621  auto args = make_args<context_type, parse_context_type>(value);
622  auto ctx = context_type(detail::wrap(std::forward<Range>(r)));
623 
624  while (true) {
625  auto pctx = parse_context_type(1, ctx);
626  auto ret = vscan(ctx, pctx, {args});
627  if (!ret) {
628  if (ret.error() == error::end_of_range) {
629  break;
630  }
631  return {ret.error(), ctx.range().get_return()};
632  }
633  c.push_back(std::move(value));
634 
635  if (separator != 0) {
636  auto sep_ret = read_char(ctx.range());
637  if (!sep_ret) {
638  if (sep_ret.error() == scn::error::end_of_range) {
639  break;
640  }
641  return {sep_ret.error(), ctx.range().get_return()};
642  }
643  if (sep_ret.value() == separator) {
644  continue;
645  }
646  else {
648  "Invalid separator character"),
649  ctx.range().get_return()};
650  }
651  }
652  }
653  return {{}, ctx.range().get_return()};
654  }
655 
662  template <typename T>
663  struct discard_type {
664  discard_type() = default;
665  };
666 
683  template <typename T>
685  {
686  return temp(discard_type<T>{})();
687  }
688 
689  template <typename CharT, typename T>
690  struct scanner<CharT, discard_type<T>> : public scanner<CharT, T> {
691  template <typename Context>
692  error scan(discard_type<T>&, Context& ctx)
693  {
694  T tmp;
695  return scanner<CharT, T>::scan(tmp, ctx);
696  }
697  };
698 
700 } // namespace scn
701 
702 #endif // SCN_DETAIL_SCAN_H
error read_until_space(WrappedRange &r, OutputIterator &out, Predicate is_space, bool keep_final_space)
Reads characters from r until a space is found (as determined by is_space) and writes them into out...
Definition: reader.h:321
constexpr const ignore_iterator & operator*() const noexcept
Definition: scan.h:467
auto prompt(const CharT *p, const Format &f, Args &...a) -> detail::scan_result_for_range_t< decltype(stdin_range< CharT >())>
Equivalent to input, except writes what's in p to stdout.
Definition: scan.h:276
constexpr const ignore_iterator_n & operator=(CharT) const noexcept
Definition: scan.h:488
auto scan(Range &&r, detail::default_t, Args &...a) -> detail::scan_result_for_range_t< Range >
Equivalent to scan, but with a format string with the appropriate amount of space-separated "{}"s for...
Definition: scan.h:136
Scanned value was invalid for given type.
Definition: result.h:44
std::ptrdiff_t difference_type
Definition: scan.h:482
auto scanf(Range &&r, const Format &f, Args &...a) -> detail::scan_result_for_range_t< Range >
Otherwise equivalent to scan, except it uses scanf-like format string syntax, instead of the Python-l...
Definition: scan.h:213
auto getline_impl(WrappedRange &r, basic_string_view< CharT > &str, CharT until) -> detail::scan_result_for_range_t< WrappedRange, wrapped_error >
Definition: scan.h:375
constexpr const_pointer data() const noexcept
Definition: string_view.h:155
#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
value_type & reference
Definition: scan.h:456
void size(T &&)=delete
auto scan_value(Range &&r) -> detail::scan_result_for_range_t< Range, expected< T >>
Scans a single value with the default options, returning it instead of using an output parameter...
Definition: scan.h:169
std::output_iterator_tag iterator_category
Definition: scan.h:483
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
value_type * pointer
Definition: scan.h:455
SCN_CONSTEXPR14 ignore_iterator_n & operator++() noexcept
Definition: scan.h:498
value_type & reference
Definition: scan.h:481
SCN_NODISCARD constexpr bool empty() const noexcept
Definition: string_view.h:172
auto getline_impl(WrappedRange &r, String &str, CharT until) -> detail::scan_result_for_range_t< WrappedRange, wrapped_error >
Definition: scan.h:342
expected< span< const typename detail::extract_char_type< typename WrappedRange::iterator >::type > > read_until_space_zero_copy(WrappedRange &r, Predicate is_space, bool keep_final_space)
Reads characters from r until a space is found (as determined by is_space), and returns a span into t...
Definition: reader.h:262
auto ignore_until(Range &&r, CharT until) -> decltype(detail::ignore_until_impl(std::declval< decltype(detail::wrap(std::forward< Range >(r)))& >(), until))
Advances the beginning of r until until is found.
Definition: scan.h:558
temporary< T > temp(T &&val)
Factory function for temporary.
Definition: args.h:61
typename std::enable_if< range< R >::value, decltype(::scn::detail::ranges::begin(std::declval< R & >()))>::type iterator_t
Definition: ranges.h:491
expected-like type.
Definition: result.h:180
discard_type< T > & discard()
Scans an instance of T, but doesn't store it anywhere.
Definition: scan.h:684
difference_type i
Definition: scan.h:513
auto ignore_until_n(Range &&r, detail::ranges::range_difference_t< Range > n, CharT until) -> decltype(detail::ignore_until_n_impl(std::declval< decltype(detail::wrap(std::forward< Range >(r)))& >(), n, until))
Advances the beginning of r until until is found, or the beginning has been advanced n times...
Definition: scan.h:582
typename range_wrapper_for< Range >::type range_wrapper_for_t
Definition: range.h:263
expected< const CharT * > parse_integer(basic_string_view< CharT > str, T &val, int base=10)
Parses an integer into val in base base from str.
Definition: scan.h:306
typename scan_result_for_range< Range, E >::type scan_result_for_range_t
Definition: scan.h:37
constexpr bool operator==(const ignore_iterator_n &o) const noexcept
Definition: scan.h:504
constexpr const ignore_iterator_n & operator*() const noexcept
Definition: scan.h:493
Stream does not support the performed operation.
Definition: result.h:46
typename std::enable_if< range< R >::value, iter_difference_t< iterator_t< R >>>::type range_difference_t
Definition: ranges.h:500
constexpr bool operator!=(const ignore_iterator_n &o) const noexcept
Definition: scan.h:508
Error class.
Definition: result.h:32
#define SCN_BEGIN_NAMESPACE
Definition: config.h:400
auto scan(Range &&r, const Format &f, Args &...a) -> detail::scan_result_for_range_t< Range >
The most fundamental part of the scanning API.
Definition: scan.h:73
auto input(const Format &f, Args &...a) -> detail::scan_result_for_range_t< decltype(stdin_range< CharT >())>
Otherwise equivalent to scan, expect reads from stdin.
Definition: scan.h:243
ignore_iterator_n(difference_type n)
Definition: scan.h:486
constexpr const ignore_iterator & operator=(CharT) const noexcept
Definition: scan.h:462
constexpr ignore_iterator()=default
std::ptrdiff_t difference_type
Definition: scan.h:457
auto scan_list(Range &&r, Container &c, CharT separator) -> detail::scan_result_for_range_t< Range, wrapped_error >
Reads values repeatedly from r and writes them into c.
Definition: scan.h:611
constexpr const ignore_iterator & operator++() const noexcept
Definition: scan.h:471
error scan(discard_type< T > &, Context &ctx)
Definition: scan.h:692
constexpr size_type size() const noexcept
Definition: string_view.h:160
void end(T &&)=delete
error read_until_space_ranged(WrappedRange &r, OutputIterator &out, Sentinel end, Predicate is_space, bool keep_final_space)
Reads characters from r until a space is found (as determined by is_space), or out reaches end...
Definition: reader.h:414
auto scan_localized(const Locale &loc, Range &&r, const Format &f, Args &...a) -> detail::scan_result_for_range_t< Range >
Read from the range in r using the locale in loc.
Definition: scan.h:104
constexpr span< T > make_span(T *ptr, std::size_t count) noexcept
Definition: span.h:383
scan_result_for_t< Context > vscan(Context &ctx, ParseCtx &pctx, basic_args< Context > args)
Definition: vscan.h:48
void begin(T &&)=delete
auto ignore_until_n_impl(WrappedRange &r, ranges::range_difference_t< WrappedRange > n, CharT until) -> scan_result< WrappedRange, wrapped_error >
Definition: scan.h:536
auto ignore_until_impl(WrappedRange &r, CharT until) -> scan_result< WrappedRange, wrapped_error >
Definition: scan.h:520
A view over a (sub)string.
Definition: string_view.h:60
discard_type()=default
auto getline(Range &&r, String &str, CharT until) -> decltype(detail::getline_impl(std::declval< decltype(detail::wrap(std::forward< Range >(r)))& >(), str, until))
Read the range in r into str until until is found.
Definition: scan.h:418
std::output_iterator_tag iterator_category
Definition: scan.h:458
#define SCN_EXPECT(cond)
Definition: config.h:396
#define SCN_CONSTEXPR14
Definition: config.h:240