#ifndef utility_H__ #define utility_H__ #include #include #include #include #include namespace meow { /*! * @brief A structur with memember \c .from.first , \c .from.second , * \c .to.first , \c .to.second * * @author cathook */ template struct PairToPair { std::pair from; std::pair to; PairToPair() { } PairToPair(PairToPair const& pp): from(pp.from), to(pp.to) { } PairToPair(F1 const& f1, F2 const& f2, T1 const& t1, T2 const& t2): from(f1, f2), to(t1, t2) { } bool operator==(PairToPair const& p) const { return (from == p.from && to == p.to); } }; /*! * @brief 類似C的printf, 不過是將格式化的字串丟到 \c std::string 裡回傳 * * @param [in] fmt,... 同printf * @return 一個 \c std::string * @warning 目前格式化字串最長只支援8191個字元 */ inline std::string stringPrintf(char const * fmt, ...) { char str[8192]; va_list args; va_start(args, fmt); vsnprintf(str, 8192, fmt, args); va_end(args); return std::string(str); } /*! * @brief 將輸入字串中的某個pattern取代成另一個pattern * * @param [in] str 輸入的字串 * @param [in] from 要被取代的pattern * @param [in] to 將要取代的pattern * @return 取代後的字串 * @warning 有礙於目前實作方法很低級暴力, 時間複雜度神高 */ inline std::string stringReplace(std::string str, std::string const& from, std::string const& to) { std::string out = str; int len = from.length(); for (size_t pos; (pos = out.find(from)) != std::string::npos; ) { out.replace(pos, len, to); } return out; } /*! * @brief 檢查給定字串的結尾是否符合給定的數個patterns中的一個 * * @param [in] str 愈檢查的字串 * @param [in] n pattern數 * @param [in] ... 各種pattern * @return \c true/false 表示 \b 是否有符合 * @note 參數中所有的字串都是用\c cstring 來傳遞, * 也就是 \c char \c const* 型態 */ inline bool cstringEndWith(char const* str, int n, ...) { int len = strlen(str); va_list args; va_start(args, n); for (int i = 0; i < n; i++) { char const* arg = va_arg(args, char const*); int arglen = strlen(arg); if (arglen <= len && strcmp(str + len - arglen, arg) == 0) { return true; } } va_end(args); return false; } /*! * @brief 若DEBUG有被define過, 將字串印到stderr, 並且附上檔名行號與所在函數名 * * @param [in] str 要輸出的字串, 必須是c string, 即 \c char \c const* 型態 * @return 無 * @note 這是一個 \b macro */ #define debugPrintf(str) \ debugPrintf_(\ __FILE__,\ __FUNCTION__,\ __LINE__,\ str) inline void debugPrintf_(char const* file, char const* func, size_t line, char const* msg) { #ifdef DEBUG fprintf(stderr, "%s[%d] %s >> %s", file, line, func, msg); #endif // DEBUG } /*! * @brief 階層式輸出 * * 像是printf, 但多了一個 \b 巢狀 的概念, 例如: * * @code * message1(level = 0) * message2(level = 1) * information1(level = 2) * information2(level = 2) * ... ok(for message2) * message3(level = 1) ... ok * information3(level = 1) * message4(level = 1) * message5(level = 2) ... ok * message6(level = 2) ... ok * information4(level = 2) * ... ok(for message4) * ... ok(for message5) * @endcode * @param [in] level_change 分以下三種情況: * - == 0, 只是印出一個information * - == 1, 印出一個message, 並且level++ * - == -1, 表示此訊息相對應最近一次level++的那個message * @param [in] fmt, ... 跟printf一樣 * @return 無 */ inline void messagePrintf(int level_change, char const* fmt, ...) { static int level = 0; static int last_level = -5; char str[8192]; va_list args; va_start(args, fmt); vsnprintf(str, 8192, fmt, args); va_end(args); if (last_level == 1 && level_change == -1) { printf(" ...%s\n", str); } else { if (last_level == 1) printf("\n"); int level2 = level + (level_change == -1 ? -1 : 0); for (int i = 0; i < level2; i++) printf("| "); printf("%s%s", (level_change == -1 ? "..." : ""), str); if (level_change != 1) printf("\n"); } level += level_change; last_level = level_change; fflush(stdout); } /*! * @brief 將兩個字串用人類習慣的檔名排序方式排序 * * 例如 a1 \< a2 \< a3 \< a10 \< a12 \< a20, * 而不是 a1 \< a10 \< a12 \< a2 \< a20 \< a3 * * @param [in] f1 第一個字串 * @param [in] f2 第二個字串 * @return \c true/false 表 \b f1是否該排在f2前面 */ inline bool filenameCompare(std::string const& f1, std::string const& f2) { char const* s1 = f1.c_str(); char const* s2 = f2.c_str(); int l1 = f1.length(); int l2 = f2.length(); int i1, i2; for (i1 = i2 = 0; i1 < l1 || i2 < l2; i1++, i2++) { if (isdigit(s1[i1]) && isdigit(s2[i2])) { int n1 = atoi(s1 + i1); int n2 = atoi(s2 + i2); if (n1 != n2) return (n1 < n2); while(i1 + 1 < l1 && isdigit(s1[i1 + 1])) i1++; while(i2 + 1 < l2 && isdigit(s2[i2 + 1])) i2++; } else { if(s1[i1] != s2[i2]) return s1[i1] < s2[i2]; } } return false; } } // meow #endif // utility_H__