scan.h 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. // Formatting library for C++ - scanning API proof of concept
  2. //
  3. // Copyright (c) 2019 - present, Victor Zverovich
  4. // All rights reserved.
  5. //
  6. // For the license information refer to format.h.
  7. #include <array>
  8. #include <cassert>
  9. #include <climits>
  10. #include "fmt/format.h"
  11. FMT_BEGIN_NAMESPACE
  12. template <typename T, typename Char = char> struct scanner {
  13. // A deleted default constructor indicates a disabled scanner.
  14. scanner() = delete;
  15. };
  16. class scan_parse_context {
  17. private:
  18. string_view format_;
  19. public:
  20. using iterator = string_view::iterator;
  21. explicit FMT_CONSTEXPR scan_parse_context(string_view format)
  22. : format_(format) {}
  23. FMT_CONSTEXPR iterator begin() const { return format_.begin(); }
  24. FMT_CONSTEXPR iterator end() const { return format_.end(); }
  25. void advance_to(iterator it) {
  26. format_.remove_prefix(detail::to_unsigned(it - begin()));
  27. }
  28. };
  29. struct scan_context {
  30. private:
  31. string_view input_;
  32. public:
  33. using iterator = const char*;
  34. explicit scan_context(string_view input) : input_(input) {}
  35. iterator begin() const { return input_.data(); }
  36. iterator end() const { return begin() + input_.size(); }
  37. void advance_to(iterator it) {
  38. input_.remove_prefix(detail::to_unsigned(it - begin()));
  39. }
  40. };
  41. namespace detail {
  42. enum class scan_type {
  43. none_type,
  44. int_type,
  45. uint_type,
  46. long_long_type,
  47. ulong_long_type,
  48. string_type,
  49. string_view_type,
  50. custom_type
  51. };
  52. struct custom_scan_arg {
  53. void* value;
  54. void (*scan)(void* arg, scan_parse_context& parse_ctx, scan_context& ctx);
  55. };
  56. class scan_arg {
  57. public:
  58. scan_type type;
  59. union {
  60. int* int_value;
  61. unsigned* uint_value;
  62. long long* long_long_value;
  63. unsigned long long* ulong_long_value;
  64. std::string* string;
  65. fmt::string_view* string_view;
  66. custom_scan_arg custom;
  67. // TODO: more types
  68. };
  69. scan_arg() : type(scan_type::none_type) {}
  70. scan_arg(int& value) : type(scan_type::int_type), int_value(&value) {}
  71. scan_arg(unsigned& value) : type(scan_type::uint_type), uint_value(&value) {}
  72. scan_arg(long long& value)
  73. : type(scan_type::long_long_type), long_long_value(&value) {}
  74. scan_arg(unsigned long long& value)
  75. : type(scan_type::ulong_long_type), ulong_long_value(&value) {}
  76. scan_arg(std::string& value) : type(scan_type::string_type), string(&value) {}
  77. scan_arg(fmt::string_view& value)
  78. : type(scan_type::string_view_type), string_view(&value) {}
  79. template <typename T> scan_arg(T& value) : type(scan_type::custom_type) {
  80. custom.value = &value;
  81. custom.scan = scan_custom_arg<T>;
  82. }
  83. private:
  84. template <typename T>
  85. static void scan_custom_arg(void* arg, scan_parse_context& parse_ctx,
  86. scan_context& ctx) {
  87. scanner<T> s;
  88. parse_ctx.advance_to(s.parse(parse_ctx));
  89. ctx.advance_to(s.scan(*static_cast<T*>(arg), ctx));
  90. }
  91. };
  92. } // namespace detail
  93. struct scan_args {
  94. int size;
  95. const detail::scan_arg* data;
  96. template <size_t N>
  97. scan_args(const std::array<detail::scan_arg, N>& store)
  98. : size(N), data(store.data()) {
  99. static_assert(N < INT_MAX, "too many arguments");
  100. }
  101. };
  102. namespace detail {
  103. struct scan_handler : error_handler {
  104. private:
  105. scan_parse_context parse_ctx_;
  106. scan_context scan_ctx_;
  107. scan_args args_;
  108. int next_arg_id_;
  109. scan_arg arg_;
  110. template <typename T = unsigned> T read_uint() {
  111. T value = 0;
  112. auto it = scan_ctx_.begin(), end = scan_ctx_.end();
  113. while (it != end) {
  114. char c = *it++;
  115. if (c < '0' || c > '9') on_error("invalid input");
  116. // TODO: check overflow
  117. value = value * 10 + static_cast<unsigned>(c - '0');
  118. }
  119. scan_ctx_.advance_to(it);
  120. return value;
  121. }
  122. template <typename T = int> T read_int() {
  123. auto it = scan_ctx_.begin(), end = scan_ctx_.end();
  124. bool negative = it != end && *it == '-';
  125. if (negative) ++it;
  126. scan_ctx_.advance_to(it);
  127. const auto value = read_uint<typename std::make_unsigned<T>::type>();
  128. if (negative) return -static_cast<T>(value);
  129. return static_cast<T>(value);
  130. }
  131. public:
  132. scan_handler(string_view format, string_view input, scan_args args)
  133. : parse_ctx_(format), scan_ctx_(input), args_(args), next_arg_id_(0) {}
  134. const char* pos() const { return scan_ctx_.begin(); }
  135. void on_text(const char* begin, const char* end) {
  136. auto size = to_unsigned(end - begin);
  137. auto it = scan_ctx_.begin();
  138. if (it + size > scan_ctx_.end() ||
  139. !std::equal(begin, end, make_checked(it, size))) {
  140. on_error("invalid input");
  141. }
  142. scan_ctx_.advance_to(it + size);
  143. }
  144. FMT_CONSTEXPR int on_arg_id() { return on_arg_id(next_arg_id_++); }
  145. FMT_CONSTEXPR int on_arg_id(int id) {
  146. if (id >= args_.size) on_error("argument index out of range");
  147. arg_ = args_.data[id];
  148. return id;
  149. }
  150. FMT_CONSTEXPR int on_arg_id(string_view id) {
  151. if (id.data()) on_error("invalid format");
  152. return 0;
  153. }
  154. void on_replacement_field(int, const char*) {
  155. auto it = scan_ctx_.begin(), end = scan_ctx_.end();
  156. switch (arg_.type) {
  157. case scan_type::int_type:
  158. *arg_.int_value = read_int();
  159. break;
  160. case scan_type::uint_type:
  161. *arg_.uint_value = read_uint();
  162. break;
  163. case scan_type::long_long_type:
  164. *arg_.long_long_value = read_int<long long>();
  165. break;
  166. case scan_type::ulong_long_type:
  167. *arg_.ulong_long_value = read_uint<unsigned long long>();
  168. break;
  169. case scan_type::string_type:
  170. while (it != end && *it != ' ') arg_.string->push_back(*it++);
  171. scan_ctx_.advance_to(it);
  172. break;
  173. case scan_type::string_view_type: {
  174. auto s = it;
  175. while (it != end && *it != ' ') ++it;
  176. *arg_.string_view = fmt::string_view(s, to_unsigned(it - s));
  177. scan_ctx_.advance_to(it);
  178. break;
  179. }
  180. case scan_type::none_type:
  181. case scan_type::custom_type:
  182. assert(false);
  183. }
  184. }
  185. const char* on_format_specs(int, const char* begin, const char*) {
  186. if (arg_.type != scan_type::custom_type) return begin;
  187. parse_ctx_.advance_to(begin);
  188. arg_.custom.scan(arg_.custom.value, parse_ctx_, scan_ctx_);
  189. return parse_ctx_.begin();
  190. }
  191. };
  192. } // namespace detail
  193. template <typename... Args>
  194. std::array<detail::scan_arg, sizeof...(Args)> make_scan_args(Args&... args) {
  195. return {{args...}};
  196. }
  197. string_view::iterator vscan(string_view input, string_view format_str,
  198. scan_args args) {
  199. detail::scan_handler h(format_str, input, args);
  200. detail::parse_format_string<false>(format_str, h);
  201. return input.begin() + (h.pos() - &*input.begin());
  202. }
  203. template <typename... Args>
  204. string_view::iterator scan(string_view input, string_view format_str,
  205. Args&... args) {
  206. return vscan(input, format_str, make_scan_args(args...));
  207. }
  208. FMT_END_NAMESPACE