fork download
  1. #ifndef SCANNER_HPP
  2. #define SCANNER_HPP
  3.  
  4. #include <cstdlib>
  5. #include <stdexcept>
  6. #include <tuple>
  7. #include <type_traits>
  8.  
  9. template <typename T>
  10. struct static_parser;
  11.  
  12. template <template <typename> class Parser = static_parser>
  13. class scanner
  14. {
  15. const char* buf_;
  16.  
  17. public:
  18. scanner(const char* over)
  19. : buf_(over)
  20. {
  21. if (buf_ == 0) // gcc 5.1 doesn't know nullptr
  22. throw std::logic_error("Invalid nullpointer");
  23. }
  24.  
  25. template <typename T0>
  26. T0 scan(const char* format)
  27. {
  28. auto r = scan_impl<T0>(format);
  29.  
  30. while (*buf_ && *format)
  31. {
  32. if (*format == '%' && *++format != '%')
  33. {
  34. throw std::runtime_error("Unexpected % in format string.");
  35. }
  36.  
  37. if (*buf_++ != *format++)
  38. throw std::runtime_error("Format string differs from buffer.");
  39. }
  40.  
  41. if (*format)
  42. throw std::runtime_error("Format string is longer than buffer.");
  43.  
  44. return r;
  45. }
  46.  
  47. template <typename T0, typename T1>
  48. std::tuple<T0, T1> scan(const char* format)
  49. {
  50. auto r0 = scan_impl<T0>(format);
  51. return std::make_tuple(r0, scan<T1>(format));
  52. }
  53.  
  54. template <typename T0, typename T1, typename T2>
  55. std::tuple<T0, T1, T2> scan(const char* format)
  56. {
  57. auto r0 = scan_impl<T0>(format);
  58. auto t = scan<T1, T2>(format);
  59. return std::make_tuple(r0, std::get<0>(t), std::get<1>(t));
  60. }
  61.  
  62. template <typename T0, typename T1, typename T2, typename T3>
  63. std::tuple<T0, T1, T2, T3> scan(const char* format)
  64. {
  65. auto r0 = scan_impl<T0>(format);
  66. auto t = scan<T1, T2, T3>(format);
  67. return std::make_tuple(r0, std::get<0>(t), std::get<1>(t), std::get<2>(t));
  68. }
  69.  
  70. template <typename T0, typename T1, typename T2, typename T3, typename T4>
  71. std::tuple<T0, T1, T2, T3, T4> scan(const char* format)
  72. {
  73. auto r0 = scan_impl<T0>(format);
  74. auto t = scan<T1, T2, T3, T4>(format);
  75. return std::make_tuple(r0, std::get<0>(t), std::get<1>(t), std::get<2>(t), std::get<3>(t));
  76. }
  77.  
  78. template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
  79. std::tuple<T0, T1, T2, T3, T4, T5> scan(const char* format)
  80. {
  81. auto r0 = scan_impl<T0>(format);
  82. auto t = scan<T1, T2, T3, T4, T5>(format);
  83. return std::make_tuple(r0, std::get<0>(t), std::get<1>(t), std::get<2>(t), std::get<3>(t), std::get<4>(t));
  84. }
  85.  
  86. private:
  87. template <typename T0>
  88. T0 scan_impl(const char*& format)
  89. {
  90. while (*buf_ && *format)
  91. {
  92. if (*format == '%' && *++format != '%')
  93. return Parser<T0>::parse(*this, buf_);
  94.  
  95. if (*buf_++ != *format++)
  96. throw std::runtime_error("Unexpected character.");
  97. }
  98. throw std::runtime_error("Unexpected end.");
  99. }
  100. };
  101.  
  102. template <typename T>
  103. struct static_parser
  104. {
  105. static T parse(scanner<>& s, const char*& buf)
  106. { // dummy so the compiler can only use static_assert if function is instanciated
  107. const bool is_ = std::is_pod<T>::value;
  108. const bool or_ = !std::is_pod<T>::value;
  109. static_assert(is_ || or_, "No parsing function for this type.");
  110. }
  111. };
  112.  
  113. template <char C>
  114. class delim
  115. {
  116. std::string data_;
  117.  
  118. public:
  119. delim(std::string data)
  120. : data_(std::move(data))
  121. {}
  122.  
  123. operator std::string() const
  124. {
  125. return data_;
  126. }
  127. };
  128.  
  129. template <char C>
  130. struct static_parser<delim<C>>
  131. {
  132. static delim<C> parse(scanner<>&, const char*& buf)
  133. {
  134. auto begin = buf;
  135. while (*buf && *buf != C)
  136. ++buf;
  137. return std::string(begin, buf);
  138. }
  139. };
  140.  
  141. template <>
  142. std::string static_parser<std::string>::parse(scanner<>&, const char*& buf)
  143. {
  144. while (std::isspace(*buf))
  145. ++buf;
  146.  
  147. auto begin = buf;
  148. while (*buf && !std::isspace(*buf))
  149. ++buf;
  150.  
  151. return std::string(begin, buf);
  152. }
  153.  
  154. // Es fehlen noch: signed char, unsigned char, long long, unsigned long long, long double
  155.  
  156. template <>
  157. char static_parser<char>::parse(scanner<>&, const char*& buf)
  158. {
  159. if (*buf != '\0')
  160. return *buf++;
  161. throw std::runtime_error("End of buffer found, could not parse character.");
  162. }
  163.  
  164. template <>
  165. long static_parser<long>::parse(scanner<>&, const char*& buf)
  166. {
  167. char* p;
  168. auto r = std::strtol(buf, &p, 10);
  169. if (r == 0 && p == buf)
  170. throw std::runtime_error("Failed to parse long.");
  171. buf = p;
  172. return r;
  173. }
  174.  
  175. template <>
  176. unsigned long static_parser<unsigned long>::parse(scanner<>&, const char*& buf)
  177. {
  178. char* p;
  179. auto r = std::strtoul(buf, &p, 10);
  180. if (r == 0 && p == buf)
  181. throw std::runtime_error("Failed to parse unsigned long.");
  182. buf = p;
  183. return r;
  184. }
  185.  
  186. template <>
  187. int static_parser<int>::parse(scanner<>& s, const char*& buf)
  188. { // Overflow?
  189. return static_parser<long>::parse(s, buf);
  190. }
  191.  
  192. template <>
  193. unsigned static_parser<unsigned>::parse(scanner<>& s, const char*& buf)
  194. { // Overflow?
  195. return static_parser<unsigned long>::parse(s, buf);
  196. }
  197.  
  198. template <>
  199. double static_parser<double>::parse(scanner<>&, const char*& buf)
  200. {
  201. char* p;
  202. auto r = std::strtod(buf, &p);
  203. if (r == 0.0 && p == buf)
  204. throw std::runtime_error("Failed to parse double.");
  205. buf = p;
  206. return r;
  207. }
  208.  
  209. template <>
  210. float static_parser<float>::parse(scanner<>& s, const char*& buf)
  211. { // Overflow?
  212. return static_cast<float>(static_parser<double>::parse(s, buf));
  213. }
  214.  
  215. #endif
  216.  
  217. #include <iostream>
  218.  
  219. class person
  220. {
  221. std::string name_;
  222. unsigned age_;
  223.  
  224. public:
  225. person(std::string name, unsigned age)
  226. : name_(std::move(name))
  227. , age_(age)
  228. {}
  229.  
  230. person(person&& p)
  231. : name_(std::move(p.name_))
  232. , age_(p.age_)
  233. {}
  234.  
  235. const std::string& name() const
  236. {
  237. return name_;
  238. }
  239.  
  240. unsigned age() const
  241. {
  242. return age_;
  243. }
  244.  
  245. private:
  246. person(const person&);
  247. person& operator = (const person&);
  248. };
  249.  
  250.  
  251. template <>
  252. person static_parser<person>::parse(scanner<>& s, const char*&)
  253. {
  254. auto t = s.scan<delim<'\n'>, int>("name: %""\nage: %\n");
  255. return person(std::get<0>(t), std::get<1>(t));
  256. }
  257.  
  258. int main()
  259. {
  260. try
  261. {
  262. scanner<> s("name: John Doe\n""age: 27\n");
  263. auto p = s.scan<person>("%");
  264. std::cout << "Hello, " << p.name() << '\n';
  265. if (p.age() <= 30)
  266. std::cout << "What? You are already " << p.age() << " years old? You look younger.\n";
  267. else
  268. std::cout << "What? You are only " << p.age() << " years old? You look older.\n";
  269. }
  270. catch (const std::runtime_error& e)
  271. {
  272. std::cerr << e.what() << '\n';
  273. }
  274. }
Success #stdin #stdout 0s 2968KB
stdin
Standard input is empty
stdout
Hello, John Doe
What? You are already 27 years old? You look younger.