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 <vector>
22 
23 #include "vscan.h"
24 
25 namespace scn {
27 
28  namespace detail {
29  template <typename Range, typename E = wrapped_error>
31  using type = scan_result<
33  E>;
34  };
35  template <typename Range, typename E = wrapped_error>
38  } // namespace detail
39 
63 
65  // scan
66 
71  template <typename Range, typename Format, typename... Args>
72  auto scan(Range&& r, const Format& f, Args&... a)
74  {
75  static_assert(sizeof...(Args) > 0,
76  "Have to scan at least a single argument");
77 
78  using range_type = detail::range_wrapper_for_t<Range>;
79  using context_type = basic_context<range_type>;
80  using parse_context_type =
82 
83  auto args = make_args<context_type, parse_context_type>(a...);
84  auto ctx = context_type(detail::wrap(std::forward<Range>(r)));
85  auto pctx = parse_context_type(f, ctx);
86  return vscan(ctx, pctx, {args});
87  }
88 
89  // scan localized
90 
99  template <typename Locale,
100  typename Range,
101  typename Format,
102  typename... Args>
103  auto scan_localized(const Locale& loc,
104  Range&& r,
105  const Format& f,
107  {
108  static_assert(sizeof...(Args) > 0,
109  "Have to scan at least a single argument");
110 
111  using range_type = detail::range_wrapper_for_t<Range>;
113  using context_type = basic_context<range_type, locale_type>;
114  using parse_context_type =
116 
117  auto args = make_args<context_type, parse_context_type>(a...);
118  auto ctx = context_type(detail::wrap(std::forward<Range>(r)),
119  {std::addressof(loc)});
120  auto pctx = parse_context_type(f, ctx);
121  return vscan(ctx, pctx, {args});
122  }
123 
124  // default format
125 
134  template <typename Range, typename... Args>
135  auto scan(Range&& r, detail::default_t, Args&... a)
137  {
138  static_assert(sizeof...(Args) > 0,
139  "Have to scan at least a single argument");
140 
141  using range_type = detail::range_wrapper_for_t<Range>;
142  using context_type = basic_context<range_type>;
143  using parse_context_type =
145 
146  auto args = make_args<context_type, parse_context_type>(a...);
147  auto ctx = context_type(detail::wrap(std::forward<Range>(r)));
148  auto pctx = parse_context_type(static_cast<int>(sizeof...(Args)), ctx);
149  return vscan(ctx, pctx, {args});
150  }
151 
152  // value
153 
167  template <typename T, typename Range>
168  auto scan_value(Range&& r)
170  {
171  using range_type = detail::range_wrapper_for_t<Range>;
172  using context_type = basic_context<range_type>;
173  using parse_context_type =
175 
176  T value;
177  auto args = make_args<context_type, parse_context_type>(value);
178  auto ctx = context_type(detail::wrap(std::forward<Range>(r)));
179 
180 #if 0
181  using char_type = typename context_type::char_type;
182  auto e = skip_range_whitespace(ctx);
183  if (!e) {
184  ctx.range().reset_to_rollback_point();
185  return {e, ctx.range().get_return()};
186  }
187 
189  e = s.scan(value, ctx);
190  if (!e) {
191  ctx.range().reset_to_rollback_point();
192  return {e, ctx.range().get_return()};
193  }
194  return {std::move(value), ctx.range().get_return()};
195 #else
196  auto pctx = parse_context_type(1, ctx);
197  auto ret = vscan(ctx, pctx, {args});
198  if (!ret) {
199  return {ret.error(), ret.range()};
200  }
201  return {value, ret.range()};
202 #endif
203  }
204 
205  // scanf
206 
211  template <typename Range, typename Format, typename... Args>
212  auto scanf(Range&& r, const Format& f, Args&... a)
214  {
215  static_assert(sizeof...(Args) > 0,
216  "Have to scan at least a single argument");
217 
219  using parse_context_type =
221 
222  auto args = make_args<context_type, parse_context_type>(a...);
223  auto ctx = context_type(detail::wrap(std::forward<Range>(r)));
224  auto pctx = parse_context_type(f, ctx);
225  return vscan(ctx, pctx, {args});
226  }
227 
228  // input
229 
239  template <typename Format,
240  typename... Args,
241  typename CharT = detail::ranges::range_value_t<Format>>
242  auto input(const Format& f, Args&... a)
244  {
245  static_assert(sizeof...(Args) > 0,
246  "Have to scan at least a single argument");
247 
248  using context_type = basic_context<
250  using parse_context_type =
252 
253  auto args = make_args<context_type, parse_context_type>(a...);
254  auto ctx = context_type(detail::wrap(stdin_range<CharT>()));
255  auto pctx = parse_context_type(f, ctx);
256  return vscan(ctx, pctx, {args});
257  }
258 
259  // prompt
260 
272  template <typename Format,
273  typename... Args,
274  typename CharT = detail::ranges::range_value_t<Format>>
275  auto prompt(const CharT* p, const Format& f, Args&... a)
277  {
278  static_assert(sizeof...(Args) > 0,
279  "Have to scan at least a single argument");
280  SCN_EXPECT(p != nullptr);
281 
282  std::fputs(p, stdout);
283 
284  using context_type = basic_context<
286  using parse_context_type =
288 
289  auto args = make_args<context_type, parse_context_type>(a...);
290  auto ctx = context_type(detail::wrap(stdin_range<CharT>()));
291  auto pctx = parse_context_type(f, ctx);
292  return vscan(ctx, pctx, {args});
293  }
294 
304  template <typename T, typename CharT>
306  T& val,
307  int base = 10)
308  {
309  SCN_EXPECT(!str.empty());
310  auto s = scanner<CharT, T>{base};
311  bool minus_sign = false;
312  if (str[0] == detail::ascii_widen<CharT>('-')) {
313  minus_sign = true;
314  }
315  auto ret = s._read_int(val, minus_sign,
316  make_span(str.data(), str.size()).as_const(),
317  detail::ascii_widen<CharT>('\0'));
318  if (!ret) {
319  return ret.error();
320  }
321  return {ret.value()};
322  }
323 
324  // scanning api
326 
337  // getline
338 
339  namespace detail {
340  template <typename WrappedRange, typename String, typename CharT>
341  auto getline_impl(WrappedRange& r, String& str, CharT until)
343  {
344  auto until_pred = [until](CharT ch) { return ch == until; };
345  auto s = read_until_space_zero_copy(r, until_pred, true);
346  if (!s) {
347  return {std::move(s.error()), r.get_return()};
348  }
349  if (s.value().size() != 0) {
350  auto size = s.value().size();
351  if (until_pred(s.value()[size - 1])) {
352  --size;
353  }
354  str.clear();
355  str.resize(size);
356  std::copy(s.value().begin(), s.value().begin() + size,
357  str.begin());
358  return {{}, r.get_return()};
359  }
360 
361  String tmp;
362  auto out = std::back_inserter(tmp);
363  auto e = read_until_space(r, out, until_pred, true);
364  if (!e) {
365  return {std::move(e), r.get_return()};
366  }
367  if (until_pred(tmp.back())) {
368  tmp.pop_back();
369  }
370  str = std::move(tmp);
371  return {{}, r.get_return()};
372  }
373  template <typename WrappedRange, typename CharT>
374  auto getline_impl(WrappedRange& r,
376  CharT until)
378  {
379  auto until_pred = [until](CharT ch) { return ch == until; };
380  auto s = read_until_space_zero_copy(r, until_pred, true);
381  if (!s) {
382  return {std::move(s.error()), r.get_return()};
383  }
384  if (s.value().size() != 0) {
385  auto size = s.value().size();
386  if (until_pred(s.value()[size - 1])) {
387  --size;
388  }
389  str = basic_string_view<CharT>{s.value().data(), size};
390  return {{}, r.get_return()};
391  }
392  // TODO: Compile-time error?
393  return {
394  error(
396  "Cannot getline a string_view from a non-contiguous range"),
397  r.get_return()};
398  }
399  } // namespace detail
400 
416  template <typename Range, typename String, typename CharT>
417  auto getline(Range&& r, String& str, CharT until)
418  -> decltype(detail::getline_impl(
419  std::declval<decltype(detail::wrap(std::forward<Range>(r)))&>(),
420  str,
421  until))
422  {
423  auto wrapped = detail::wrap(std::forward<Range>(r));
424  return getline_impl(wrapped, str, until);
425  }
426 
436  template <typename Range,
437  typename String,
438  typename CharT =
439  typename detail::extract_char_type<detail::ranges::iterator_t<
440  detail::range_wrapper_for_t<Range>>>::type>
441  auto getline(Range&& r, String& str) -> decltype(
442  getline(std::forward<Range>(r), str, detail::ascii_widen<CharT>('\n')))
443  {
444  return getline(std::forward<Range>(r), str,
445  detail::ascii_widen<CharT>('\n'));
446  }
447 
448  // ignore
449 
450  namespace detail {
451  template <typename CharT>
453  using value_type = CharT;
454  using pointer = value_type*;
456  using difference_type = std::ptrdiff_t;
457  using iterator_category = std::output_iterator_tag;
458 
459  constexpr ignore_iterator() = default;
460 
461  constexpr const ignore_iterator& operator=(CharT) const noexcept
462  {
463  return *this;
464  }
465 
466  constexpr const ignore_iterator& operator*() const noexcept
467  {
468  return *this;
469  }
470  constexpr const ignore_iterator& operator++() const noexcept
471  {
472  return *this;
473  }
474  };
475 
476  template <typename CharT>
478  using value_type = CharT;
479  using pointer = value_type*;
481  using difference_type = std::ptrdiff_t;
482  using iterator_category = std::output_iterator_tag;
483 
484  ignore_iterator_n() = default;
486 
487  constexpr const ignore_iterator_n& operator=(CharT) const noexcept
488  {
489  return *this;
490  }
491 
492  constexpr const ignore_iterator_n& operator*() const noexcept
493  {
494  return *this;
495  }
496 
498  {
499  ++i;
500  return *this;
501  }
502 
503  constexpr bool operator==(const ignore_iterator_n& o) const noexcept
504  {
505  return i == o.i;
506  }
507  constexpr bool operator!=(const ignore_iterator_n& o) const noexcept
508  {
509  return !(*this == o);
510  }
511 
513  };
514 
515  template <typename WrappedRange,
516  typename CharT = typename detail::extract_char_type<
518  typename WrappedRange::iterator>>::type>
519  auto ignore_until_impl(WrappedRange& r, CharT until)
521  {
522  auto until_pred = [until](CharT ch) { return ch == until; };
524  auto e = read_until_space(r, it, until_pred, false);
525  if (!e) {
526  return {std::move(e), r.get_return()};
527  }
528  return {{}, r.get_return()};
529  }
530 
531  template <typename WrappedRange,
532  typename CharT = typename detail::extract_char_type<
534  typename WrappedRange::iterator>>::type>
535  auto ignore_until_n_impl(WrappedRange& r,
537  CharT until)
539  {
540  auto until_pred = [until](CharT ch) { return ch == until; };
542  auto e = read_until_space_ranged(r, begin, end, until_pred, false);
543  if (!e) {
544  return {std::move(e), r.get_return()};
545  }
546  return {{}, r.get_return()};
547  }
548  } // namespace detail
549 
556  template <typename Range, typename CharT>
557  auto ignore_until(Range&& r, CharT until)
558  -> decltype(detail::ignore_until_impl(
559  std::declval<decltype(detail::wrap(std::forward<Range>(r)))&>(),
560  until))
561  {
562  auto wrapped = detail::wrap(std::forward<Range>(r));
563  auto ret = detail::ignore_until_impl(wrapped, until);
564  if (!ret) {
565  auto e = wrapped.reset_to_rollback_point();
566  if (!e) {
567  return {std::move(e), wrapped.get_return()};
568  }
569  }
570  return ret;
571  }
572 
580  template <typename Range, typename CharT>
581  auto ignore_until_n(Range&& r,
583  CharT until)
584  -> decltype(detail::ignore_until_n_impl(
585  std::declval<decltype(detail::wrap(std::forward<Range>(r)))&>(),
586  n,
587  until))
588  {
589  auto wrapped = detail::wrap(std::forward<Range>(r));
590  auto ret = detail::ignore_until_n_impl(wrapped, n, until);
591  if (!ret) {
592  auto e = wrapped.reset_to_rollback_point();
593  if (!e) {
594  return {std::move(e), wrapped.get_return()};
595  }
596  }
597  return ret;
598  }
599 
609  template <typename Range, typename Container, typename CharT>
610  auto scan_list(Range&& r, Container& c, CharT separator)
612  {
613  using value_type = typename Container::value_type;
614  using range_type = detail::range_wrapper_for_t<Range>;
615  using context_type = basic_context<range_type>;
616  using parse_context_type =
618 
619  value_type value;
620  auto args = make_args<context_type, parse_context_type>(value);
621  auto ctx = context_type(detail::wrap(std::forward<Range>(r)));
622 
623  while (true) {
624  auto pctx = parse_context_type(1, ctx);
625  auto ret = vscan(ctx, pctx, {args});
626  if (!ret) {
627  if (ret.error() == error::end_of_range) {
628  break;
629  }
630  return {ret.error(), ctx.range().get_return()};
631  }
632  c.push_back(std::move(value));
633 
634  if (separator != 0) {
635  auto sep_ret = read_char(ctx.range());
636  if (!sep_ret) {
637  if (sep_ret.error() == scn::error::end_of_range) {
638  break;
639  }
640  return {sep_ret.error(), ctx.range().get_return()};
641  }
642  if (sep_ret.value() == separator) {
643  continue;
644  }
645  else {
647  "Invalid separator character"),
648  ctx.range().get_return()};
649  }
650  }
651  }
652  return {{}, ctx.range().get_return()};
653  }
654 
661  template <typename T>
662  struct discard_type {
663  discard_type() = default;
664  };
665 
682  template <typename T>
684  {
685  return temp(discard_type<T>{})();
686  }
687 
688  template <typename CharT, typename T>
689  struct scanner<CharT, discard_type<T>> : public scanner<CharT, T> {
690  template <typename Context>
691  error scan(discard_type<T>&, Context& ctx)
692  {
693  T tmp;
694  return scanner<CharT, T>::scan(tmp, ctx);
695  }
696  };
697 
699 } // namespace scn
700 
701 #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:466
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:275
constexpr const ignore_iterator_n & operator=(CharT) const noexcept
Definition: scan.h:487
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:135
Scanned value was invalid for given type.
Definition: result.h:44
std::ptrdiff_t difference_type
Definition: scan.h:481
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:212
auto getline_impl(WrappedRange &r, basic_string_view< CharT > &str, CharT until) -> detail::scan_result_for_range_t< WrappedRange, wrapped_error >
Definition: scan.h:374
constexpr const_pointer data() const noexcept
Definition: string_view.h:155
#define SCN_END_NAMESPACE
Definition: config.h:406
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:455
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:168
std::output_iterator_tag iterator_category
Definition: scan.h:482
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:454
SCN_CONSTEXPR14 ignore_iterator_n & operator++() noexcept
Definition: scan.h:497
value_type & reference
Definition: scan.h:480
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:341
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:557
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:683
difference_type i
Definition: scan.h:512
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:581
typename range_wrapper_for< Range >::type range_wrapper_for_t
Definition: range.h:280
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:305
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:503
constexpr const ignore_iterator_n & operator*() const noexcept
Definition: scan.h:492
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:507
Error class.
Definition: result.h:32
#define SCN_BEGIN_NAMESPACE
Definition: config.h:405
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:72
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:242
ignore_iterator_n(difference_type n)
Definition: scan.h:485
constexpr const ignore_iterator & operator=(CharT) const noexcept
Definition: scan.h:461
constexpr ignore_iterator()=default
std::ptrdiff_t difference_type
Definition: scan.h:456
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:610
constexpr const ignore_iterator & operator++() const noexcept
Definition: scan.h:470
error scan(discard_type< T > &, Context &ctx)
Definition: scan.h:691
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:103
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:535
auto ignore_until_impl(WrappedRange &r, CharT until) -> scan_result< WrappedRange, wrapped_error >
Definition: scan.h:519
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:417
std::output_iterator_tag iterator_category
Definition: scan.h:457
#define SCN_EXPECT(cond)
Definition: config.h:401
#define SCN_CONSTEXPR14
Definition: config.h:246