您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

390 行
9.1 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2010—2017 Sam Hocevar <sam@hocevar.net>
  5. // © 2013—2015 Benjamin “Touky” Huet <huet.benjamin@gmail.com>
  6. //
  7. // Lol Engine is free software. It comes without any warranty, to
  8. // the extent permitted by applicable law. You can redistribute it
  9. // and/or modify it under the terms of the Do What the Fuck You Want
  10. // to Public License, Version 2, as published by the WTFPL Task Force.
  11. // See http://www.wtfpl.net/ for more details.
  12. //
  13. #pragma once
  14. //
  15. // The string tools
  16. // ----------------
  17. // Contains some utilities to work with std::string objects.
  18. //
  19. #include <string>
  20. namespace lol
  21. {
  22. /* Split a string along a single separator */
  23. array<std::string> split(std::string const &s, char sep);
  24. /* Split a string along multiple separators */
  25. array<std::string> split(std::string const &s, std::string const &seps);
  26. std::string format(char const *format, ...) LOL_ATTR_FORMAT(1, 2);
  27. std::string vformat(char const *format, va_list ap);
  28. } /* namespace lol */
  29. //
  30. // The deprecated String class
  31. // ---------------------------
  32. // A very simple String class, based on Array. The most interesting
  33. // thing in there was LOL_ATTR_NODISCARD but apart from that there was
  34. // no real point in using our own class. Phase this out.
  35. //
  36. #include <lol/base/assert.h>
  37. #include <lol/base/array.h>
  38. #include <cstring>
  39. #include <cstdarg>
  40. namespace lol
  41. {
  42. class LOL_ATTR_NODISCARD String : protected array<char>
  43. {
  44. private:
  45. typedef array<char> super;
  46. public:
  47. inline String()
  48. : super()
  49. {
  50. push('\0');
  51. }
  52. inline String(char const *str)
  53. : super()
  54. {
  55. using namespace std;
  56. ASSERT(str);
  57. resize((int)strlen(str));
  58. memcpy(&(*this)[0], str, count() + 1);
  59. }
  60. inline String(char const *str, int item_count)
  61. : super()
  62. {
  63. using namespace std;
  64. ASSERT(str);
  65. resize(item_count);
  66. memcpy(&(*this)[0], str, item_count);
  67. ((super &)*this)[item_count] = '\0';
  68. }
  69. /* Legacy constructor for std::string */
  70. inline String(std::string const &s)
  71. : String(s.c_str())
  72. {
  73. }
  74. inline String(String const &s)
  75. : super((super const &)s)
  76. {
  77. }
  78. inline char &operator [](int n)
  79. {
  80. /* Allow n == count() because we might have reasonable reasons
  81. * to access that hidden null character. We cast to unsigned so
  82. * as to avoid a harmless message from the GCC optimiser. */
  83. ASSERT(n >= 0);
  84. ASSERT((unsigned)n <= (unsigned)count());
  85. return ((super &)*this)[n];
  86. }
  87. inline char const &operator [](int n) const
  88. {
  89. ASSERT(n >= 0);
  90. ASSERT((unsigned)n <= (unsigned)count());
  91. return ((super const &)*this)[n];
  92. }
  93. inline char &last()
  94. {
  95. ASSERT(count() > 0);
  96. return (*this)[count() - 1];
  97. }
  98. inline char const &last() const
  99. {
  100. ASSERT(count() > 0);
  101. return (*this)[count() - 1];
  102. }
  103. inline int count() const
  104. {
  105. return ((super const &)*this).count() - 1;
  106. }
  107. /* Return a C string */
  108. inline char const *C() const
  109. {
  110. return &(*this)[0];
  111. }
  112. /* Non-const version; make sure to not overflow the internal array */
  113. inline char *C()
  114. {
  115. return &(*this)[0];
  116. }
  117. /* Does not initialise the newly allocated characters */
  118. void resize(int item_count)
  119. {
  120. ASSERT(item_count >= 0);
  121. ((super &)*this).resize(item_count + 1);
  122. ((super &)*this).last() = '\0';
  123. }
  124. String sub(int start, int item_count = -1) const
  125. {
  126. ASSERT(start >= 0);
  127. if (start >= count())
  128. return String();
  129. if (item_count < 0 || item_count >= count() - start)
  130. item_count = count() - start;
  131. return String(&(*this)[start], item_count);
  132. }
  133. bool contains(String const &s) const
  134. {
  135. return index_of(s.C()) != INDEX_NONE;
  136. }
  137. int index_of(char token) const
  138. {
  139. using namespace std;
  140. char const *tmp = strchr(C(), token);
  141. return tmp ? int(tmp - C()) : INDEX_NONE;
  142. }
  143. int index_of(String const& token) const { return index_of(token.C()); }
  144. int index_of(char const* token) const
  145. {
  146. using namespace std;
  147. char const *tmp = strstr(C(), token);
  148. return tmp ? int(tmp - C()) : INDEX_NONE;
  149. }
  150. int last_index_of(char token) const
  151. {
  152. using namespace std;
  153. char const *tmp = strrchr(C(), token);
  154. return tmp ? int(tmp - C()) : INDEX_NONE;
  155. }
  156. int last_index_of(String const& token) const { return last_index_of(token.C()); }
  157. int last_index_of(char const* token) const
  158. {
  159. using namespace std;
  160. int token_len = (int)strlen(token);
  161. for (int i = count() - token_len; i >= 0; --i)
  162. if (strstr(C() + i, token))
  163. return i;
  164. return -1;
  165. }
  166. int count_occurence(String const& token) const { return last_index_of(token.C()); }
  167. int count_occurence(char const* token) const
  168. {
  169. int count = 0;
  170. const char *match = strstr(C(), token);
  171. while (match)
  172. {
  173. count++;
  174. match = strstr(match + 1, token);
  175. }
  176. return count;
  177. }
  178. int replace(char const old_token, char const new_token,
  179. bool all_occurrences = false)
  180. {
  181. using namespace std;
  182. int res = 0;
  183. char *tmp = NULL;
  184. while ((tmp = strrchr(C(), old_token)))
  185. {
  186. *tmp = new_token;
  187. res++;
  188. if (!all_occurrences)
  189. break;
  190. }
  191. return res;
  192. }
  193. inline String& to_lower()
  194. {
  195. String ret(*this);
  196. for (int i = 0; i < ret.count(); ++i)
  197. {
  198. if ('A' <= ret[i] && ret[i] <= 'Z')
  199. ret[i] += 'a' - 'A';
  200. }
  201. *this = ret;
  202. return *this;
  203. }
  204. inline String& to_upper()
  205. {
  206. String ret(*this);
  207. for (int i = 0; i < ret.count(); ++i)
  208. {
  209. if ('a' <= ret[i] && ret[i] <= 'z')
  210. ret[i] += 'A' - 'a';
  211. }
  212. *this = ret;
  213. return *this;
  214. }
  215. inline String& case_change(bool case_to_upper)
  216. {
  217. return case_to_upper ? to_upper() : to_lower();
  218. }
  219. bool starts_with(String const &s) const
  220. {
  221. using namespace std;
  222. return count() >= s.count()
  223. && memcmp(C(), s.C(), s.count()) == 0;
  224. }
  225. bool ends_with(String const &s) const
  226. {
  227. using namespace std;
  228. return count() >= s.count()
  229. && memcmp(C() + count() - s.count(), s.C(), s.count()) == 0;
  230. }
  231. array<String> split(char c = '\n') const
  232. {
  233. array<String> ret;
  234. for (int start = 0; start < m_count; )
  235. {
  236. char const *tmp = strchr(C() + start, c);
  237. if (!tmp)
  238. {
  239. ret.push(String(C() + start));
  240. break;
  241. }
  242. int size = int(tmp - C()) - start;
  243. ret.push(String(C() + start, size));
  244. start += size + 1;
  245. }
  246. return ret;
  247. }
  248. bool is_alpha() const
  249. {
  250. for (int i = 0; i < m_count; i++)
  251. if (m_data[i] != '\0' && (m_data[i] < '0' || '9' < m_data[i]))
  252. return false;
  253. return true;
  254. }
  255. inline String operator +(String const &s) const
  256. {
  257. String ret(*this);
  258. return ret += s;
  259. }
  260. inline String operator +(char c) const
  261. {
  262. String ret(*this);
  263. return ret += c;
  264. }
  265. inline String& operator +=(String const &s)
  266. {
  267. using namespace std;
  268. int old_count = count();
  269. resize(count() + s.count());
  270. memcpy(&(*this)[old_count], &s[0], count() - old_count);
  271. return *this;
  272. }
  273. inline String& operator +=(char c)
  274. {
  275. ((super &)*this).last() = c;
  276. ((super &)*this).push('\0');
  277. return *this;
  278. }
  279. inline bool operator ==(String const &s) const
  280. {
  281. using namespace std;
  282. return count() == s.count()
  283. && memcmp(C(), s.C(), count()) == 0;
  284. }
  285. inline bool operator !=(String const &s) const
  286. {
  287. return !(*this == s);
  288. }
  289. inline bool operator ==(char const* sz) const
  290. {
  291. /* We parse the C string twice because of strlen + memcmp
  292. * but it's probably still faster than doing it by hand. */
  293. using namespace std;
  294. int sz_len = (int)strlen(sz);
  295. return count() == sz_len
  296. && memcmp(C(), sz, sz_len) == 0;
  297. }
  298. inline bool operator !=(char const* sz) const
  299. {
  300. return !(*this == sz);
  301. }
  302. inline bool operator <(String const & s) const
  303. {
  304. using namespace std;
  305. int res = memcmp(C(), s.C(), count() < s.count() ? count() : s.count());
  306. if (!res)
  307. return count() < s.count();
  308. return res < 0;
  309. }
  310. };
  311. inline String operator +(char c, String const &s)
  312. {
  313. return String() + c + s;
  314. }
  315. inline String operator +(char const *sz, String const &s)
  316. {
  317. return String(sz) + s;
  318. }
  319. inline bool operator ==(char const* sz, String const &s)
  320. {
  321. return s == sz;
  322. }
  323. inline bool operator !=(char const* sz, String const &s)
  324. {
  325. return s != sz;
  326. }
  327. } /* namespace lol */