You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

276 lines
6.4 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2010—2018 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 = '\n');
  24. /* Split a string along multiple separators */
  25. array<std::string> split(std::string const &s, std::string const &seps);
  26. /* Check whether a string starts or ends with a given substring */
  27. bool starts_with(std::string const &s, std::string const &prefix);
  28. bool ends_with(std::string const &s, std::string const &suffix);
  29. /* Convert a string to lowercase or uppercase */
  30. std::string tolower(std::string const &s);
  31. std::string toupper(std::string const &s);
  32. /* Format a string, printf-style */
  33. std::string format(char const *format, ...) LOL_ATTR_FORMAT(1, 2);
  34. std::string vformat(char const *format, va_list ap);
  35. } /* namespace lol */
  36. //
  37. // The deprecated String class
  38. // ---------------------------
  39. // A very simple String class, based on Array. The most interesting
  40. // thing in there was LOL_ATTR_NODISCARD but apart from that there was
  41. // no real point in using our own class. Phase this out.
  42. //
  43. #include <lol/base/assert.h>
  44. #include <lol/base/array.h>
  45. #include <cstring>
  46. #include <cstdarg>
  47. namespace lol
  48. {
  49. class LOL_ATTR_NODISCARD String : protected array<char>
  50. {
  51. private:
  52. typedef array<char> super;
  53. public:
  54. inline String()
  55. : super()
  56. {
  57. push('\0');
  58. }
  59. inline String(char const *str)
  60. : super()
  61. {
  62. using namespace std;
  63. ASSERT(str);
  64. resize((int)strlen(str));
  65. memcpy(&(*this)[0], str, count() + 1);
  66. }
  67. inline String(char const *str, int item_count)
  68. : super()
  69. {
  70. using namespace std;
  71. ASSERT(str);
  72. resize(item_count);
  73. memcpy(&(*this)[0], str, item_count);
  74. ((super &)*this)[item_count] = '\0';
  75. }
  76. /* Legacy constructor for std::string */
  77. inline String(std::string const &s)
  78. : String(s.c_str())
  79. {
  80. }
  81. inline String(String const &s)
  82. : super((super const &)s)
  83. {
  84. }
  85. inline char &operator [](int n)
  86. {
  87. /* Allow n == count() because we might have reasonable reasons
  88. * to access that hidden null character. We cast to unsigned so
  89. * as to avoid a harmless message from the GCC optimiser. */
  90. ASSERT(n >= 0);
  91. ASSERT((unsigned)n <= (unsigned)count());
  92. return ((super &)*this)[n];
  93. }
  94. inline char const &operator [](int n) const
  95. {
  96. ASSERT(n >= 0);
  97. ASSERT((unsigned)n <= (unsigned)count());
  98. return ((super const &)*this)[n];
  99. }
  100. inline char &last()
  101. {
  102. ASSERT(count() > 0);
  103. return (*this)[count() - 1];
  104. }
  105. inline char const &last() const
  106. {
  107. ASSERT(count() > 0);
  108. return (*this)[count() - 1];
  109. }
  110. inline int count() const
  111. {
  112. return ((super const &)*this).count() - 1;
  113. }
  114. /* Return a C string */
  115. inline char const *C() const
  116. {
  117. return &(*this)[0];
  118. }
  119. /* Non-const version; make sure to not overflow the internal array */
  120. inline char *C()
  121. {
  122. return &(*this)[0];
  123. }
  124. /* Does not initialise the newly allocated characters */
  125. void resize(int item_count)
  126. {
  127. ASSERT(item_count >= 0);
  128. ((super &)*this).resize(item_count + 1);
  129. ((super &)*this).last() = '\0';
  130. }
  131. String sub(int start, int item_count = -1) const
  132. {
  133. ASSERT(start >= 0);
  134. if (start >= count())
  135. return String();
  136. if (item_count < 0 || item_count >= count() - start)
  137. item_count = count() - start;
  138. return String(&(*this)[start], item_count);
  139. }
  140. int replace(char const old_token, char const new_token,
  141. bool all_occurrences = false)
  142. {
  143. using namespace std;
  144. int res = 0;
  145. char *tmp = NULL;
  146. while ((tmp = strrchr(C(), old_token)))
  147. {
  148. *tmp = new_token;
  149. res++;
  150. if (!all_occurrences)
  151. break;
  152. }
  153. return res;
  154. }
  155. inline String operator +(String const &s) const
  156. {
  157. String ret(*this);
  158. return ret += s;
  159. }
  160. inline String operator +(char c) const
  161. {
  162. String ret(*this);
  163. return ret += c;
  164. }
  165. inline String& operator +=(String const &s)
  166. {
  167. using namespace std;
  168. int old_count = count();
  169. resize(count() + s.count());
  170. memcpy(&(*this)[old_count], &s[0], count() - old_count);
  171. return *this;
  172. }
  173. inline String& operator +=(char c)
  174. {
  175. ((super &)*this).last() = c;
  176. ((super &)*this).push('\0');
  177. return *this;
  178. }
  179. inline bool operator ==(String const &s) const
  180. {
  181. using namespace std;
  182. return count() == s.count()
  183. && memcmp(C(), s.C(), count()) == 0;
  184. }
  185. inline bool operator !=(String const &s) const
  186. {
  187. return !(*this == s);
  188. }
  189. inline bool operator ==(char const* sz) const
  190. {
  191. /* We parse the C string twice because of strlen + memcmp
  192. * but it's probably still faster than doing it by hand. */
  193. using namespace std;
  194. int sz_len = (int)strlen(sz);
  195. return count() == sz_len
  196. && memcmp(C(), sz, sz_len) == 0;
  197. }
  198. inline bool operator !=(char const* sz) const
  199. {
  200. return !(*this == sz);
  201. }
  202. inline bool operator <(String const & s) const
  203. {
  204. using namespace std;
  205. int res = memcmp(C(), s.C(), count() < s.count() ? count() : s.count());
  206. if (!res)
  207. return count() < s.count();
  208. return res < 0;
  209. }
  210. };
  211. inline String operator +(char c, String const &s)
  212. {
  213. return String() + c + s;
  214. }
  215. inline String operator +(char const *sz, String const &s)
  216. {
  217. return String(sz) + s;
  218. }
  219. inline bool operator ==(char const* sz, String const &s)
  220. {
  221. return s == sz;
  222. }
  223. inline bool operator !=(char const* sz, String const &s)
  224. {
  225. return s != sz;
  226. }
  227. } /* namespace lol */