13 #include "fmt/format-inl.h" 18 inline auto is_whitespace(
char c) ->
bool {
return c ==
' ' || c ==
'\n'; }
21 inline auto to_hex_digit(
char c) ->
int {
22 if (c >=
'0' && c <=
'9')
return c -
'0';
23 if (c >=
'a' && c <=
'f')
return c -
'a' + 10;
24 if (c >=
'A' && c <=
'F')
return c -
'A' + 10;
28 struct maybe_contiguous_range {
32 explicit operator bool()
const {
return begin !=
nullptr; }
42 scan_buffer(
const char* ptr,
const char* end,
bool contiguous)
43 : ptr_(ptr), end_(end), contiguous_(contiguous) {}
44 ~scan_buffer() =
default;
46 void set(span<const char> buf) {
48 end_ = buf.data + buf.size;
51 auto ptr() const -> const
char* {
return ptr_; }
54 scan_buffer(
const scan_buffer&) =
delete;
55 void operator=(
const scan_buffer&) =
delete;
58 virtual void consume() = 0;
68 static auto get_sentinel() ->
const char** {
69 static const char* ptr =
nullptr;
73 friend class scan_buffer;
75 friend auto operator==(iterator lhs, sentinel) ->
bool {
76 return *lhs.ptr_ ==
nullptr;
78 friend auto operator!=(iterator lhs, sentinel) ->
bool {
79 return *lhs.ptr_ !=
nullptr;
82 iterator(scan_buffer* buf) : buf_(buf) {
83 if (buf->ptr_ == buf->end_) {
84 ptr_ = get_sentinel();
91 friend scan_buffer& get_buffer(iterator it) {
return *it.buf_; }
94 iterator() : ptr_(get_sentinel()), buf_(nullptr) {}
96 auto operator++() -> iterator& {
97 if (!buf_->try_consume()) ptr_ = get_sentinel();
101 auto operator++(
int) -> iterator {
102 iterator copy = *
this;
106 auto operator*() const ->
char {
return value_; }
108 auto base() const -> const
char* {
return buf_->ptr_; }
110 friend auto to_contiguous(iterator it) -> maybe_contiguous_range;
111 friend auto advance(iterator it,
size_t n) -> iterator;
114 friend auto to_contiguous(iterator it) -> maybe_contiguous_range {
115 if (it.buf_->is_contiguous())
return {it.buf_->ptr_, it.buf_->end_};
116 return {
nullptr,
nullptr};
118 friend auto advance(iterator it,
size_t n) -> iterator {
119 FMT_ASSERT(it.buf_->is_contiguous(),
"");
120 const char*& ptr = it.buf_->ptr_;
123 if (ptr == it.buf_->end_) it.ptr_ = iterator::get_sentinel();
127 auto begin() -> iterator {
return this; }
128 auto end() -> sentinel {
return {}; }
130 auto is_contiguous() const ->
bool {
return contiguous_; }
133 auto try_consume() ->
bool {
134 FMT_ASSERT(ptr_ != end_,
"");
136 if (ptr_ != end_)
return true;
142 using scan_iterator = scan_buffer::iterator;
143 using scan_sentinel = scan_buffer::sentinel;
145 class string_scan_buffer final :
public scan_buffer {
147 void consume()
override {}
151 : scan_buffer(s.begin(), s.end(), true) {}
154 class file_scan_buffer final :
public scan_buffer {
156 template <
typename F, FMT_ENABLE_IF(
sizeof(F::_IO_read_ptr) != 0 &&
157 !FMT_USE_FALLBACK_FILE)>
158 static auto get_file(F* f,
int) -> glibc_file<F> {
161 template <
typename F,
162 FMT_ENABLE_IF(
sizeof(F::_p) != 0 && !FMT_USE_FALLBACK_FILE)>
163 static auto get_file(F* f,
int) -> apple_file<F> {
166 static auto get_file(FILE* f, ...) -> fallback_file<FILE> {
return f; }
168 decltype(get_file(static_cast<FILE*>(
nullptr), 0)) file_;
172 span<const char> buf = file_.get_read_buffer();
176 if (c != EOF) file_.unget(static_cast<char>(c));
177 buf = file_.get_read_buffer();
182 void consume()
override {
184 size_t n = to_unsigned(ptr() - file_.get_read_buffer().data);
185 for (
size_t i = 0; i != n; ++i) file_.get();
190 explicit file_scan_buffer(FILE* f)
191 : scan_buffer(nullptr, nullptr, false), file_(f) {
195 ~file_scan_buffer() {
202 template <
typename T,
typename Char =
char>
struct scanner {
207 class scan_parse_context {
212 using iterator = string_view::iterator;
214 FMT_CONSTEXPR
explicit scan_parse_context(
string_view format)
217 FMT_CONSTEXPR
auto begin() const -> iterator {
return format_.begin(); }
218 FMT_CONSTEXPR
auto end() const -> iterator {
return format_.end(); }
220 void advance_to(iterator it) {
221 format_.remove_prefix(detail::to_unsigned(it - begin()));
226 enum class scan_type {
239 template <
typename Context>
struct custom_scan_arg {
241 void (*scan)(
void* arg, scan_parse_context& parse_ctx, Context& ctx);
247 template <
typename Context>
class basic_scan_arg {
249 using scan_type = detail::scan_type;
253 unsigned* uint_value_;
254 long long* long_long_value_;
255 unsigned long long* ulong_long_value_;
256 double* double_value_;
258 std::string* string_;
260 detail::custom_scan_arg<Context> custom_;
264 template <
typename T>
265 static void scan_custom_arg(
void* arg, scan_parse_context& parse_ctx,
267 auto s = scanner<T>();
268 parse_ctx.advance_to(s.parse(parse_ctx));
269 ctx.advance_to(s.scan(*static_cast<T*>(arg), ctx));
273 FMT_CONSTEXPR basic_scan_arg()
274 : type_(scan_type::none_type), int_value_(nullptr) {}
275 FMT_CONSTEXPR basic_scan_arg(
int& value)
276 : type_(scan_type::int_type), int_value_(&value) {}
277 FMT_CONSTEXPR basic_scan_arg(
unsigned& value)
278 : type_(scan_type::uint_type), uint_value_(&value) {}
279 FMT_CONSTEXPR basic_scan_arg(
long long& value)
280 : type_(scan_type::long_long_type), long_long_value_(&value) {}
281 FMT_CONSTEXPR basic_scan_arg(
unsigned long long& value)
282 : type_(scan_type::ulong_long_type), ulong_long_value_(&value) {}
283 FMT_CONSTEXPR basic_scan_arg(
double& value)
284 : type_(scan_type::double_type), double_value_(&value) {}
285 FMT_CONSTEXPR basic_scan_arg(
float& value)
286 : type_(scan_type::float_type), float_value_(&value) {}
287 FMT_CONSTEXPR basic_scan_arg(std::string& value)
288 : type_(scan_type::string_type), string_(&value) {}
290 : type_(scan_type::string_view_type), string_view_(&value) {}
291 template <
typename T>
292 FMT_CONSTEXPR basic_scan_arg(T& value) : type_(scan_type::custom_type) {
293 custom_.value = &value;
294 custom_.scan = scan_custom_arg<T>;
297 constexpr
explicit operator bool() const noexcept {
298 return type_ != scan_type::none_type;
301 auto type() const ->
detail::scan_type {
return type_; }
303 template <
typename Visitor>
304 auto visit(Visitor&& vis) -> decltype(vis(monostate())) {
306 case scan_type::none_type:
308 case scan_type::int_type:
309 return vis(*int_value_);
310 case scan_type::uint_type:
311 return vis(*uint_value_);
312 case scan_type::long_long_type:
313 return vis(*long_long_value_);
314 case scan_type::ulong_long_type:
315 return vis(*ulong_long_value_);
316 case scan_type::double_type:
317 return vis(*double_value_);
318 case scan_type::float_type:
319 return vis(*float_value_);
320 case scan_type::string_type:
321 return vis(*string_);
322 case scan_type::string_view_type:
323 return vis(*string_view_);
324 case scan_type::custom_type:
327 return vis(monostate());
330 auto scan_custom(
const char* parse_begin, scan_parse_context& parse_ctx,
331 Context& ctx)
const ->
bool {
332 if (type_ != scan_type::custom_type)
return false;
333 parse_ctx.advance_to(parse_begin);
334 custom_.scan(custom_.value, parse_ctx, ctx);
340 using scan_arg = basic_scan_arg<scan_context>;
344 const scan_arg* data;
347 FMT_CONSTEXPR scan_args(
const std::array<scan_arg, N>& store)
348 : size(N), data(store.data()) {
349 static_assert(N < INT_MAX,
"too many arguments");
355 detail::scan_buffer& buf_;
359 using iterator = detail::scan_iterator;
360 using sentinel = detail::scan_sentinel;
362 FMT_CONSTEXPR
explicit scan_context(detail::scan_buffer& buf, scan_args args)
363 : buf_(buf), args_(args) {}
365 FMT_CONSTEXPR
auto arg(
int id)
const -> scan_arg {
366 return id < args_.size ? args_.data[id] : scan_arg();
369 auto begin() const -> iterator {
return buf_.begin(); }
370 auto end() const -> sentinel {
return {}; }
372 void advance_to(iterator) { buf_.consume(); }
377 const char* parse_scan_specs(
const char* begin,
const char* end,
378 format_specs& specs, scan_type) {
379 while (begin != end) {
380 switch (to_ascii(*begin)) {
383 specs.set_type(presentation_type::hex);
393 template <typename T, FMT_ENABLE_IF(std::is_unsigned<T>::value)>
394 auto read(scan_iterator it, T& value) -> scan_iterator {
395 if (it == scan_sentinel())
return it;
397 if (c < '0' || c >
'9') report_error(
"invalid input");
404 n = n * 10 +
static_cast<unsigned>(c -
'0');
408 if (c < '0' || c >
'9')
break;
409 }
while (it != scan_sentinel());
412 if (num_digits <= std::numeric_limits<int>::digits10) {
416 unsigned max = to_unsigned((std::numeric_limits<int>::max)());
417 if (num_digits == std::numeric_limits<int>::digits10 + 1 &&
418 prev * 10ull +
unsigned(prev_digit -
'0') <= max) {
421 report_error(
"number is too big");
426 template <typename T, FMT_ENABLE_IF(std::is_unsigned<T>::value)>
427 auto read_hex(scan_iterator it, T& value) -> scan_iterator {
428 if (it == scan_sentinel())
return it;
429 int digit = to_hex_digit(*it);
430 if (digit < 0) report_error(
"invalid input");
435 n = (n << 4) + static_cast<unsigned>(digit);
437 digit = to_hex_digit(*++it);
438 if (digit < 0)
break;
439 }
while (it != scan_sentinel());
442 if (num_digits <= (std::numeric_limits<T>::digits >> 2))
445 report_error(
"number is too big");
449 template <typename T, FMT_ENABLE_IF(std::is_unsigned<T>::value)>
450 auto read(scan_iterator it, T& value,
const format_specs& specs)
452 if (specs.type() == presentation_type::hex)
return read_hex(it, value);
453 return read(it, value);
456 template <typename T, FMT_ENABLE_IF(std::is_signed<T>::value)>
457 auto read(scan_iterator it, T& value,
const format_specs& specs = {})
459 bool negative = it != scan_sentinel() && *it ==
'-';
462 if (it == scan_sentinel()) report_error(
"invalid input");
464 using unsigned_type =
typename std::make_unsigned<T>::type;
465 unsigned_type abs_value = 0;
466 it = read(it, abs_value, specs);
467 auto n =
static_cast<T
>(abs_value);
468 value = negative ? -n : n;
472 auto read(scan_iterator it,
double& value,
const format_specs& = {})
474 if (it == scan_sentinel())
return it;
477 bool negative = *it ==
'-';
480 if (it == scan_sentinel()) report_error(
"invalid input");
485 while (it != scan_sentinel() && *it >=
'0' && *it <=
'9') {
486 result = result * 10.0 + (*it -
'0');
491 if (it != scan_sentinel() && *it ==
'.') {
493 double fraction = 0.1;
494 while (it != scan_sentinel() && *it >=
'0' && *it <=
'9') {
495 result += (*it -
'0') * fraction;
501 value = negative ? -result : result;
505 auto read(scan_iterator it,
float& value,
const format_specs& specs = {})
508 it = read(it, temp, specs);
509 value =
static_cast<float>(temp);
513 auto read(scan_iterator it, std::string& value,
const format_specs& = {})
515 while (it != scan_sentinel() && *it !=
' ') value.push_back(*it++);
519 auto read(scan_iterator it,
string_view& value,
const format_specs& = {})
521 auto range = to_contiguous(it);
523 if (!range) report_error(
"string_view requires contiguous input");
524 auto p = range.begin;
525 while (p != range.end && *p !=
' ') ++p;
526 size_t size = to_unsigned(p - range.begin);
527 value = {range.begin, size};
528 return advance(it, size);
531 auto read(scan_iterator it, monostate,
const format_specs& = {})
537 struct default_arg_scanner {
540 template <
typename T> FMT_INLINE
auto operator()(T&& value) -> scan_iterator {
541 return read(it, value);
548 const format_specs& specs;
550 template <
typename T>
auto operator()(T&& value) -> scan_iterator {
551 return read(it, value, specs);
555 struct scan_handler {
557 scan_parse_context parse_ctx_;
558 scan_context scan_ctx_;
561 using sentinel = scan_buffer::sentinel;
564 FMT_CONSTEXPR scan_handler(
string_view format, scan_buffer& buf,
566 : parse_ctx_(format), scan_ctx_(buf, args), next_arg_id_(0) {}
568 auto pos() const -> scan_buffer::iterator {
return scan_ctx_.begin(); }
570 void on_text(
const char* begin,
const char* end) {
571 if (begin == end)
return;
572 auto it = scan_ctx_.begin();
573 for (; begin != end; ++begin, ++it) {
574 if (it == sentinel() || *begin != *it) on_error(
"invalid input");
576 scan_ctx_.advance_to(it);
579 FMT_CONSTEXPR
auto on_arg_id() ->
int {
return on_arg_id(next_arg_id_++); }
580 FMT_CONSTEXPR
auto on_arg_id(
int id) ->
int {
581 if (!scan_ctx_.arg(
id)) on_error(
"argument index out of range");
584 FMT_CONSTEXPR
auto on_arg_id(
string_view id) ->
int {
585 if (
id.data()) on_error(
"invalid format");
589 void on_replacement_field(
int arg_id,
const char* begin) {
590 scan_arg arg = scan_ctx_.arg(arg_id);
591 if (arg.scan_custom(begin, parse_ctx_, scan_ctx_))
return;
592 auto it = scan_ctx_.begin();
593 while (it != sentinel() && is_whitespace(*it)) ++it;
594 scan_ctx_.advance_to(arg.visit(default_arg_scanner{it}));
597 auto on_format_specs(
int arg_id,
const char* begin,
const char* end) ->
const 599 scan_arg arg = scan_ctx_.arg(arg_id);
600 if (arg.scan_custom(begin, parse_ctx_, scan_ctx_))
601 return parse_ctx_.begin();
602 auto specs = format_specs();
603 begin = parse_scan_specs(begin, end, specs, arg.type());
604 if (begin == end || *begin !=
'}') on_error(
"missing '}' in format string");
605 scan_ctx_.advance_to(arg.visit(arg_scanner{scan_ctx_.begin(), specs}));
609 FMT_NORETURN
void on_error(
const char* message) { report_error(message); }
612 void vscan(detail::scan_buffer& buf,
string_view fmt, scan_args args) {
613 auto h = detail::scan_handler(fmt, buf, args);
614 detail::parse_format_string(fmt, h);
617 template <
size_t I,
typename... T, FMT_ENABLE_IF(I ==
sizeof...(T))>
618 void make_args(std::array<scan_arg,
sizeof...(T)>&, std::tuple<T...>&) {}
620 template <
size_t I,
typename... T, FMT_ENABLE_IF(I <
sizeof...(T))>
621 void make_args(std::array<scan_arg,
sizeof...(T)>& args,
622 std::tuple<T...>& values) {
623 using element_type =
typename std::tuple_element<I, std::tuple<T...>>::type;
624 static_assert(std::is_same<remove_cvref_t<element_type>, element_type>::value,
626 args[I] = std::get<I>(values);
627 make_args<I + 1>(args, values);
631 template <
typename Range,
typename... T>
class scan_data {
633 std::tuple<T...> values_;
637 scan_data() =
default;
638 scan_data(T... values) : values_(
std::move(values)...) {}
640 auto value() const -> decltype(
std::
get<0>(values_)) {
641 return std::get<0>(values_);
644 auto values() const -> const
std::tuple<T...>& {
return values_; }
646 auto make_args() -> std::array<scan_arg,
sizeof...(T)> {
647 auto args = std::array<scan_arg,
sizeof...(T)>();
648 detail::make_args<0>(args, values_);
652 auto range() const -> Range {
return range_; }
654 auto begin() const -> decltype(range_.begin()) {
return range_.begin(); }
655 auto end() const -> decltype(range_.end()) {
return range_.end(); }
658 template <
typename... T>
659 auto make_scan_args(T&... args) -> std::array<scan_arg,
sizeof...(T)> {
666 template <
typename T,
typename E>
class expected {
669 bool has_value_ =
true;
672 expected(T value) : value_(
std::move(value)) {}
674 explicit operator bool()
const {
return has_value_; }
676 auto operator->() const -> const T* {
return &value_; }
678 auto error() -> E
const {
return E(); }
681 template <
typename Range,
typename... T>
682 using scan_result = expected<scan_data<Range, T...>, scan_error>;
685 -> string_view::iterator {
686 auto&& buf = detail::string_scan_buffer(input);
687 detail::vscan(buf, fmt, args);
688 return input.begin() + (buf.begin().base() - input.data());
692 template <
typename... T>
694 -> string_view::iterator {
695 return vscan(input, fmt, make_scan_args(args...));
698 template <
typename... T>
701 auto data = scan_data<string_view, T...>();
702 vscan(input, fmt, data.make_args());
706 template <
typename Range,
typename... T,
707 FMT_ENABLE_IF(!std::is_convertible<Range, string_view>::value)>
708 auto scan_to(Range&& input, string_view fmt, T&... args)
709 -> decltype(std::begin(input)) {
710 auto it = std::begin(input);
711 detail::vscan(get_buffer(it), fmt, make_scan_args(args...));
715 template <
typename... T>
716 auto scan_to(FILE* f, string_view fmt, T&... args) ->
bool {
717 auto&& buf = detail::file_scan_buffer(f);
718 detail::vscan(buf, fmt, make_scan_args(args...));
719 return buf.begin() != buf.end();
Converts a string literal into a format string that will be parsed at compile time and converted into...
Definition: args.h:20
void error(const char *const s,...)
Print error with format string a la printf and throw exception.
Definition: error.cxx:42
const Array< num_dimensions - num_dimensions2, elemT > & get(const Array< num_dimensions, elemT > &a, const BasicCoordinate< num_dimensions2, int > &c)
an alternative for array indexing using BasicCoordinate objects
Definition: array_index_functions.inl:114