Advertisement
Guest User

Untitled

a guest
Mar 25th, 2017
146
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.27 KB | None | 0 0
  1. #include <vector>
  2. #include <sstream>
  3. #include <iostream>
  4. #include <iterator>
  5. #include <tuple>
  6.  
  7. template <typename T>
  8. std::vector<std::string> Split(T&& input) {
  9.     std::stringstream ss{ std::forward<T>(input) };
  10.     return std::vector<std::string> {std::istream_iterator<std::string>(ss), std::istream_iterator<std::string>{} };
  11. }
  12.  
  13. // Throw format
  14. inline void ThrowInternal(std::stringstream& ss) {
  15.     throw std::logic_error(ss.str());
  16. }
  17.  
  18. template<typename T, typename...ARGS>
  19. void ThrowInternal(std::stringstream& ss, T&& elem, ARGS&&...rest) {
  20.     ss << std::forward<T>(elem);
  21.     ThrowInternal(ss, std::forward<ARGS>(rest)...);
  22. }
  23.  
  24. template <typename...ARGS>
  25. void Throw(ARGS&&...args) {
  26.     std::stringstream ss;
  27.     ThrowInternal(ss, std::forward<ARGS>(args)...);
  28. }
  29.  
  30. // ForEach tuple
  31. template <size_t CUR, size_t END>
  32. struct ForEachIter_t {
  33.     template <typename CALLABLE, typename...TYPES>
  34.     static void Do(const std::tuple<TYPES...>& tpl, CALLABLE&& func) {
  35.         func(std::get<CUR>(tpl));
  36.         ForEachIter_t<CUR + 1, END>::Do(tpl, func);
  37.     }
  38.     template <typename CALLABLE, typename...TYPES>
  39.     static void Do(std::tuple<TYPES...>& tpl, CALLABLE&& func) {
  40.         func(std::get<CUR>(tpl));
  41.         ForEachIter_t<CUR + 1, END>::Do(tpl, func);
  42.     }
  43. };
  44.  
  45. template <size_t CUR>
  46. struct ForEachIter_t<CUR, CUR> {
  47.     template <typename CALLABLE, typename...TYPES>
  48.     static void Do(const std::tuple<TYPES...>&, CALLABLE&&) {};
  49. };
  50.  
  51. template <typename CALLABLE, typename...TYPES>
  52. void ForEach(const std::tuple<TYPES...>& tpl, CALLABLE&& func) {
  53.     constexpr size_t tplSize = std::tuple_size<std::tuple<TYPES...>>::value;
  54.     ForEachIter_t<0, tplSize>::Do(tpl, func);
  55. }
  56.  
  57. template <typename CALLABLE, typename...TYPES>
  58. void ForEach(std::tuple<TYPES...>& tpl, CALLABLE&& func) {
  59.     constexpr size_t tplSize = std::tuple_size<std::tuple<TYPES...>>::value;
  60.     ForEachIter_t<0, tplSize>::Do(tpl, func);
  61. }
  62.  
  63. // Expand Tuple to function
  64. template <typename...TYPES, typename CALLABLE, size_t...IDX>
  65. void ExpandHelper(const std::tuple<TYPES...>& tpl, CALLABLE&& func, std::index_sequence<IDX...>&& idx) {
  66.     func(std::get<IDX>(tpl)...);
  67. }
  68.  
  69. template <typename...TYPES, typename CALLABLE>
  70. void ExpandAndCall(const std::tuple<TYPES...>& tpl, CALLABLE&& func) {
  71.     ExpandHelper(tpl, std::forward<CALLABLE>(func), std::make_index_sequence<sizeof...(TYPES)>());
  72. }
  73.  
  74. // Callbacks
  75. namespace fn {
  76.     inline void sum(int a, int b) {
  77.         std::cout << a << " + " << b << " = " << a + b << '\n';
  78.     }
  79.     inline void div(const double& a, const double& b) {
  80.         std::cout << a << " / " << b << " = " << a / b << '\n';
  81.     }
  82.     inline void square(const unsigned long& a) {
  83.         std::cout << a << " ^ 2 = " << a * a << '\n';
  84.     }
  85.     inline void reverse(const std::string& str) {
  86.         std::cout << str << " -> " << std::string{ str.rbegin(), str.rend() } << '\n';
  87.     }
  88.     inline void con_exit() {
  89.         exit(0);
  90.     }
  91. }
  92.  
  93. // Converter
  94. template <typename T>
  95. T Converter(const std::string&) {
  96.     static_assert(std::is_same<T, void>::value, "Converter for this type is not specialized");
  97.     return T{};
  98. }
  99.  
  100. template<>
  101. inline int Converter<int>(const std::string& str) {
  102.     try {
  103.         return stoi(str);
  104.     }
  105.     catch (...) {
  106.         Throw("Unable to convert '", str, "' to int");
  107.     }
  108. }
  109.  
  110. template <>
  111. inline double Converter<double>(const std::string& str) {
  112.     try {
  113.         return stod(str);
  114.     }
  115.     catch (...) {
  116.         Throw("Unable to convert '", str, "' to double");
  117.     }
  118. }
  119.  
  120. template<>
  121. inline unsigned long Converter<unsigned long>(const std::string& str) {
  122.     try {
  123.         if (str.front() == '-') throw std::exception{};
  124.         return stoul(str);
  125.     }
  126.     catch (...) {
  127.         Throw("Unable to convert '", str, "' to unsigned long");
  128.     }
  129. }
  130.  
  131. template<>
  132. inline std::string Converter<std::string>(const std::string& str) {
  133.     return str;
  134. }
  135.  
  136. // Invoke
  137. template<typename...ARGS>
  138. void Invoke(void(*func)(ARGS...args), std::vector<std::string>::const_iterator curr) {
  139.     std::tuple<std::decay_t<ARGS>...> tempTpl;
  140.     ForEach(tempTpl, [&curr](auto& elem) {
  141.         elem = Converter<std::decay_t<decltype(elem)>>(*(++curr));
  142.     });
  143.     ExpandAndCall(tempTpl, func);
  144. }
  145.  
  146. // Command
  147. template <typename CALLABLE, typename...TYPES>
  148. class Command_t {
  149.     template <typename...ARGS>
  150.     friend auto MakeCommand(std::string&& name, void(*func)(ARGS...));
  151. public:
  152.     const std::string& GetName() const {
  153.         return m_name;
  154.     }
  155.     const CALLABLE& GetFunc() const {
  156.         return m_func;
  157.     }
  158. private:
  159.     Command_t(std::string&& name, CALLABLE func) :
  160.         m_name(std::forward<std::string>(name)), m_func(func) {}
  161.  
  162.     const std::string m_name;
  163.     const CALLABLE m_func;
  164. };
  165.  
  166. template <typename...ARGS>
  167. auto MakeCommand(std::string&& name, void(*func)(ARGS...)) {
  168.     return Command_t<decltype(func), std::decay_t<ARGS>...>(move(name), func);
  169. }
  170.  
  171. // Branch
  172. template <typename...CMDS>
  173. class Branch_t {
  174.     template <typename...ARGS>
  175.     friend Branch_t<ARGS...> MakeBranch(std::string&& name, ARGS&&...args);
  176. public:
  177.     const std::string& GetName() const {
  178.         return m_name;
  179.     }
  180.     const std::tuple<CMDS...>& GetChildren() const {
  181.         return m_cmds;
  182.     }
  183. private:
  184.     Branch_t(std::string&& name, CMDS&&...cmds) :
  185.         m_name(std::forward<std::string>(name)),
  186.         m_cmds(std::forward_as_tuple(cmds...)) {};
  187.  
  188.     const std::string m_name;
  189.     const std::tuple<CMDS...> m_cmds;
  190. };
  191.  
  192. template <typename...ARGS>
  193. Branch_t<ARGS...> MakeBranch(std::string&& name, ARGS&&...args) {
  194.     return Branch_t<ARGS...>(std::forward<std::string>(name), std::forward<ARGS>(args)...);
  195. }
  196.  
  197. template <typename CALLABLE, typename...TYPES>
  198. bool ProcessTupleElem(std::vector<std::string>::const_iterator curr, std::vector<std::string>::const_iterator last, const Command_t<CALLABLE, TYPES...>& command) {
  199.     if (command.GetName() == *curr) {
  200.         if (std::distance(curr, last) != sizeof...(TYPES)+1) {
  201.             Throw("Excepted ", sizeof...(TYPES), " arguments, got ", std::distance(curr, last) - 1);
  202.         }
  203.         Invoke(command.GetFunc(), curr);
  204.         return true;
  205.     }
  206.     return false;
  207. }
  208.  
  209. template <typename...ARGS>
  210. bool ProcessTupleElem(std::vector<std::string>::const_iterator curr, std::vector<std::string>::const_iterator last, const Branch_t<ARGS...>& branch) {
  211.     if (branch.GetName() == *curr) {
  212.         if (std::distance(curr, last) == 1) {
  213.             Throw("Excepted command after branch, got none");
  214.         }
  215.         bool found{ false };
  216.         ForEach(branch.GetChildren(), [&found, &curr, &last](const auto &elem) {
  217.             found |= ProcessTupleElem(curr + 1, last, elem);
  218.         });
  219.         if (!found) {
  220.             Throw("command '", *curr, "' not found in branch '", *(curr + 1), "'");
  221.         }
  222.         return true;
  223.     }
  224.     return false;
  225. }
  226.  
  227. template <typename...ARGS>
  228. void MagicStartsHere(const std::tuple<ARGS...>& cmds, std::vector<std::string>&& tokens) {
  229.     if (tokens.empty()) return;
  230.     bool found{ false };
  231.     ForEach(cmds, [&found, &tokens](auto&& elem) {
  232.         found |= ProcessTupleElem(tokens.cbegin(), tokens.cend(), elem);
  233.     });
  234.     if (!found) {
  235.         Throw("command '", tokens.front(), "' not found");
  236.     }
  237. }
  238.  
  239. int main() {
  240.     const auto commands = std::make_tuple(
  241.         MakeBranch("math",
  242.             MakeCommand("sum", fn::sum),
  243.             MakeCommand("div", fn::div),
  244.             MakeCommand("square", fn::square)
  245.         ),
  246.         MakeCommand("reverse", fn::reverse),
  247.         MakeCommand("exit", fn::con_exit)
  248.     );
  249.  
  250.     while (true) {
  251.         std::cout << "> ";
  252.         std::string inp;
  253.         getline(std::cin, inp);
  254.         try {
  255.             MagicStartsHere(commands, Split(inp));
  256.         }
  257.         catch (const std::exception& e) {
  258.             std::cout << "ERROR: " << e.what() << '\n';
  259.         }
  260.     }
  261. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement