/******************************************************** * ██████╗ ██████╗████████╗██╗ * ██╔════╝ ██╔════╝╚══██╔══╝██║ * ██║ ███╗██║ ██║ ██║ * ██║ ██║██║ ██║ ██║ * ╚██████╔╝╚██████╗ ██║ ███████╗ * ╚═════╝ ╚═════╝ ╚═╝ ╚══════╝ * Geophysical Computational Tools & Library (GCTL) * * Copyright (c) 2023 Yi Zhang (yizhang-geo@zju.edu.cn) * * GCTL is distributed under a dual licensing scheme. You can redistribute * it and/or modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either version 2 * of the License, or (at your option) any later version. You should have * received a copy of the GNU Lesser General Public License along with this * program. If not, see . * * If the terms and conditions of the LGPL v.2. would prevent you from using * the GCTL, please consider the option to obtain a commercial license for a * fee. These licenses are offered by the GCTL's original author. As a rule, * licenses are provided "as-is", unlimited in time for a one time fee. Please * send corresponding requests to: yizhang-geo@zju.edu.cn. Please do not forget * to include some description of your company and the realm of its activities. * Also add information on how to contact you by electronic and paper mail. ******************************************************/ #ifndef _GCTL_STREAM_TEMPLATE_H #define _GCTL_STREAM_TEMPLATE_H #include "string" #include "sstream" #include "../core/exceptions.h" #include "../core/vector_t.h" /** * terminal control symbols */ #define GCTL_BOLD "\033[1m" ///< 设置终端字体与颜色为粗体 #define GCTL_BOLDRED "\033[1m\033[31m" ///< 设置终端字体与颜色为粗体红色 #define GCTL_BOLDGREEN "\033[1m\033[32m" ///< 设置终端字体与颜色为粗体绿色 #define GCTL_BOLDBLUE "\033[1m\033[34m" ///< 设置终端字体与颜色为粗体蓝色 #define GCTL_BOLDYELLOW "\033[1m\033[33m" ///< 设置后续字符字体为黄色加粗 #define GCTL_UNDERLINE "\033[1m\033[4m" ///< 设置终端字体为下划线 #define GCTL_RESET "\033[0m" ///< 重置字体与颜色设定 #define GCTL_CLEARLINE "\033[K" ///< 清空终端当前行 #define GCTL_CLEARALL "\033[2J" ///< 清空终端窗口 #define GCTL_MOVEUP(os, x) do {os << "\033[" << x << "A";} while (0); ///< 终端光标上移x行 #define GCTL_MOVEDOWN(os, x) do {os << "\033[" << x << "B";} while (0); ///< 终端光标下移x行 #define GCTL_MOVERIGHT(os, x) do {os << "\033[" << x << "C";} while (0); ///< 终端光标右移x列 #define GCTL_MOVELEFT(os, x) do {os << "\033[" << x << "D";} while (0); ///< 终端光标左移x列 #define GCTL_MOVETO(os, r, c) do {os << "\033[" << c << ";" << r << "H";} while (0); ///< 终端光标移动至r行c列位置 namespace gctl { template void type2ss(ObjValType in_val, std::stringstream &out_ss) { out_ss.clear(); out_ss << in_val; return; } template int str2type(std::string in_str, OutValType &out_val, char sep = ' ') { std::stringstream tmp_ss; if (sep != ' ') { std::string new_str = in_str; std::string old_sep; old_sep = sep; std::string new_sep = " "; for(std::string::size_type pos(0); pos != std::string::npos; pos += new_sep.length()) { if((pos = new_str.find(old_sep, pos)) != std::string::npos) { new_str.replace(pos,old_sep.length(), new_sep); } else break; } tmp_ss.clear(); tmp_ss.str(new_str); } else { tmp_ss.clear(); tmp_ss.str(in_str); } tmp_ss >> out_val; if (tmp_ss.fail()) { return -1; } return 0; } template void str2type_vector(const std::vector &in_vec, std::vector &out_data) { if (!out_data.empty()) out_data.clear(); out_data.resize(in_vec.size()); for (int i = 0; i < out_data.size(); i++) { if (str2type(in_vec[i], out_data[i])) { throw gctl::runtime_error("[gctl::str2type_vector] Failed to parse: " + in_vec[i]); } } return; } template void type2str_vector(const std::vector &in_vec, std::vector &out_vec) { if (!out_vec.empty()) out_vec.clear(); out_vec.resize(in_vec.size()); for (size_t i = 0; i < in_vec.size(); i++) { out_vec[i] = std::to_string(in_vec[i]); } return; } template void str2type_vector2d(const std::vector> &vec2d, std::string order_str, std::vector &vec) { int idx; std::string tmp_str; std::stringstream tmp_ss(order_str); std::getline(tmp_ss, tmp_str, ','); tmp_ss.clear(); tmp_ss.str(tmp_str); tmp_ss >> idx; if (idx >= vec2d.size()) throw std::runtime_error("[gctl::str2type_vector2d] Invalid index."); order_str = order_str.substr(order_str.find_first_of(',') + 1); str2type_vector(vec2d[idx], vec); return; } template void str2type_vector2d(const std::vector> &vec2d, std::string order_str, std::vector &vec, Args&... rest) { int idx; std::string tmp_str; std::stringstream tmp_ss(order_str); std::getline(tmp_ss, tmp_str, ','); tmp_ss.clear(); tmp_ss.str(tmp_str); tmp_ss >> idx; if (idx >= vec2d.size()) throw std::runtime_error("[gctl::str2type_vector2d] Invalid index."); order_str = order_str.substr(order_str.find_first_of(',') + 1); str2type_vector(vec2d[idx], vec); str2type_vector2d(vec2d, order_str, rest...); return; } template void type2str_vector2d(std::vector> &vec2d, const std::vector &vec) { std::vector str_vec; type2str_vector(vec, str_vec); vec2d.push_back(str_vec); return; } template void type2str_vector2d(std::vector> &vec2d, const std::vector &vec, Args&... rest) { std::vector str_vec; type2str_vector(vec, str_vec); vec2d.push_back(str_vec); type2str_vector2d(vec2d, rest...); return; } /** * @brief Parse a string argument into an element array * * @param[in] val_str The input value string * @param out_vec The output array * @param[in] separator The separator * * @tparam ValueType Runtime value type * * @return 0 for success, -1 for failure */ template int parse_string_to_vector(std::string val_str, char separator, std::vector &out_vec) { val_str.erase(0, val_str.find_first_not_of(" \t")); val_str.erase(val_str.find_last_not_of(" \t") + 1); int pos; bool bk = false; ValueType val; std::string l_str; while (1) { pos = val_str.find(separator); if (pos == val_str.npos) { l_str = val_str; bk = true; } else { l_str = val_str.substr(0, pos); val_str = val_str.substr(pos+1, val_str.length()); val_str.erase(0, val_str.find_first_not_of(" \t")); } // 如果输出也是字符串 就直接赋值即可(避免l_str中含有空格会出现bug) if constexpr (std::is_same::value) val = l_str; else str2type(l_str, val); out_vec.push_back(val); if (bk) break; } return 0; } /** * @brief Parse a string argument into separated elements. * * @param[in] val_str The input value string * @param[in] separator The separator * @param[in] throw_err Throw out errors * @param[in] fst_val The output values returned by quote * * @tparam ValueType Runtime value type * * @return Number of parsed strings */ template int parse_string_to_value(std::string val_str, char separator, bool throw_err, ValueType &fst_val) { std::string tmp_str; std::stringstream tmp_ss(val_str); std::getline(tmp_ss, tmp_str, separator); tmp_ss.clear(); tmp_ss.str(tmp_str); tmp_ss >> fst_val; if (throw_err && tmp_ss.fail()) { throw std::runtime_error("Fail to parse the input string. From gctl::parse_string_to_value(...)"); } else if (tmp_ss.fail()) { return 0; } return 1; } /** * @brief Parse a string argument into separated elements. * * @param[in] val_str The input value string * @param[in] separator The separator * @param[in] throw_err Throw out errors * @param[in] fst_val The output values returned by quote * * @tparam ValueType Runtime value type * @tparam Args Runtime value types of the rest arguments * * @return Number of parsed strings */ template int parse_string_to_value(std::string val_str, char separator, bool throw_err, ValueType &fst_val, Args&... rest) { std::string tmp_str; std::stringstream tmp_ss(val_str); std::getline(tmp_ss, tmp_str, separator); tmp_ss.clear(); tmp_ss.str(tmp_str); tmp_ss >> fst_val; if (throw_err && tmp_ss.fail()) { throw std::runtime_error("Fail to parse the input string. From gctl::parse_string_to_value(...)"); } else if (tmp_ss.fail()) { return 0; } int position = val_str.find_first_of(separator); if (position == std::string::npos) tmp_str = ""; else tmp_str = val_str.substr(position+1, val_str.length()); return parse_string_to_value(tmp_str, separator, throw_err, rest...) + 1; } } #endif // _GCTL_STREAM_TEMPLATE_H