aboutsummaryrefslogtreecommitdiffstats
path: root/meowpp/utility.h
blob: 02cf6a2a654b37a26db0ae08d032415b53b6085a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
#ifndef   utility_H__
#define   utility_H__

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cstdarg>

#include <string>

namespace meow {

/*!
 * @brief A structur with memember \c .from.first , \c .from.second ,
 *        \c .to.first , \c .to.second
 *
 * @author cathook
 */
template<class F1, class F2 = F1, class T1 = F1, class T2 = T1>
struct PairToPair {
  std::pair<F1, F2> from;
  std::pair<T1, T2> 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__