scnlib  0.2.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
parse_context.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_PARSE_CONTEXT_H
19 #define SCN_DETAIL_PARSE_CONTEXT_H
20 
21 #include "result.h"
22 #include "string_view.h"
23 
24 namespace scn {
26 
27  namespace detail {
29  public:
30  SCN_CONSTEXPR14 std::ptrdiff_t next_arg_id()
31  {
32  return m_next_arg_id >= 0 ? m_next_arg_id++ : 0;
33  }
34  SCN_CONSTEXPR14 bool check_arg_id(std::ptrdiff_t)
35  {
36  if (m_next_arg_id > 0) {
37  return false;
38  }
39  m_next_arg_id = -1;
40  return true;
41  }
42 
43  protected:
44  parse_context_base() = default;
45 
46  std::ptrdiff_t m_next_arg_id{0};
47  };
48  template <typename Char>
50  public:
53  };
54  } // namespace detail
55 
57  SCN_CLANG_IGNORE("-Wpadded")
58 
59  template <typename Locale>
61  : public detail::basic_parse_context_base<typename Locale::char_type> {
62  public:
63  using locale_type = Locale;
64  using char_type = typename Locale::char_type;
67 
69  locale_type& loc)
70  : m_str(f), m_locale(loc)
71  {
72  }
73 
75  {
76  bool skip = false;
77  while (*this && m_locale.is_space(next())) {
78  skip = true;
79  advance();
80  }
81  return skip;
82  }
84  {
85  const auto brace = detail::ascii_widen<char_type>('{');
86  if (next() != brace) {
87  if (next() == detail::ascii_widen<char_type>('}')) {
88  advance();
89  }
90  return true;
91  }
92  if (SCN_UNLIKELY(m_str.size() > 1 &&
93  *(m_str.begin() + 1) == brace)) {
94  advance();
95  return true;
96  }
97  return false;
98  }
99  constexpr bool check_literal(char_type ch) const
100  {
101  return ch == next();
102  }
103 
104  constexpr bool good() const
105  {
106  return !m_str.empty();
107  }
108  constexpr explicit operator bool() const
109  {
110  return good();
111  }
112 
113  SCN_CONSTEXPR14 void advance(std::ptrdiff_t n = 1) noexcept
114  {
115  SCN_EXPECT(good());
116  m_str.remove_prefix(static_cast<std::size_t>(n));
117  }
118  constexpr char_type next() const
119  {
120  return m_str.front();
121  }
122 
123  constexpr bool check_arg_begin() const
124  {
125  return next() == detail::ascii_widen<char_type>('{');
126  }
127  constexpr bool check_arg_end() const
128  {
129  return next() == detail::ascii_widen<char_type>('}');
130  }
131 
132  SCN_CONSTEXPR14 void arg_begin() const noexcept {}
133  SCN_CONSTEXPR14 void arg_end() const noexcept {}
134 
135  SCN_CONSTEXPR14 void arg_handled() const noexcept {}
136 
137  template <typename Scanner>
138  error parse(Scanner& s)
139  {
140  return s.parse(*this);
141  }
142 
143  bool has_arg_id()
144  {
145  SCN_EXPECT(good());
146  if (m_str.size() == 1) {
147  return true;
148  }
149  if (m_str[1] == detail::ascii_widen<char_type>('}')) {
150  advance();
151  return false;
152  }
153  if (m_str[1] == detail::ascii_widen<char_type>(':')) {
154  advance(2);
155  return false;
156  }
157  return true;
158  }
160  {
161  SCN_EXPECT(good());
162  advance();
163  if (SCN_UNLIKELY(!good())) {
165  "Unexpected end of format argument");
166  }
167  auto it = m_str.begin();
168  for (std::ptrdiff_t i = 0; good(); ++i, (void)advance()) {
169  if (check_arg_end()) {
170  return string_view_type{
171  it,
172  static_cast<typename string_view_type::size_type>(i)};
173  }
174  if (next() == detail::ascii_widen<char_type>(':')) {
175  advance();
176  return string_view_type{
177  it,
178  static_cast<typename string_view_type::size_type>(i)};
179  }
180  }
182  "Unexpected end of format argument");
183  }
184 
185  private:
186  string_view_type m_str;
187  locale_type& m_locale;
188  };
189 
190  template <typename Locale>
192  : public detail::basic_parse_context_base<typename Locale::char_type> {
193  public:
194  using locale_type = Locale;
195  using char_type = typename Locale::char_type;
198 
199  explicit constexpr basic_scanf_parse_context(
201  locale_type& loc)
202  : m_str(f), m_it(m_str.begin()), m_locale(loc)
203  {
204  }
205 
207  {
208  bool skip = false;
209  while (good() && m_locale.is_space(next())) {
210  skip = true;
211  advance();
212  }
213  return skip;
214  }
216  {
217  const auto percent = detail::ascii_widen<char_type>('%');
218  if (next() != percent) {
219  return true;
220  }
221  if (SCN_UNLIKELY(std::distance(m_it, m_str.end()) > 1 &&
222  *(m_it + 1) == percent)) {
223  advance();
224  return true;
225  }
226  return false;
227  }
228  constexpr bool check_literal(char_type ch) const
229  {
230  return ch == next();
231  }
232 
233  constexpr bool good() const
234  {
235  return m_it != m_str.end();
236  }
237  constexpr explicit operator bool() const
238  {
239  return good();
240  }
241 
242  SCN_CONSTEXPR14 void advance(std::ptrdiff_t n = 1) noexcept
243  {
244  SCN_EXPECT(good());
245  m_it += n;
246  }
247  constexpr char_type next() const
248  {
249  return *m_it;
250  }
251 
252  bool check_arg_begin() const
253  {
254  return next() == detail::ascii_widen<char_type>('%');
255  }
256  bool check_arg_end() const
257  {
258  return !good() || check_arg_begin() || m_locale.is_space(next());
259  }
260 
262  {
263  advance();
264  }
266  {
267  if (good()) {
268  backward();
269  }
270  }
271 
272  SCN_CONSTEXPR14 void arg_handled() const noexcept {}
273 
274  template <typename Scanner>
275  error parse(Scanner& s)
276  {
277  return s.parse(*this);
278  }
279 
280  constexpr bool has_arg_id() const
281  {
282  return false;
283  }
285  {
286  SCN_EXPECT(good());
287  return string_view_type{};
288  }
289 
290  private:
291  void backward(std::ptrdiff_t n = 1) noexcept
292  {
293  SCN_EXPECT(m_it != m_str.begin());
294  m_it -= n;
295  }
296 
297  basic_string_view<char_type> m_str;
298  iterator m_it;
299  locale_type& m_locale;
300  };
301 
302  template <typename Locale>
304  : public detail::basic_parse_context_base<typename Locale::char_type> {
305  public:
306  using locale_type = Locale;
307  using char_type = typename Locale::char_type;
309 
310  explicit constexpr basic_empty_parse_context(int args, Locale& loc)
311  : m_args_left(args), m_locale(loc)
312  {
313  }
314 
316  {
317  if (m_should_skip_ws) {
318  m_should_skip_ws = false;
319  return true;
320  }
321  return false;
322  }
323  constexpr bool should_read_literal() const
324  {
325  return false;
326  }
327  constexpr bool check_literal(char_type) const
328  {
329  return false;
330  }
331 
332  constexpr bool good() const
333  {
334  return m_args_left > 0;
335  }
336  constexpr explicit operator bool() const
337  {
338  return good();
339  }
340 
341  SCN_CONSTEXPR14 void advance(std::ptrdiff_t = 1) const noexcept {}
342  char_type next() const
343  {
344  SCN_EXPECT(false);
346  }
347 
348  constexpr bool check_arg_begin() const
349  {
350  return true;
351  }
352  constexpr bool check_arg_end() const
353  {
354  return true;
355  }
356 
357  SCN_CONSTEXPR14 void arg_begin() const noexcept {}
358  SCN_CONSTEXPR14 void arg_end() const noexcept {}
359 
361  {
362  m_should_skip_ws = true;
363  --m_args_left;
364  }
365 
366  template <typename Scanner>
367  constexpr error parse(Scanner&) const
368  {
369  return {};
370  }
371 
372  constexpr bool has_arg_id() const
373  {
374  return false;
375  }
377  {
378  SCN_EXPECT(good());
379  return string_view_type{};
380  }
381 
382  private:
383  int m_args_left;
384  bool m_should_skip_ws{false};
385  locale_type& m_locale;
386  };
387 
389 
391 } // namespace scn
392 
393 #endif // SCN_DETAIL_PARSE_CONTEXT_H
constexpr bool check_literal(char_type) const
constexpr bool check_literal(char_type ch) const
Definition: parse_context.h:99
SCN_CONSTEXPR14 bool check_arg_id(std::ptrdiff_t)
Definition: parse_context.h:34
SCN_CONSTEXPR14 void arg_handled()
constexpr const_iterator begin() const noexcept
Definition: string_view.h:103
constexpr expected< string_view_type > parse_arg_id() const
#define SCN_END_NAMESPACE
Definition: config.h:401
constexpr bool check_arg_end() const
#define SCN_UNLIKELY(x)
Definition: config.h:362
SCN_CONSTEXPR14 void arg_handled() const noexcept
SCN_CONSTEXPR14 void arg_handled() const noexcept
constexpr bool good() const
constexpr basic_parse_context(basic_string_view< char_type > f, locale_type &loc)
Definition: parse_context.h:68
typename Locale::char_type char_type
Definition: parse_context.h:64
SCN_CONSTEXPR14 void arg_end() const noexcept
#define SCN_UNREACHABLE
Definition: config.h:347
SCN_CONSTEXPR14 void check_arg_id(basic_string_view< Char >)
Definition: parse_context.h:52
#define SCN_CLANG_IGNORE(x)
Definition: config.h:144
constexpr char_type next() const
constexpr basic_scanf_parse_context(basic_string_view< char_type > f, locale_type &loc)
Format string was invalid.
Definition: result.h:41
expected-like type.
Definition: result.h:180
constexpr const_iterator end() const noexcept
Definition: string_view.h:111
expected< string_view_type > parse_arg_id()
SCN_CONSTEXPR14 void arg_begin()
SCN_CONSTEXPR14 void arg_end() const noexcept
SCN_CONSTEXPR14 std::ptrdiff_t next_arg_id()
Definition: parse_context.h:30
SCN_CONSTEXPR14 void advance(std::ptrdiff_t n=1) noexcept
SCN_CONSTEXPR14 void arg_end()
typename string_view_type::iterator iterator
Definition: parse_context.h:66
constexpr bool check_arg_begin() const
SCN_CONSTEXPR14 void arg_begin() const noexcept
#define SCN_CLANG_POP
Definition: config.h:143
SCN_CONSTEXPR14 void advance(std::ptrdiff_t=1) const noexcept
constexpr bool check_arg_begin() const
constexpr bool should_read_literal() const
constexpr bool good() const
Error class.
Definition: result.h:32
#define SCN_BEGIN_NAMESPACE
Definition: config.h:400
error parse(Scanner &s)
SCN_CONSTEXPR14 bool should_skip_ws()
constexpr char_type next() const
typename span_type::const_iterator iterator
Definition: string_view.h:69
SCN_CONSTEXPR14 void advance(std::ptrdiff_t n=1) noexcept
constexpr bool has_arg_id() const
constexpr basic_empty_parse_context(int args, Locale &loc)
typename string_view_type::iterator iterator
constexpr bool good() const
constexpr bool check_literal(char_type ch) const
constexpr expected< string_view_type > parse_arg_id() const
SCN_CONSTEXPR14 void arg_begin() const noexcept
void begin(T &&)=delete
A view over a (sub)string.
Definition: string_view.h:60
constexpr bool check_arg_end() const
constexpr bool has_arg_id() const
#define SCN_EXPECT(cond)
Definition: config.h:396
constexpr error parse(Scanner &) const
#define SCN_CLANG_PUSH
Definition: config.h:142
#define SCN_CONSTEXPR14
Definition: config.h:240