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