Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <vector>
- #include <sstream>
- #include <iostream>
- #include <iterator>
- #include <tuple>
- template <typename T>
- std::vector<std::string> Split(T&& input) {
- std::stringstream ss{ std::forward<T>(input) };
- return std::vector<std::string> {std::istream_iterator<std::string>(ss), std::istream_iterator<std::string>{} };
- }
- // Throw format
- inline void ThrowInternal(std::stringstream& ss) {
- throw std::logic_error(ss.str());
- }
- template<typename T, typename...ARGS>
- void ThrowInternal(std::stringstream& ss, T&& elem, ARGS&&...rest) {
- ss << std::forward<T>(elem);
- ThrowInternal(ss, std::forward<ARGS>(rest)...);
- }
- template <typename...ARGS>
- void Throw(ARGS&&...args) {
- std::stringstream ss;
- ThrowInternal(ss, std::forward<ARGS>(args)...);
- }
- // ForEach tuple
- template <size_t CUR, size_t END>
- struct ForEachIter_t {
- template <typename CALLABLE, typename...TYPES>
- static void Do(const std::tuple<TYPES...>& tpl, CALLABLE&& func) {
- func(std::get<CUR>(tpl));
- ForEachIter_t<CUR + 1, END>::Do(tpl, func);
- }
- template <typename CALLABLE, typename...TYPES>
- static void Do(std::tuple<TYPES...>& tpl, CALLABLE&& func) {
- func(std::get<CUR>(tpl));
- ForEachIter_t<CUR + 1, END>::Do(tpl, func);
- }
- };
- template <size_t CUR>
- struct ForEachIter_t<CUR, CUR> {
- template <typename CALLABLE, typename...TYPES>
- static void Do(const std::tuple<TYPES...>&, CALLABLE&&) {};
- };
- template <typename CALLABLE, typename...TYPES>
- void ForEach(const std::tuple<TYPES...>& tpl, CALLABLE&& func) {
- constexpr size_t tplSize = std::tuple_size<std::tuple<TYPES...>>::value;
- ForEachIter_t<0, tplSize>::Do(tpl, func);
- }
- template <typename CALLABLE, typename...TYPES>
- void ForEach(std::tuple<TYPES...>& tpl, CALLABLE&& func) {
- constexpr size_t tplSize = std::tuple_size<std::tuple<TYPES...>>::value;
- ForEachIter_t<0, tplSize>::Do(tpl, func);
- }
- // Expand Tuple to function
- template <typename...TYPES, typename CALLABLE, size_t...IDX>
- void ExpandHelper(const std::tuple<TYPES...>& tpl, CALLABLE&& func, std::index_sequence<IDX...>&& idx) {
- func(std::get<IDX>(tpl)...);
- }
- template <typename...TYPES, typename CALLABLE>
- void ExpandAndCall(const std::tuple<TYPES...>& tpl, CALLABLE&& func) {
- ExpandHelper(tpl, std::forward<CALLABLE>(func), std::make_index_sequence<sizeof...(TYPES)>());
- }
- // Callbacks
- namespace fn {
- inline void sum(int a, int b) {
- std::cout << a << " + " << b << " = " << a + b << '\n';
- }
- inline void div(const double& a, const double& b) {
- std::cout << a << " / " << b << " = " << a / b << '\n';
- }
- inline void square(const unsigned long& a) {
- std::cout << a << " ^ 2 = " << a * a << '\n';
- }
- inline void reverse(const std::string& str) {
- std::cout << str << " -> " << std::string{ str.rbegin(), str.rend() } << '\n';
- }
- inline void con_exit() {
- exit(0);
- }
- }
- // Converter
- template <typename T>
- T Converter(const std::string&) {
- static_assert(std::is_same<T, void>::value, "Converter for this type is not specialized");
- return T{};
- }
- template<>
- inline int Converter<int>(const std::string& str) {
- try {
- return stoi(str);
- }
- catch (...) {
- Throw("Unable to convert '", str, "' to int");
- }
- }
- template <>
- inline double Converter<double>(const std::string& str) {
- try {
- return stod(str);
- }
- catch (...) {
- Throw("Unable to convert '", str, "' to double");
- }
- }
- template<>
- inline unsigned long Converter<unsigned long>(const std::string& str) {
- try {
- if (str.front() == '-') throw std::exception{};
- return stoul(str);
- }
- catch (...) {
- Throw("Unable to convert '", str, "' to unsigned long");
- }
- }
- template<>
- inline std::string Converter<std::string>(const std::string& str) {
- return str;
- }
- // Invoke
- template<typename...ARGS>
- void Invoke(void(*func)(ARGS...args), std::vector<std::string>::const_iterator curr) {
- std::tuple<std::decay_t<ARGS>...> tempTpl;
- ForEach(tempTpl, [&curr](auto& elem) {
- elem = Converter<std::decay_t<decltype(elem)>>(*(++curr));
- });
- ExpandAndCall(tempTpl, func);
- }
- // Command
- template <typename CALLABLE, typename...TYPES>
- class Command_t {
- template <typename...ARGS>
- friend auto MakeCommand(std::string&& name, void(*func)(ARGS...));
- public:
- const std::string& GetName() const {
- return m_name;
- }
- const CALLABLE& GetFunc() const {
- return m_func;
- }
- private:
- Command_t(std::string&& name, CALLABLE func) :
- m_name(std::forward<std::string>(name)), m_func(func) {}
- const std::string m_name;
- const CALLABLE m_func;
- };
- template <typename...ARGS>
- auto MakeCommand(std::string&& name, void(*func)(ARGS...)) {
- return Command_t<decltype(func), std::decay_t<ARGS>...>(move(name), func);
- }
- // Branch
- template <typename...CMDS>
- class Branch_t {
- template <typename...ARGS>
- friend Branch_t<ARGS...> MakeBranch(std::string&& name, ARGS&&...args);
- public:
- const std::string& GetName() const {
- return m_name;
- }
- const std::tuple<CMDS...>& GetChildren() const {
- return m_cmds;
- }
- private:
- Branch_t(std::string&& name, CMDS&&...cmds) :
- m_name(std::forward<std::string>(name)),
- m_cmds(std::forward_as_tuple(cmds...)) {};
- const std::string m_name;
- const std::tuple<CMDS...> m_cmds;
- };
- template <typename...ARGS>
- Branch_t<ARGS...> MakeBranch(std::string&& name, ARGS&&...args) {
- return Branch_t<ARGS...>(std::forward<std::string>(name), std::forward<ARGS>(args)...);
- }
- template <typename CALLABLE, typename...TYPES>
- bool ProcessTupleElem(std::vector<std::string>::const_iterator curr, std::vector<std::string>::const_iterator last, const Command_t<CALLABLE, TYPES...>& command) {
- if (command.GetName() == *curr) {
- if (std::distance(curr, last) != sizeof...(TYPES)+1) {
- Throw("Excepted ", sizeof...(TYPES), " arguments, got ", std::distance(curr, last) - 1);
- }
- Invoke(command.GetFunc(), curr);
- return true;
- }
- return false;
- }
- template <typename...ARGS>
- bool ProcessTupleElem(std::vector<std::string>::const_iterator curr, std::vector<std::string>::const_iterator last, const Branch_t<ARGS...>& branch) {
- if (branch.GetName() == *curr) {
- if (std::distance(curr, last) == 1) {
- Throw("Excepted command after branch, got none");
- }
- bool found{ false };
- ForEach(branch.GetChildren(), [&found, &curr, &last](const auto &elem) {
- found |= ProcessTupleElem(curr + 1, last, elem);
- });
- if (!found) {
- Throw("command '", *curr, "' not found in branch '", *(curr + 1), "'");
- }
- return true;
- }
- return false;
- }
- template <typename...ARGS>
- void MagicStartsHere(const std::tuple<ARGS...>& cmds, std::vector<std::string>&& tokens) {
- if (tokens.empty()) return;
- bool found{ false };
- ForEach(cmds, [&found, &tokens](auto&& elem) {
- found |= ProcessTupleElem(tokens.cbegin(), tokens.cend(), elem);
- });
- if (!found) {
- Throw("command '", tokens.front(), "' not found");
- }
- }
- int main() {
- const auto commands = std::make_tuple(
- MakeBranch("math",
- MakeCommand("sum", fn::sum),
- MakeCommand("div", fn::div),
- MakeCommand("square", fn::square)
- ),
- MakeCommand("reverse", fn::reverse),
- MakeCommand("exit", fn::con_exit)
- );
- while (true) {
- std::cout << "> ";
- std::string inp;
- getline(std::cin, inp);
- try {
- MagicStartsHere(commands, Split(inp));
- }
- catch (const std::exception& e) {
- std::cout << "ERROR: " << e.what() << '\n';
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement