| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 | // Formatting library for C++ - scanning API proof of concept//// Copyright (c) 2019 - present, Victor Zverovich// All rights reserved.//// For the license information refer to format.h.#include <array>#include <cassert>#include <climits>#include "fmt/format.h"FMT_BEGIN_NAMESPACEtemplate <typename T, typename Char = char> struct scanner {  // A deleted default constructor indicates a disabled scanner.  scanner() = delete;};class scan_parse_context { private:  string_view format_; public:  using iterator = string_view::iterator;  explicit FMT_CONSTEXPR scan_parse_context(string_view format)      : format_(format) {}  FMT_CONSTEXPR iterator begin() const { return format_.begin(); }  FMT_CONSTEXPR iterator end() const { return format_.end(); }  void advance_to(iterator it) {    format_.remove_prefix(detail::to_unsigned(it - begin()));  }};struct scan_context { private:  string_view input_; public:  using iterator = const char*;  explicit scan_context(string_view input) : input_(input) {}  iterator begin() const { return input_.data(); }  iterator end() const { return begin() + input_.size(); }  void advance_to(iterator it) {    input_.remove_prefix(detail::to_unsigned(it - begin()));  }};namespace detail {enum class scan_type {  none_type,  int_type,  uint_type,  long_long_type,  ulong_long_type,  string_type,  string_view_type,  custom_type};struct custom_scan_arg {  void* value;  void (*scan)(void* arg, scan_parse_context& parse_ctx, scan_context& ctx);};class scan_arg { public:  scan_type type;  union {    int* int_value;    unsigned* uint_value;    long long* long_long_value;    unsigned long long* ulong_long_value;    std::string* string;    fmt::string_view* string_view;    custom_scan_arg custom;    // TODO: more types  };  scan_arg() : type(scan_type::none_type) {}  scan_arg(int& value) : type(scan_type::int_type), int_value(&value) {}  scan_arg(unsigned& value) : type(scan_type::uint_type), uint_value(&value) {}  scan_arg(long long& value)      : type(scan_type::long_long_type), long_long_value(&value) {}  scan_arg(unsigned long long& value)      : type(scan_type::ulong_long_type), ulong_long_value(&value) {}  scan_arg(std::string& value) : type(scan_type::string_type), string(&value) {}  scan_arg(fmt::string_view& value)      : type(scan_type::string_view_type), string_view(&value) {}  template <typename T> scan_arg(T& value) : type(scan_type::custom_type) {    custom.value = &value;    custom.scan = scan_custom_arg<T>;  } private:  template <typename T>  static void scan_custom_arg(void* arg, scan_parse_context& parse_ctx,                              scan_context& ctx) {    scanner<T> s;    parse_ctx.advance_to(s.parse(parse_ctx));    ctx.advance_to(s.scan(*static_cast<T*>(arg), ctx));  }};}  // namespace detailstruct scan_args {  int size;  const detail::scan_arg* data;  template <size_t N>  scan_args(const std::array<detail::scan_arg, N>& store)      : size(N), data(store.data()) {    static_assert(N < INT_MAX, "too many arguments");  }};namespace detail {struct scan_handler : error_handler { private:  scan_parse_context parse_ctx_;  scan_context scan_ctx_;  scan_args args_;  int next_arg_id_;  scan_arg arg_;  template <typename T = unsigned> T read_uint() {    T value = 0;    auto it = scan_ctx_.begin(), end = scan_ctx_.end();    while (it != end) {      char c = *it++;      if (c < '0' || c > '9') on_error("invalid input");      // TODO: check overflow      value = value * 10 + static_cast<unsigned>(c - '0');    }    scan_ctx_.advance_to(it);    return value;  }  template <typename T = int> T read_int() {    auto it = scan_ctx_.begin(), end = scan_ctx_.end();    bool negative = it != end && *it == '-';    if (negative) ++it;    scan_ctx_.advance_to(it);    const auto value = read_uint<typename std::make_unsigned<T>::type>();    if (negative) return -static_cast<T>(value);    return static_cast<T>(value);  } public:  scan_handler(string_view format, string_view input, scan_args args)      : parse_ctx_(format), scan_ctx_(input), args_(args), next_arg_id_(0) {}  const char* pos() const { return scan_ctx_.begin(); }  void on_text(const char* begin, const char* end) {    auto size = to_unsigned(end - begin);    auto it = scan_ctx_.begin();    if (it + size > scan_ctx_.end() ||        !std::equal(begin, end, make_checked(it, size))) {      on_error("invalid input");    }    scan_ctx_.advance_to(it + size);  }  FMT_CONSTEXPR int on_arg_id() { return on_arg_id(next_arg_id_++); }  FMT_CONSTEXPR int on_arg_id(int id) {    if (id >= args_.size) on_error("argument index out of range");    arg_ = args_.data[id];    return id;  }  FMT_CONSTEXPR int on_arg_id(string_view id) {    if (id.data()) on_error("invalid format");    return 0;  }  void on_replacement_field(int, const char*) {    auto it = scan_ctx_.begin(), end = scan_ctx_.end();    switch (arg_.type) {    case scan_type::int_type:      *arg_.int_value = read_int();      break;    case scan_type::uint_type:      *arg_.uint_value = read_uint();      break;    case scan_type::long_long_type:      *arg_.long_long_value = read_int<long long>();      break;    case scan_type::ulong_long_type:      *arg_.ulong_long_value = read_uint<unsigned long long>();      break;    case scan_type::string_type:      while (it != end && *it != ' ') arg_.string->push_back(*it++);      scan_ctx_.advance_to(it);      break;    case scan_type::string_view_type: {      auto s = it;      while (it != end && *it != ' ') ++it;      *arg_.string_view = fmt::string_view(s, to_unsigned(it - s));      scan_ctx_.advance_to(it);      break;    }    case scan_type::none_type:    case scan_type::custom_type:      assert(false);    }  }  const char* on_format_specs(int, const char* begin, const char*) {    if (arg_.type != scan_type::custom_type) return begin;    parse_ctx_.advance_to(begin);    arg_.custom.scan(arg_.custom.value, parse_ctx_, scan_ctx_);    return parse_ctx_.begin();  }};}  // namespace detailtemplate <typename... Args>std::array<detail::scan_arg, sizeof...(Args)> make_scan_args(Args&... args) {  return {{args...}};}string_view::iterator vscan(string_view input, string_view format_str,                            scan_args args) {  detail::scan_handler h(format_str, input, args);  detail::parse_format_string<false>(format_str, h);  return input.begin() + (h.pos() - &*input.begin());}template <typename... Args>string_view::iterator scan(string_view input, string_view format_str,                           Args&... args) {  return vscan(input, format_str, make_scan_args(args...));}FMT_END_NAMESPACE
 |