xref: /aosp_15_r20/external/fmtlib/test/scan.h (revision 5c90c05cd622c0a81b57953a4d343e0e489f2e08)
1*5c90c05cSAndroid Build Coastguard Worker // Formatting library for C++ - scanning API proof of concept
2*5c90c05cSAndroid Build Coastguard Worker //
3*5c90c05cSAndroid Build Coastguard Worker // Copyright (c) 2019 - present, Victor Zverovich
4*5c90c05cSAndroid Build Coastguard Worker // All rights reserved.
5*5c90c05cSAndroid Build Coastguard Worker //
6*5c90c05cSAndroid Build Coastguard Worker // For the license information refer to format.h.
7*5c90c05cSAndroid Build Coastguard Worker 
8*5c90c05cSAndroid Build Coastguard Worker #include <array>
9*5c90c05cSAndroid Build Coastguard Worker #include <cassert>
10*5c90c05cSAndroid Build Coastguard Worker #include <climits>
11*5c90c05cSAndroid Build Coastguard Worker #include <tuple>
12*5c90c05cSAndroid Build Coastguard Worker 
13*5c90c05cSAndroid Build Coastguard Worker #include "fmt/format-inl.h"
14*5c90c05cSAndroid Build Coastguard Worker 
15*5c90c05cSAndroid Build Coastguard Worker FMT_BEGIN_NAMESPACE
16*5c90c05cSAndroid Build Coastguard Worker namespace detail {
17*5c90c05cSAndroid Build Coastguard Worker 
18*5c90c05cSAndroid Build Coastguard Worker inline auto is_whitespace(char c) -> bool { return c == ' ' || c == '\n'; }
19*5c90c05cSAndroid Build Coastguard Worker 
20*5c90c05cSAndroid Build Coastguard Worker // If c is a hex digit returns its numeric value, otherwise -1.
21*5c90c05cSAndroid Build Coastguard Worker inline auto to_hex_digit(char c) -> int {
22*5c90c05cSAndroid Build Coastguard Worker   if (c >= '0' && c <= '9') return c - '0';
23*5c90c05cSAndroid Build Coastguard Worker   if (c >= 'a' && c <= 'f') return c - 'a' + 10;
24*5c90c05cSAndroid Build Coastguard Worker   if (c >= 'A' && c <= 'F') return c - 'A' + 10;
25*5c90c05cSAndroid Build Coastguard Worker   return -1;
26*5c90c05cSAndroid Build Coastguard Worker }
27*5c90c05cSAndroid Build Coastguard Worker 
28*5c90c05cSAndroid Build Coastguard Worker struct maybe_contiguous_range {
29*5c90c05cSAndroid Build Coastguard Worker   const char* begin;
30*5c90c05cSAndroid Build Coastguard Worker   const char* end;
31*5c90c05cSAndroid Build Coastguard Worker 
32*5c90c05cSAndroid Build Coastguard Worker   explicit operator bool() const { return begin != nullptr; }
33*5c90c05cSAndroid Build Coastguard Worker };
34*5c90c05cSAndroid Build Coastguard Worker 
35*5c90c05cSAndroid Build Coastguard Worker class scan_buffer {
36*5c90c05cSAndroid Build Coastguard Worker  private:
37*5c90c05cSAndroid Build Coastguard Worker   const char* ptr_;
38*5c90c05cSAndroid Build Coastguard Worker   const char* end_;
39*5c90c05cSAndroid Build Coastguard Worker   bool contiguous_;
40*5c90c05cSAndroid Build Coastguard Worker 
41*5c90c05cSAndroid Build Coastguard Worker  protected:
scan_buffer(const char * ptr,const char * end,bool contiguous)42*5c90c05cSAndroid Build Coastguard Worker   scan_buffer(const char* ptr, const char* end, bool contiguous)
43*5c90c05cSAndroid Build Coastguard Worker       : ptr_(ptr), end_(end), contiguous_(contiguous) {}
44*5c90c05cSAndroid Build Coastguard Worker   ~scan_buffer() = default;
45*5c90c05cSAndroid Build Coastguard Worker 
set(span<const char> buf)46*5c90c05cSAndroid Build Coastguard Worker   void set(span<const char> buf) {
47*5c90c05cSAndroid Build Coastguard Worker     ptr_ = buf.data;
48*5c90c05cSAndroid Build Coastguard Worker     end_ = buf.data + buf.size;
49*5c90c05cSAndroid Build Coastguard Worker   }
50*5c90c05cSAndroid Build Coastguard Worker 
51*5c90c05cSAndroid Build Coastguard Worker   auto ptr() const -> const char* { return ptr_; }
52*5c90c05cSAndroid Build Coastguard Worker 
53*5c90c05cSAndroid Build Coastguard Worker  public:
54*5c90c05cSAndroid Build Coastguard Worker   scan_buffer(const scan_buffer&) = delete;
55*5c90c05cSAndroid Build Coastguard Worker   void operator=(const scan_buffer&) = delete;
56*5c90c05cSAndroid Build Coastguard Worker 
57*5c90c05cSAndroid Build Coastguard Worker   // Fills the buffer with more input if available.
58*5c90c05cSAndroid Build Coastguard Worker   virtual void consume() = 0;
59*5c90c05cSAndroid Build Coastguard Worker 
60*5c90c05cSAndroid Build Coastguard Worker   class sentinel {};
61*5c90c05cSAndroid Build Coastguard Worker 
62*5c90c05cSAndroid Build Coastguard Worker   class iterator {
63*5c90c05cSAndroid Build Coastguard Worker    private:
64*5c90c05cSAndroid Build Coastguard Worker     const char** ptr_;
65*5c90c05cSAndroid Build Coastguard Worker     scan_buffer* buf_;  // This could be merged with ptr_.
66*5c90c05cSAndroid Build Coastguard Worker     char value_;
67*5c90c05cSAndroid Build Coastguard Worker 
68*5c90c05cSAndroid Build Coastguard Worker     static auto get_sentinel() -> const char** {
69*5c90c05cSAndroid Build Coastguard Worker       static const char* ptr = nullptr;
70*5c90c05cSAndroid Build Coastguard Worker       return &ptr;
71*5c90c05cSAndroid Build Coastguard Worker     }
72*5c90c05cSAndroid Build Coastguard Worker 
73*5c90c05cSAndroid Build Coastguard Worker     friend class scan_buffer;
74*5c90c05cSAndroid Build Coastguard Worker 
75*5c90c05cSAndroid Build Coastguard Worker     friend auto operator==(iterator lhs, sentinel) -> bool {
76*5c90c05cSAndroid Build Coastguard Worker       return *lhs.ptr_ == nullptr;
77*5c90c05cSAndroid Build Coastguard Worker     }
78*5c90c05cSAndroid Build Coastguard Worker     friend auto operator!=(iterator lhs, sentinel) -> bool {
79*5c90c05cSAndroid Build Coastguard Worker       return *lhs.ptr_ != nullptr;
80*5c90c05cSAndroid Build Coastguard Worker     }
81*5c90c05cSAndroid Build Coastguard Worker 
iterator(scan_buffer * buf)82*5c90c05cSAndroid Build Coastguard Worker     iterator(scan_buffer* buf) : buf_(buf) {
83*5c90c05cSAndroid Build Coastguard Worker       if (buf->ptr_ == buf->end_) {
84*5c90c05cSAndroid Build Coastguard Worker         ptr_ = get_sentinel();
85*5c90c05cSAndroid Build Coastguard Worker         return;
86*5c90c05cSAndroid Build Coastguard Worker       }
87*5c90c05cSAndroid Build Coastguard Worker       ptr_ = &buf->ptr_;
88*5c90c05cSAndroid Build Coastguard Worker       value_ = *buf->ptr_;
89*5c90c05cSAndroid Build Coastguard Worker     }
90*5c90c05cSAndroid Build Coastguard Worker 
get_buffer(iterator it)91*5c90c05cSAndroid Build Coastguard Worker     friend scan_buffer& get_buffer(iterator it) { return *it.buf_; }
92*5c90c05cSAndroid Build Coastguard Worker 
93*5c90c05cSAndroid Build Coastguard Worker    public:
iterator()94*5c90c05cSAndroid Build Coastguard Worker     iterator() : ptr_(get_sentinel()), buf_(nullptr) {}
95*5c90c05cSAndroid Build Coastguard Worker 
96*5c90c05cSAndroid Build Coastguard Worker     auto operator++() -> iterator& {
97*5c90c05cSAndroid Build Coastguard Worker       if (!buf_->try_consume()) ptr_ = get_sentinel();
98*5c90c05cSAndroid Build Coastguard Worker       value_ = *buf_->ptr_;
99*5c90c05cSAndroid Build Coastguard Worker       return *this;
100*5c90c05cSAndroid Build Coastguard Worker     }
101*5c90c05cSAndroid Build Coastguard Worker     auto operator++(int) -> iterator {
102*5c90c05cSAndroid Build Coastguard Worker       iterator copy = *this;
103*5c90c05cSAndroid Build Coastguard Worker       ++*this;
104*5c90c05cSAndroid Build Coastguard Worker       return copy;
105*5c90c05cSAndroid Build Coastguard Worker     }
106*5c90c05cSAndroid Build Coastguard Worker     auto operator*() const -> char { return value_; }
107*5c90c05cSAndroid Build Coastguard Worker 
108*5c90c05cSAndroid Build Coastguard Worker     auto base() const -> const char* { return buf_->ptr_; }
109*5c90c05cSAndroid Build Coastguard Worker 
110*5c90c05cSAndroid Build Coastguard Worker     friend auto to_contiguous(iterator it) -> maybe_contiguous_range;
111*5c90c05cSAndroid Build Coastguard Worker     friend auto advance(iterator it, size_t n) -> iterator;
112*5c90c05cSAndroid Build Coastguard Worker   };
113*5c90c05cSAndroid Build Coastguard Worker 
114*5c90c05cSAndroid Build Coastguard Worker   friend auto to_contiguous(iterator it) -> maybe_contiguous_range {
115*5c90c05cSAndroid Build Coastguard Worker     if (it.buf_->is_contiguous()) return {it.buf_->ptr_, it.buf_->end_};
116*5c90c05cSAndroid Build Coastguard Worker     return {nullptr, nullptr};
117*5c90c05cSAndroid Build Coastguard Worker   }
118*5c90c05cSAndroid Build Coastguard Worker   friend auto advance(iterator it, size_t n) -> iterator {
119*5c90c05cSAndroid Build Coastguard Worker     FMT_ASSERT(it.buf_->is_contiguous(), "");
120*5c90c05cSAndroid Build Coastguard Worker     const char*& ptr = it.buf_->ptr_;
121*5c90c05cSAndroid Build Coastguard Worker     ptr += n;
122*5c90c05cSAndroid Build Coastguard Worker     it.value_ = *ptr;
123*5c90c05cSAndroid Build Coastguard Worker     if (ptr == it.buf_->end_) it.ptr_ = iterator::get_sentinel();
124*5c90c05cSAndroid Build Coastguard Worker     return it;
125*5c90c05cSAndroid Build Coastguard Worker   }
126*5c90c05cSAndroid Build Coastguard Worker 
127*5c90c05cSAndroid Build Coastguard Worker   auto begin() -> iterator { return this; }
128*5c90c05cSAndroid Build Coastguard Worker   auto end() -> sentinel { return {}; }
129*5c90c05cSAndroid Build Coastguard Worker 
130*5c90c05cSAndroid Build Coastguard Worker   auto is_contiguous() const -> bool { return contiguous_; }
131*5c90c05cSAndroid Build Coastguard Worker 
132*5c90c05cSAndroid Build Coastguard Worker   // Tries consuming a single code unit. Returns true iff there is more input.
133*5c90c05cSAndroid Build Coastguard Worker   auto try_consume() -> bool {
134*5c90c05cSAndroid Build Coastguard Worker     FMT_ASSERT(ptr_ != end_, "");
135*5c90c05cSAndroid Build Coastguard Worker     ++ptr_;
136*5c90c05cSAndroid Build Coastguard Worker     if (ptr_ != end_) return true;
137*5c90c05cSAndroid Build Coastguard Worker     consume();
138*5c90c05cSAndroid Build Coastguard Worker     return ptr_ != end_;
139*5c90c05cSAndroid Build Coastguard Worker   }
140*5c90c05cSAndroid Build Coastguard Worker };
141*5c90c05cSAndroid Build Coastguard Worker 
142*5c90c05cSAndroid Build Coastguard Worker using scan_iterator = scan_buffer::iterator;
143*5c90c05cSAndroid Build Coastguard Worker using scan_sentinel = scan_buffer::sentinel;
144*5c90c05cSAndroid Build Coastguard Worker 
145*5c90c05cSAndroid Build Coastguard Worker class string_scan_buffer final : public scan_buffer {
146*5c90c05cSAndroid Build Coastguard Worker  private:
consume()147*5c90c05cSAndroid Build Coastguard Worker   void consume() override {}
148*5c90c05cSAndroid Build Coastguard Worker 
149*5c90c05cSAndroid Build Coastguard Worker  public:
string_scan_buffer(string_view s)150*5c90c05cSAndroid Build Coastguard Worker   explicit string_scan_buffer(string_view s)
151*5c90c05cSAndroid Build Coastguard Worker       : scan_buffer(s.begin(), s.end(), true) {}
152*5c90c05cSAndroid Build Coastguard Worker };
153*5c90c05cSAndroid Build Coastguard Worker 
154*5c90c05cSAndroid Build Coastguard Worker class file_scan_buffer final : public scan_buffer {
155*5c90c05cSAndroid Build Coastguard Worker  private:
156*5c90c05cSAndroid Build Coastguard Worker   template <typename F, FMT_ENABLE_IF(sizeof(F::_IO_read_ptr) != 0 &&
157*5c90c05cSAndroid Build Coastguard Worker                                       !FMT_USE_FALLBACK_FILE)>
158*5c90c05cSAndroid Build Coastguard Worker   static auto get_file(F* f, int) -> glibc_file<F> {
159*5c90c05cSAndroid Build Coastguard Worker     return f;
160*5c90c05cSAndroid Build Coastguard Worker   }
161*5c90c05cSAndroid Build Coastguard Worker   template <typename F,
162*5c90c05cSAndroid Build Coastguard Worker             FMT_ENABLE_IF(sizeof(F::_p) != 0 && !FMT_USE_FALLBACK_FILE)>
163*5c90c05cSAndroid Build Coastguard Worker   static auto get_file(F* f, int) -> apple_file<F> {
164*5c90c05cSAndroid Build Coastguard Worker     return f;
165*5c90c05cSAndroid Build Coastguard Worker   }
166*5c90c05cSAndroid Build Coastguard Worker   static auto get_file(FILE* f, ...) -> fallback_file<FILE> { return f; }
167*5c90c05cSAndroid Build Coastguard Worker 
168*5c90c05cSAndroid Build Coastguard Worker   decltype(get_file(static_cast<FILE*>(nullptr), 0)) file_;
169*5c90c05cSAndroid Build Coastguard Worker 
170*5c90c05cSAndroid Build Coastguard Worker   // Fills the buffer if it is empty.
fill()171*5c90c05cSAndroid Build Coastguard Worker   void fill() {
172*5c90c05cSAndroid Build Coastguard Worker     span<const char> buf = file_.get_read_buffer();
173*5c90c05cSAndroid Build Coastguard Worker     if (buf.size == 0) {
174*5c90c05cSAndroid Build Coastguard Worker       int c = file_.get();
175*5c90c05cSAndroid Build Coastguard Worker       // Put the character back since we are only filling the buffer.
176*5c90c05cSAndroid Build Coastguard Worker       if (c != EOF) file_.unget(static_cast<char>(c));
177*5c90c05cSAndroid Build Coastguard Worker       buf = file_.get_read_buffer();
178*5c90c05cSAndroid Build Coastguard Worker     }
179*5c90c05cSAndroid Build Coastguard Worker     set(buf);
180*5c90c05cSAndroid Build Coastguard Worker   }
181*5c90c05cSAndroid Build Coastguard Worker 
consume()182*5c90c05cSAndroid Build Coastguard Worker   void consume() override {
183*5c90c05cSAndroid Build Coastguard Worker     // Consume the current buffer content.
184*5c90c05cSAndroid Build Coastguard Worker     size_t n = to_unsigned(ptr() - file_.get_read_buffer().data);
185*5c90c05cSAndroid Build Coastguard Worker     for (size_t i = 0; i != n; ++i) file_.get();
186*5c90c05cSAndroid Build Coastguard Worker     fill();
187*5c90c05cSAndroid Build Coastguard Worker   }
188*5c90c05cSAndroid Build Coastguard Worker 
189*5c90c05cSAndroid Build Coastguard Worker  public:
file_scan_buffer(FILE * f)190*5c90c05cSAndroid Build Coastguard Worker   explicit file_scan_buffer(FILE* f)
191*5c90c05cSAndroid Build Coastguard Worker       : scan_buffer(nullptr, nullptr, false), file_(f) {
192*5c90c05cSAndroid Build Coastguard Worker     flockfile(f);
193*5c90c05cSAndroid Build Coastguard Worker     fill();
194*5c90c05cSAndroid Build Coastguard Worker   }
~file_scan_buffer()195*5c90c05cSAndroid Build Coastguard Worker   ~file_scan_buffer() {
196*5c90c05cSAndroid Build Coastguard Worker     FILE* f = file_;
197*5c90c05cSAndroid Build Coastguard Worker     funlockfile(f);
198*5c90c05cSAndroid Build Coastguard Worker   }
199*5c90c05cSAndroid Build Coastguard Worker };
200*5c90c05cSAndroid Build Coastguard Worker }  // namespace detail
201*5c90c05cSAndroid Build Coastguard Worker 
202*5c90c05cSAndroid Build Coastguard Worker template <typename T, typename Char = char> struct scanner {
203*5c90c05cSAndroid Build Coastguard Worker   // A deleted default constructor indicates a disabled scanner.
204*5c90c05cSAndroid Build Coastguard Worker   scanner() = delete;
205*5c90c05cSAndroid Build Coastguard Worker };
206*5c90c05cSAndroid Build Coastguard Worker 
207*5c90c05cSAndroid Build Coastguard Worker class scan_parse_context {
208*5c90c05cSAndroid Build Coastguard Worker  private:
209*5c90c05cSAndroid Build Coastguard Worker   string_view format_;
210*5c90c05cSAndroid Build Coastguard Worker 
211*5c90c05cSAndroid Build Coastguard Worker  public:
212*5c90c05cSAndroid Build Coastguard Worker   using iterator = string_view::iterator;
213*5c90c05cSAndroid Build Coastguard Worker 
scan_parse_context(string_view format)214*5c90c05cSAndroid Build Coastguard Worker   explicit FMT_CONSTEXPR scan_parse_context(string_view format)
215*5c90c05cSAndroid Build Coastguard Worker       : format_(format) {}
216*5c90c05cSAndroid Build Coastguard Worker 
217*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR auto begin() const -> iterator { return format_.begin(); }
218*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR auto end() const -> iterator { return format_.end(); }
219*5c90c05cSAndroid Build Coastguard Worker 
advance_to(iterator it)220*5c90c05cSAndroid Build Coastguard Worker   void advance_to(iterator it) {
221*5c90c05cSAndroid Build Coastguard Worker     format_.remove_prefix(detail::to_unsigned(it - begin()));
222*5c90c05cSAndroid Build Coastguard Worker   }
223*5c90c05cSAndroid Build Coastguard Worker };
224*5c90c05cSAndroid Build Coastguard Worker 
225*5c90c05cSAndroid Build Coastguard Worker namespace detail {
226*5c90c05cSAndroid Build Coastguard Worker enum class scan_type {
227*5c90c05cSAndroid Build Coastguard Worker   none_type,
228*5c90c05cSAndroid Build Coastguard Worker   int_type,
229*5c90c05cSAndroid Build Coastguard Worker   uint_type,
230*5c90c05cSAndroid Build Coastguard Worker   long_long_type,
231*5c90c05cSAndroid Build Coastguard Worker   ulong_long_type,
232*5c90c05cSAndroid Build Coastguard Worker   string_type,
233*5c90c05cSAndroid Build Coastguard Worker   string_view_type,
234*5c90c05cSAndroid Build Coastguard Worker   custom_type
235*5c90c05cSAndroid Build Coastguard Worker };
236*5c90c05cSAndroid Build Coastguard Worker 
237*5c90c05cSAndroid Build Coastguard Worker template <typename Context> struct custom_scan_arg {
238*5c90c05cSAndroid Build Coastguard Worker   void* value;
239*5c90c05cSAndroid Build Coastguard Worker   void (*scan)(void* arg, scan_parse_context& parse_ctx, Context& ctx);
240*5c90c05cSAndroid Build Coastguard Worker };
241*5c90c05cSAndroid Build Coastguard Worker }  // namespace detail
242*5c90c05cSAndroid Build Coastguard Worker 
243*5c90c05cSAndroid Build Coastguard Worker // A scan argument. Context is a template parameter for the compiled API where
244*5c90c05cSAndroid Build Coastguard Worker // output can be unbuffered.
245*5c90c05cSAndroid Build Coastguard Worker template <typename Context> class basic_scan_arg {
246*5c90c05cSAndroid Build Coastguard Worker  private:
247*5c90c05cSAndroid Build Coastguard Worker   using scan_type = detail::scan_type;
248*5c90c05cSAndroid Build Coastguard Worker   scan_type type_;
249*5c90c05cSAndroid Build Coastguard Worker   union {
250*5c90c05cSAndroid Build Coastguard Worker     int* int_value_;
251*5c90c05cSAndroid Build Coastguard Worker     unsigned* uint_value_;
252*5c90c05cSAndroid Build Coastguard Worker     long long* long_long_value_;
253*5c90c05cSAndroid Build Coastguard Worker     unsigned long long* ulong_long_value_;
254*5c90c05cSAndroid Build Coastguard Worker     std::string* string_;
255*5c90c05cSAndroid Build Coastguard Worker     string_view* string_view_;
256*5c90c05cSAndroid Build Coastguard Worker     detail::custom_scan_arg<Context> custom_;
257*5c90c05cSAndroid Build Coastguard Worker     // TODO: more types
258*5c90c05cSAndroid Build Coastguard Worker   };
259*5c90c05cSAndroid Build Coastguard Worker 
260*5c90c05cSAndroid Build Coastguard Worker   template <typename T>
scan_custom_arg(void * arg,scan_parse_context & parse_ctx,Context & ctx)261*5c90c05cSAndroid Build Coastguard Worker   static void scan_custom_arg(void* arg, scan_parse_context& parse_ctx,
262*5c90c05cSAndroid Build Coastguard Worker                               Context& ctx) {
263*5c90c05cSAndroid Build Coastguard Worker     auto s = scanner<T>();
264*5c90c05cSAndroid Build Coastguard Worker     parse_ctx.advance_to(s.parse(parse_ctx));
265*5c90c05cSAndroid Build Coastguard Worker     ctx.advance_to(s.scan(*static_cast<T*>(arg), ctx));
266*5c90c05cSAndroid Build Coastguard Worker   }
267*5c90c05cSAndroid Build Coastguard Worker 
268*5c90c05cSAndroid Build Coastguard Worker  public:
basic_scan_arg()269*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR basic_scan_arg()
270*5c90c05cSAndroid Build Coastguard Worker       : type_(scan_type::none_type), int_value_(nullptr) {}
basic_scan_arg(int & value)271*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR basic_scan_arg(int& value)
272*5c90c05cSAndroid Build Coastguard Worker       : type_(scan_type::int_type), int_value_(&value) {}
basic_scan_arg(unsigned & value)273*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR basic_scan_arg(unsigned& value)
274*5c90c05cSAndroid Build Coastguard Worker       : type_(scan_type::uint_type), uint_value_(&value) {}
basic_scan_arg(long long & value)275*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR basic_scan_arg(long long& value)
276*5c90c05cSAndroid Build Coastguard Worker       : type_(scan_type::long_long_type), long_long_value_(&value) {}
basic_scan_arg(unsigned long long & value)277*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR basic_scan_arg(unsigned long long& value)
278*5c90c05cSAndroid Build Coastguard Worker       : type_(scan_type::ulong_long_type), ulong_long_value_(&value) {}
basic_scan_arg(std::string & value)279*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR basic_scan_arg(std::string& value)
280*5c90c05cSAndroid Build Coastguard Worker       : type_(scan_type::string_type), string_(&value) {}
basic_scan_arg(string_view & value)281*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR basic_scan_arg(string_view& value)
282*5c90c05cSAndroid Build Coastguard Worker       : type_(scan_type::string_view_type), string_view_(&value) {}
283*5c90c05cSAndroid Build Coastguard Worker   template <typename T>
basic_scan_arg(T & value)284*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR basic_scan_arg(T& value) : type_(scan_type::custom_type) {
285*5c90c05cSAndroid Build Coastguard Worker     custom_.value = &value;
286*5c90c05cSAndroid Build Coastguard Worker     custom_.scan = scan_custom_arg<T>;
287*5c90c05cSAndroid Build Coastguard Worker   }
288*5c90c05cSAndroid Build Coastguard Worker 
289*5c90c05cSAndroid Build Coastguard Worker   constexpr explicit operator bool() const noexcept {
290*5c90c05cSAndroid Build Coastguard Worker     return type_ != scan_type::none_type;
291*5c90c05cSAndroid Build Coastguard Worker   }
292*5c90c05cSAndroid Build Coastguard Worker 
293*5c90c05cSAndroid Build Coastguard Worker   auto type() const -> detail::scan_type { return type_; }
294*5c90c05cSAndroid Build Coastguard Worker 
295*5c90c05cSAndroid Build Coastguard Worker   template <typename Visitor>
296*5c90c05cSAndroid Build Coastguard Worker   auto visit(Visitor&& vis) -> decltype(vis(monostate())) {
297*5c90c05cSAndroid Build Coastguard Worker     switch (type_) {
298*5c90c05cSAndroid Build Coastguard Worker     case scan_type::none_type:
299*5c90c05cSAndroid Build Coastguard Worker       break;
300*5c90c05cSAndroid Build Coastguard Worker     case scan_type::int_type:
301*5c90c05cSAndroid Build Coastguard Worker       return vis(*int_value_);
302*5c90c05cSAndroid Build Coastguard Worker     case scan_type::uint_type:
303*5c90c05cSAndroid Build Coastguard Worker       return vis(*uint_value_);
304*5c90c05cSAndroid Build Coastguard Worker     case scan_type::long_long_type:
305*5c90c05cSAndroid Build Coastguard Worker       return vis(*long_long_value_);
306*5c90c05cSAndroid Build Coastguard Worker     case scan_type::ulong_long_type:
307*5c90c05cSAndroid Build Coastguard Worker       return vis(*ulong_long_value_);
308*5c90c05cSAndroid Build Coastguard Worker     case scan_type::string_type:
309*5c90c05cSAndroid Build Coastguard Worker       return vis(*string_);
310*5c90c05cSAndroid Build Coastguard Worker     case scan_type::string_view_type:
311*5c90c05cSAndroid Build Coastguard Worker       return vis(*string_view_);
312*5c90c05cSAndroid Build Coastguard Worker     case scan_type::custom_type:
313*5c90c05cSAndroid Build Coastguard Worker       break;
314*5c90c05cSAndroid Build Coastguard Worker     }
315*5c90c05cSAndroid Build Coastguard Worker     return vis(monostate());
316*5c90c05cSAndroid Build Coastguard Worker   }
317*5c90c05cSAndroid Build Coastguard Worker 
318*5c90c05cSAndroid Build Coastguard Worker   auto scan_custom(const char* parse_begin, scan_parse_context& parse_ctx,
319*5c90c05cSAndroid Build Coastguard Worker                    Context& ctx) const -> bool {
320*5c90c05cSAndroid Build Coastguard Worker     if (type_ != scan_type::custom_type) return false;
321*5c90c05cSAndroid Build Coastguard Worker     parse_ctx.advance_to(parse_begin);
322*5c90c05cSAndroid Build Coastguard Worker     custom_.scan(custom_.value, parse_ctx, ctx);
323*5c90c05cSAndroid Build Coastguard Worker     return true;
324*5c90c05cSAndroid Build Coastguard Worker   }
325*5c90c05cSAndroid Build Coastguard Worker };
326*5c90c05cSAndroid Build Coastguard Worker 
327*5c90c05cSAndroid Build Coastguard Worker class scan_context;
328*5c90c05cSAndroid Build Coastguard Worker using scan_arg = basic_scan_arg<scan_context>;
329*5c90c05cSAndroid Build Coastguard Worker 
330*5c90c05cSAndroid Build Coastguard Worker struct scan_args {
331*5c90c05cSAndroid Build Coastguard Worker   int size;
332*5c90c05cSAndroid Build Coastguard Worker   const scan_arg* data;
333*5c90c05cSAndroid Build Coastguard Worker 
334*5c90c05cSAndroid Build Coastguard Worker   template <size_t N>
scan_argsscan_args335*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR scan_args(const std::array<scan_arg, N>& store)
336*5c90c05cSAndroid Build Coastguard Worker       : size(N), data(store.data()) {
337*5c90c05cSAndroid Build Coastguard Worker     static_assert(N < INT_MAX, "too many arguments");
338*5c90c05cSAndroid Build Coastguard Worker   }
339*5c90c05cSAndroid Build Coastguard Worker };
340*5c90c05cSAndroid Build Coastguard Worker 
341*5c90c05cSAndroid Build Coastguard Worker class scan_context {
342*5c90c05cSAndroid Build Coastguard Worker  private:
343*5c90c05cSAndroid Build Coastguard Worker   detail::scan_buffer& buf_;
344*5c90c05cSAndroid Build Coastguard Worker   scan_args args_;
345*5c90c05cSAndroid Build Coastguard Worker 
346*5c90c05cSAndroid Build Coastguard Worker  public:
347*5c90c05cSAndroid Build Coastguard Worker   using iterator = detail::scan_iterator;
348*5c90c05cSAndroid Build Coastguard Worker   using sentinel = detail::scan_sentinel;
349*5c90c05cSAndroid Build Coastguard Worker 
scan_context(detail::scan_buffer & buf,scan_args args)350*5c90c05cSAndroid Build Coastguard Worker   explicit FMT_CONSTEXPR scan_context(detail::scan_buffer& buf, scan_args args)
351*5c90c05cSAndroid Build Coastguard Worker       : buf_(buf), args_(args) {}
352*5c90c05cSAndroid Build Coastguard Worker 
353*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR auto arg(int id) const -> scan_arg {
354*5c90c05cSAndroid Build Coastguard Worker     return id < args_.size ? args_.data[id] : scan_arg();
355*5c90c05cSAndroid Build Coastguard Worker   }
356*5c90c05cSAndroid Build Coastguard Worker 
357*5c90c05cSAndroid Build Coastguard Worker   auto begin() const -> iterator { return buf_.begin(); }
358*5c90c05cSAndroid Build Coastguard Worker   auto end() const -> sentinel { return {}; }
359*5c90c05cSAndroid Build Coastguard Worker 
advance_to(iterator)360*5c90c05cSAndroid Build Coastguard Worker   void advance_to(iterator) { buf_.consume(); }
361*5c90c05cSAndroid Build Coastguard Worker };
362*5c90c05cSAndroid Build Coastguard Worker 
363*5c90c05cSAndroid Build Coastguard Worker namespace detail {
364*5c90c05cSAndroid Build Coastguard Worker 
parse_scan_specs(const char * begin,const char * end,format_specs & specs,scan_type)365*5c90c05cSAndroid Build Coastguard Worker const char* parse_scan_specs(const char* begin, const char* end,
366*5c90c05cSAndroid Build Coastguard Worker                              format_specs& specs, scan_type) {
367*5c90c05cSAndroid Build Coastguard Worker   while (begin != end) {
368*5c90c05cSAndroid Build Coastguard Worker     switch (to_ascii(*begin)) {
369*5c90c05cSAndroid Build Coastguard Worker     // TODO: parse more scan format specifiers
370*5c90c05cSAndroid Build Coastguard Worker     case 'x':
371*5c90c05cSAndroid Build Coastguard Worker       specs.set_type(presentation_type::hex);
372*5c90c05cSAndroid Build Coastguard Worker       ++begin;
373*5c90c05cSAndroid Build Coastguard Worker       break;
374*5c90c05cSAndroid Build Coastguard Worker     case '}':
375*5c90c05cSAndroid Build Coastguard Worker       return begin;
376*5c90c05cSAndroid Build Coastguard Worker     }
377*5c90c05cSAndroid Build Coastguard Worker   }
378*5c90c05cSAndroid Build Coastguard Worker   return begin;
379*5c90c05cSAndroid Build Coastguard Worker }
380*5c90c05cSAndroid Build Coastguard Worker 
381*5c90c05cSAndroid Build Coastguard Worker template <typename T, FMT_ENABLE_IF(std::is_unsigned<T>::value)>
382*5c90c05cSAndroid Build Coastguard Worker auto read(scan_iterator it, T& value) -> scan_iterator {
383*5c90c05cSAndroid Build Coastguard Worker   if (it == scan_sentinel()) return it;
384*5c90c05cSAndroid Build Coastguard Worker   char c = *it;
385*5c90c05cSAndroid Build Coastguard Worker   if (c < '0' || c > '9') report_error("invalid input");
386*5c90c05cSAndroid Build Coastguard Worker 
387*5c90c05cSAndroid Build Coastguard Worker   int num_digits = 0;
388*5c90c05cSAndroid Build Coastguard Worker   T n = 0, prev = 0;
389*5c90c05cSAndroid Build Coastguard Worker   char prev_digit = c;
390*5c90c05cSAndroid Build Coastguard Worker   do {
391*5c90c05cSAndroid Build Coastguard Worker     prev = n;
392*5c90c05cSAndroid Build Coastguard Worker     n = n * 10 + static_cast<unsigned>(c - '0');
393*5c90c05cSAndroid Build Coastguard Worker     prev_digit = c;
394*5c90c05cSAndroid Build Coastguard Worker     c = *++it;
395*5c90c05cSAndroid Build Coastguard Worker     ++num_digits;
396*5c90c05cSAndroid Build Coastguard Worker     if (c < '0' || c > '9') break;
397*5c90c05cSAndroid Build Coastguard Worker   } while (it != scan_sentinel());
398*5c90c05cSAndroid Build Coastguard Worker 
399*5c90c05cSAndroid Build Coastguard Worker   // Check overflow.
400*5c90c05cSAndroid Build Coastguard Worker   if (num_digits <= std::numeric_limits<int>::digits10) {
401*5c90c05cSAndroid Build Coastguard Worker     value = n;
402*5c90c05cSAndroid Build Coastguard Worker     return it;
403*5c90c05cSAndroid Build Coastguard Worker   }
404*5c90c05cSAndroid Build Coastguard Worker   unsigned max = to_unsigned((std::numeric_limits<int>::max)());
405*5c90c05cSAndroid Build Coastguard Worker   if (num_digits == std::numeric_limits<int>::digits10 + 1 &&
406*5c90c05cSAndroid Build Coastguard Worker       prev * 10ull + unsigned(prev_digit - '0') <= max) {
407*5c90c05cSAndroid Build Coastguard Worker     value = n;
408*5c90c05cSAndroid Build Coastguard Worker   } else {
409*5c90c05cSAndroid Build Coastguard Worker     report_error("number is too big");
410*5c90c05cSAndroid Build Coastguard Worker   }
411*5c90c05cSAndroid Build Coastguard Worker   return it;
412*5c90c05cSAndroid Build Coastguard Worker }
413*5c90c05cSAndroid Build Coastguard Worker 
414*5c90c05cSAndroid Build Coastguard Worker template <typename T, FMT_ENABLE_IF(std::is_unsigned<T>::value)>
415*5c90c05cSAndroid Build Coastguard Worker auto read_hex(scan_iterator it, T& value) -> scan_iterator {
416*5c90c05cSAndroid Build Coastguard Worker   if (it == scan_sentinel()) return it;
417*5c90c05cSAndroid Build Coastguard Worker   int digit = to_hex_digit(*it);
418*5c90c05cSAndroid Build Coastguard Worker   if (digit < 0) report_error("invalid input");
419*5c90c05cSAndroid Build Coastguard Worker 
420*5c90c05cSAndroid Build Coastguard Worker   int num_digits = 0;
421*5c90c05cSAndroid Build Coastguard Worker   T n = 0;
422*5c90c05cSAndroid Build Coastguard Worker   do {
423*5c90c05cSAndroid Build Coastguard Worker     n = (n << 4) + static_cast<unsigned>(digit);
424*5c90c05cSAndroid Build Coastguard Worker     ++num_digits;
425*5c90c05cSAndroid Build Coastguard Worker     digit = to_hex_digit(*++it);
426*5c90c05cSAndroid Build Coastguard Worker     if (digit < 0) break;
427*5c90c05cSAndroid Build Coastguard Worker   } while (it != scan_sentinel());
428*5c90c05cSAndroid Build Coastguard Worker 
429*5c90c05cSAndroid Build Coastguard Worker   // Check overflow.
430*5c90c05cSAndroid Build Coastguard Worker   if (num_digits <= (std::numeric_limits<T>::digits >> 2))
431*5c90c05cSAndroid Build Coastguard Worker     value = n;
432*5c90c05cSAndroid Build Coastguard Worker   else
433*5c90c05cSAndroid Build Coastguard Worker     report_error("number is too big");
434*5c90c05cSAndroid Build Coastguard Worker   return it;
435*5c90c05cSAndroid Build Coastguard Worker }
436*5c90c05cSAndroid Build Coastguard Worker 
437*5c90c05cSAndroid Build Coastguard Worker template <typename T, FMT_ENABLE_IF(std::is_unsigned<T>::value)>
438*5c90c05cSAndroid Build Coastguard Worker auto read(scan_iterator it, T& value, const format_specs& specs)
439*5c90c05cSAndroid Build Coastguard Worker     -> scan_iterator {
440*5c90c05cSAndroid Build Coastguard Worker   if (specs.type() == presentation_type::hex) return read_hex(it, value);
441*5c90c05cSAndroid Build Coastguard Worker   return read(it, value);
442*5c90c05cSAndroid Build Coastguard Worker }
443*5c90c05cSAndroid Build Coastguard Worker 
444*5c90c05cSAndroid Build Coastguard Worker template <typename T, FMT_ENABLE_IF(std::is_signed<T>::value)>
445*5c90c05cSAndroid Build Coastguard Worker auto read(scan_iterator it, T& value, const format_specs& specs = {})
446*5c90c05cSAndroid Build Coastguard Worker     -> scan_iterator {
447*5c90c05cSAndroid Build Coastguard Worker   bool negative = it != scan_sentinel() && *it == '-';
448*5c90c05cSAndroid Build Coastguard Worker   if (negative) {
449*5c90c05cSAndroid Build Coastguard Worker     ++it;
450*5c90c05cSAndroid Build Coastguard Worker     if (it == scan_sentinel()) report_error("invalid input");
451*5c90c05cSAndroid Build Coastguard Worker   }
452*5c90c05cSAndroid Build Coastguard Worker   using unsigned_type = typename std::make_unsigned<T>::type;
453*5c90c05cSAndroid Build Coastguard Worker   unsigned_type abs_value = 0;
454*5c90c05cSAndroid Build Coastguard Worker   it = read(it, abs_value, specs);
455*5c90c05cSAndroid Build Coastguard Worker   auto n = static_cast<T>(abs_value);
456*5c90c05cSAndroid Build Coastguard Worker   value = negative ? -n : n;
457*5c90c05cSAndroid Build Coastguard Worker   return it;
458*5c90c05cSAndroid Build Coastguard Worker }
459*5c90c05cSAndroid Build Coastguard Worker 
460*5c90c05cSAndroid Build Coastguard Worker auto read(scan_iterator it, std::string& value, const format_specs& = {})
461*5c90c05cSAndroid Build Coastguard Worker     -> scan_iterator {
462*5c90c05cSAndroid Build Coastguard Worker   while (it != scan_sentinel() && *it != ' ') value.push_back(*it++);
463*5c90c05cSAndroid Build Coastguard Worker   return it;
464*5c90c05cSAndroid Build Coastguard Worker }
465*5c90c05cSAndroid Build Coastguard Worker 
466*5c90c05cSAndroid Build Coastguard Worker auto read(scan_iterator it, string_view& value, const format_specs& = {})
467*5c90c05cSAndroid Build Coastguard Worker     -> scan_iterator {
468*5c90c05cSAndroid Build Coastguard Worker   auto range = to_contiguous(it);
469*5c90c05cSAndroid Build Coastguard Worker   // This could also be checked at compile time in scan.
470*5c90c05cSAndroid Build Coastguard Worker   if (!range) report_error("string_view requires contiguous input");
471*5c90c05cSAndroid Build Coastguard Worker   auto p = range.begin;
472*5c90c05cSAndroid Build Coastguard Worker   while (p != range.end && *p != ' ') ++p;
473*5c90c05cSAndroid Build Coastguard Worker   size_t size = to_unsigned(p - range.begin);
474*5c90c05cSAndroid Build Coastguard Worker   value = {range.begin, size};
475*5c90c05cSAndroid Build Coastguard Worker   return advance(it, size);
476*5c90c05cSAndroid Build Coastguard Worker }
477*5c90c05cSAndroid Build Coastguard Worker 
478*5c90c05cSAndroid Build Coastguard Worker auto read(scan_iterator it, monostate, const format_specs& = {})
479*5c90c05cSAndroid Build Coastguard Worker     -> scan_iterator {
480*5c90c05cSAndroid Build Coastguard Worker   return it;
481*5c90c05cSAndroid Build Coastguard Worker }
482*5c90c05cSAndroid Build Coastguard Worker 
483*5c90c05cSAndroid Build Coastguard Worker // An argument scanner that uses the default format, e.g. decimal for integers.
484*5c90c05cSAndroid Build Coastguard Worker struct default_arg_scanner {
485*5c90c05cSAndroid Build Coastguard Worker   scan_iterator it;
486*5c90c05cSAndroid Build Coastguard Worker 
487*5c90c05cSAndroid Build Coastguard Worker   template <typename T> FMT_INLINE auto operator()(T&& value) -> scan_iterator {
488*5c90c05cSAndroid Build Coastguard Worker     return read(it, value);
489*5c90c05cSAndroid Build Coastguard Worker   }
490*5c90c05cSAndroid Build Coastguard Worker };
491*5c90c05cSAndroid Build Coastguard Worker 
492*5c90c05cSAndroid Build Coastguard Worker // An argument scanner with format specifiers.
493*5c90c05cSAndroid Build Coastguard Worker struct arg_scanner {
494*5c90c05cSAndroid Build Coastguard Worker   scan_iterator it;
495*5c90c05cSAndroid Build Coastguard Worker   const format_specs& specs;
496*5c90c05cSAndroid Build Coastguard Worker 
497*5c90c05cSAndroid Build Coastguard Worker   template <typename T> auto operator()(T&& value) -> scan_iterator {
498*5c90c05cSAndroid Build Coastguard Worker     return read(it, value, specs);
499*5c90c05cSAndroid Build Coastguard Worker   }
500*5c90c05cSAndroid Build Coastguard Worker };
501*5c90c05cSAndroid Build Coastguard Worker 
502*5c90c05cSAndroid Build Coastguard Worker struct scan_handler {
503*5c90c05cSAndroid Build Coastguard Worker  private:
504*5c90c05cSAndroid Build Coastguard Worker   scan_parse_context parse_ctx_;
505*5c90c05cSAndroid Build Coastguard Worker   scan_context scan_ctx_;
506*5c90c05cSAndroid Build Coastguard Worker   int next_arg_id_;
507*5c90c05cSAndroid Build Coastguard Worker 
508*5c90c05cSAndroid Build Coastguard Worker   using sentinel = scan_buffer::sentinel;
509*5c90c05cSAndroid Build Coastguard Worker 
510*5c90c05cSAndroid Build Coastguard Worker  public:
scan_handlerscan_handler511*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR scan_handler(string_view format, scan_buffer& buf,
512*5c90c05cSAndroid Build Coastguard Worker                              scan_args args)
513*5c90c05cSAndroid Build Coastguard Worker       : parse_ctx_(format), scan_ctx_(buf, args), next_arg_id_(0) {}
514*5c90c05cSAndroid Build Coastguard Worker 
515*5c90c05cSAndroid Build Coastguard Worker   auto pos() const -> scan_buffer::iterator { return scan_ctx_.begin(); }
516*5c90c05cSAndroid Build Coastguard Worker 
on_textscan_handler517*5c90c05cSAndroid Build Coastguard Worker   void on_text(const char* begin, const char* end) {
518*5c90c05cSAndroid Build Coastguard Worker     if (begin == end) return;
519*5c90c05cSAndroid Build Coastguard Worker     auto it = scan_ctx_.begin();
520*5c90c05cSAndroid Build Coastguard Worker     for (; begin != end; ++begin, ++it) {
521*5c90c05cSAndroid Build Coastguard Worker       if (it == sentinel() || *begin != *it) on_error("invalid input");
522*5c90c05cSAndroid Build Coastguard Worker     }
523*5c90c05cSAndroid Build Coastguard Worker     scan_ctx_.advance_to(it);
524*5c90c05cSAndroid Build Coastguard Worker   }
525*5c90c05cSAndroid Build Coastguard Worker 
526*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR auto on_arg_id() -> int { return on_arg_id(next_arg_id_++); }
527*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR auto on_arg_id(int id) -> int {
528*5c90c05cSAndroid Build Coastguard Worker     if (!scan_ctx_.arg(id)) on_error("argument index out of range");
529*5c90c05cSAndroid Build Coastguard Worker     return id;
530*5c90c05cSAndroid Build Coastguard Worker   }
531*5c90c05cSAndroid Build Coastguard Worker   FMT_CONSTEXPR auto on_arg_id(string_view id) -> int {
532*5c90c05cSAndroid Build Coastguard Worker     if (id.data()) on_error("invalid format");
533*5c90c05cSAndroid Build Coastguard Worker     return 0;
534*5c90c05cSAndroid Build Coastguard Worker   }
535*5c90c05cSAndroid Build Coastguard Worker 
on_replacement_fieldscan_handler536*5c90c05cSAndroid Build Coastguard Worker   void on_replacement_field(int arg_id, const char* begin) {
537*5c90c05cSAndroid Build Coastguard Worker     scan_arg arg = scan_ctx_.arg(arg_id);
538*5c90c05cSAndroid Build Coastguard Worker     if (arg.scan_custom(begin, parse_ctx_, scan_ctx_)) return;
539*5c90c05cSAndroid Build Coastguard Worker     auto it = scan_ctx_.begin();
540*5c90c05cSAndroid Build Coastguard Worker     while (it != sentinel() && is_whitespace(*it)) ++it;
541*5c90c05cSAndroid Build Coastguard Worker     scan_ctx_.advance_to(arg.visit(default_arg_scanner{it}));
542*5c90c05cSAndroid Build Coastguard Worker   }
543*5c90c05cSAndroid Build Coastguard Worker 
544*5c90c05cSAndroid Build Coastguard Worker   auto on_format_specs(int arg_id, const char* begin, const char* end) -> const
545*5c90c05cSAndroid Build Coastguard Worker       char* {
546*5c90c05cSAndroid Build Coastguard Worker     scan_arg arg = scan_ctx_.arg(arg_id);
547*5c90c05cSAndroid Build Coastguard Worker     if (arg.scan_custom(begin, parse_ctx_, scan_ctx_))
548*5c90c05cSAndroid Build Coastguard Worker       return parse_ctx_.begin();
549*5c90c05cSAndroid Build Coastguard Worker     auto specs = format_specs();
550*5c90c05cSAndroid Build Coastguard Worker     begin = parse_scan_specs(begin, end, specs, arg.type());
551*5c90c05cSAndroid Build Coastguard Worker     if (begin == end || *begin != '}') on_error("missing '}' in format string");
552*5c90c05cSAndroid Build Coastguard Worker     scan_ctx_.advance_to(arg.visit(arg_scanner{scan_ctx_.begin(), specs}));
553*5c90c05cSAndroid Build Coastguard Worker     return begin;
554*5c90c05cSAndroid Build Coastguard Worker   }
555*5c90c05cSAndroid Build Coastguard Worker 
on_errorscan_handler556*5c90c05cSAndroid Build Coastguard Worker   FMT_NORETURN void on_error(const char* message) { report_error(message); }
557*5c90c05cSAndroid Build Coastguard Worker };
558*5c90c05cSAndroid Build Coastguard Worker 
vscan(detail::scan_buffer & buf,string_view fmt,scan_args args)559*5c90c05cSAndroid Build Coastguard Worker void vscan(detail::scan_buffer& buf, string_view fmt, scan_args args) {
560*5c90c05cSAndroid Build Coastguard Worker   auto h = detail::scan_handler(fmt, buf, args);
561*5c90c05cSAndroid Build Coastguard Worker   detail::parse_format_string(fmt, h);
562*5c90c05cSAndroid Build Coastguard Worker }
563*5c90c05cSAndroid Build Coastguard Worker 
564*5c90c05cSAndroid Build Coastguard Worker template <size_t I, typename... T, FMT_ENABLE_IF(I == sizeof...(T))>
make_args(std::array<scan_arg,sizeof...(T)> &,std::tuple<T...> &)565*5c90c05cSAndroid Build Coastguard Worker void make_args(std::array<scan_arg, sizeof...(T)>&, std::tuple<T...>&) {}
566*5c90c05cSAndroid Build Coastguard Worker 
567*5c90c05cSAndroid Build Coastguard Worker template <size_t I, typename... T, FMT_ENABLE_IF(I < sizeof...(T))>
make_args(std::array<scan_arg,sizeof...(T)> & args,std::tuple<T...> & values)568*5c90c05cSAndroid Build Coastguard Worker void make_args(std::array<scan_arg, sizeof...(T)>& args,
569*5c90c05cSAndroid Build Coastguard Worker                std::tuple<T...>& values) {
570*5c90c05cSAndroid Build Coastguard Worker   using element_type = typename std::tuple_element<I, std::tuple<T...>>::type;
571*5c90c05cSAndroid Build Coastguard Worker   static_assert(std::is_same<remove_cvref_t<element_type>, element_type>::value,
572*5c90c05cSAndroid Build Coastguard Worker                 "");
573*5c90c05cSAndroid Build Coastguard Worker   args[I] = std::get<I>(values);
574*5c90c05cSAndroid Build Coastguard Worker   make_args<I + 1>(args, values);
575*5c90c05cSAndroid Build Coastguard Worker }
576*5c90c05cSAndroid Build Coastguard Worker }  // namespace detail
577*5c90c05cSAndroid Build Coastguard Worker 
578*5c90c05cSAndroid Build Coastguard Worker template <typename Range, typename... T> class scan_data {
579*5c90c05cSAndroid Build Coastguard Worker  private:
580*5c90c05cSAndroid Build Coastguard Worker   std::tuple<T...> values_;
581*5c90c05cSAndroid Build Coastguard Worker   Range range_;
582*5c90c05cSAndroid Build Coastguard Worker 
583*5c90c05cSAndroid Build Coastguard Worker  public:
584*5c90c05cSAndroid Build Coastguard Worker   scan_data() = default;
scan_data(T...values)585*5c90c05cSAndroid Build Coastguard Worker   scan_data(T... values) : values_(std::move(values)...) {}
586*5c90c05cSAndroid Build Coastguard Worker 
587*5c90c05cSAndroid Build Coastguard Worker   auto value() const -> decltype(std::get<0>(values_)) {
588*5c90c05cSAndroid Build Coastguard Worker     return std::get<0>(values_);
589*5c90c05cSAndroid Build Coastguard Worker   }
590*5c90c05cSAndroid Build Coastguard Worker 
591*5c90c05cSAndroid Build Coastguard Worker   auto values() const -> const std::tuple<T...>& { return values_; }
592*5c90c05cSAndroid Build Coastguard Worker 
593*5c90c05cSAndroid Build Coastguard Worker   auto make_args() -> std::array<scan_arg, sizeof...(T)> {
594*5c90c05cSAndroid Build Coastguard Worker     auto args = std::array<scan_arg, sizeof...(T)>();
595*5c90c05cSAndroid Build Coastguard Worker     detail::make_args<0>(args, values_);
596*5c90c05cSAndroid Build Coastguard Worker     return args;
597*5c90c05cSAndroid Build Coastguard Worker   }
598*5c90c05cSAndroid Build Coastguard Worker 
599*5c90c05cSAndroid Build Coastguard Worker   auto range() const -> Range { return range_; }
600*5c90c05cSAndroid Build Coastguard Worker 
601*5c90c05cSAndroid Build Coastguard Worker   auto begin() const -> decltype(range_.begin()) { return range_.begin(); }
602*5c90c05cSAndroid Build Coastguard Worker   auto end() const -> decltype(range_.end()) { return range_.end(); }
603*5c90c05cSAndroid Build Coastguard Worker };
604*5c90c05cSAndroid Build Coastguard Worker 
605*5c90c05cSAndroid Build Coastguard Worker template <typename... T>
606*5c90c05cSAndroid Build Coastguard Worker auto make_scan_args(T&... args) -> std::array<scan_arg, sizeof...(T)> {
607*5c90c05cSAndroid Build Coastguard Worker   return {{args...}};
608*5c90c05cSAndroid Build Coastguard Worker }
609*5c90c05cSAndroid Build Coastguard Worker 
610*5c90c05cSAndroid Build Coastguard Worker class scan_error {};
611*5c90c05cSAndroid Build Coastguard Worker 
612*5c90c05cSAndroid Build Coastguard Worker // A rudimentary version of std::expected for testing the API shape.
613*5c90c05cSAndroid Build Coastguard Worker template <typename T, typename E> class expected {
614*5c90c05cSAndroid Build Coastguard Worker  private:
615*5c90c05cSAndroid Build Coastguard Worker   T value_;
616*5c90c05cSAndroid Build Coastguard Worker   bool has_value_ = true;
617*5c90c05cSAndroid Build Coastguard Worker 
618*5c90c05cSAndroid Build Coastguard Worker  public:
expected(T value)619*5c90c05cSAndroid Build Coastguard Worker   expected(T value) : value_(std::move(value)) {}
620*5c90c05cSAndroid Build Coastguard Worker 
621*5c90c05cSAndroid Build Coastguard Worker   explicit operator bool() const { return has_value_; }
622*5c90c05cSAndroid Build Coastguard Worker 
623*5c90c05cSAndroid Build Coastguard Worker   auto operator->() const -> const T* { return &value_; }
624*5c90c05cSAndroid Build Coastguard Worker 
625*5c90c05cSAndroid Build Coastguard Worker   auto error() -> E const { return E(); }
626*5c90c05cSAndroid Build Coastguard Worker };
627*5c90c05cSAndroid Build Coastguard Worker 
628*5c90c05cSAndroid Build Coastguard Worker template <typename Range, typename... T>
629*5c90c05cSAndroid Build Coastguard Worker using scan_result = expected<scan_data<Range, T...>, scan_error>;
630*5c90c05cSAndroid Build Coastguard Worker 
631*5c90c05cSAndroid Build Coastguard Worker auto vscan(string_view input, string_view fmt, scan_args args)
632*5c90c05cSAndroid Build Coastguard Worker     -> string_view::iterator {
633*5c90c05cSAndroid Build Coastguard Worker   auto&& buf = detail::string_scan_buffer(input);
634*5c90c05cSAndroid Build Coastguard Worker   detail::vscan(buf, fmt, args);
635*5c90c05cSAndroid Build Coastguard Worker   return input.begin() + (buf.begin().base() - input.data());
636*5c90c05cSAndroid Build Coastguard Worker }
637*5c90c05cSAndroid Build Coastguard Worker 
638*5c90c05cSAndroid Build Coastguard Worker // Scans the input and stores the results (in)to args.
639*5c90c05cSAndroid Build Coastguard Worker template <typename... T>
640*5c90c05cSAndroid Build Coastguard Worker auto scan_to(string_view input, string_view fmt, T&... args)
641*5c90c05cSAndroid Build Coastguard Worker     -> string_view::iterator {
642*5c90c05cSAndroid Build Coastguard Worker   return vscan(input, fmt, make_scan_args(args...));
643*5c90c05cSAndroid Build Coastguard Worker }
644*5c90c05cSAndroid Build Coastguard Worker 
645*5c90c05cSAndroid Build Coastguard Worker template <typename... T>
646*5c90c05cSAndroid Build Coastguard Worker auto scan(string_view input, string_view fmt)
647*5c90c05cSAndroid Build Coastguard Worker     -> scan_result<string_view, T...> {
648*5c90c05cSAndroid Build Coastguard Worker   auto data = scan_data<string_view, T...>();
649*5c90c05cSAndroid Build Coastguard Worker   vscan(input, fmt, data.make_args());
650*5c90c05cSAndroid Build Coastguard Worker   return data;
651*5c90c05cSAndroid Build Coastguard Worker }
652*5c90c05cSAndroid Build Coastguard Worker 
653*5c90c05cSAndroid Build Coastguard Worker template <typename Range, typename... T,
654*5c90c05cSAndroid Build Coastguard Worker           FMT_ENABLE_IF(!std::is_convertible<Range, string_view>::value)>
655*5c90c05cSAndroid Build Coastguard Worker auto scan_to(Range&& input, string_view fmt, T&... args)
656*5c90c05cSAndroid Build Coastguard Worker     -> decltype(std::begin(input)) {
657*5c90c05cSAndroid Build Coastguard Worker   auto it = std::begin(input);
658*5c90c05cSAndroid Build Coastguard Worker   detail::vscan(get_buffer(it), fmt, make_scan_args(args...));
659*5c90c05cSAndroid Build Coastguard Worker   return it;
660*5c90c05cSAndroid Build Coastguard Worker }
661*5c90c05cSAndroid Build Coastguard Worker 
662*5c90c05cSAndroid Build Coastguard Worker template <typename... T>
663*5c90c05cSAndroid Build Coastguard Worker auto scan_to(FILE* f, string_view fmt, T&... args) -> bool {
664*5c90c05cSAndroid Build Coastguard Worker   auto&& buf = detail::file_scan_buffer(f);
665*5c90c05cSAndroid Build Coastguard Worker   detail::vscan(buf, fmt, make_scan_args(args...));
666*5c90c05cSAndroid Build Coastguard Worker   return buf.begin() != buf.end();
667*5c90c05cSAndroid Build Coastguard Worker }
668*5c90c05cSAndroid Build Coastguard Worker 
669*5c90c05cSAndroid Build Coastguard Worker FMT_END_NAMESPACE
670