Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

193 linhas
5.1 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2010–2023 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 "../features.h"
  20. #include <vector> // std::vector
  21. #include <string> // std::basic_string
  22. #include <algorithm> // std::transform
  23. #include <iterator> // std::back_inserter
  24. #include <cstdarg> // va_list
  25. #include <cctype> // size_t
  26. namespace lol
  27. {
  28. // Split a string along a single separator
  29. template<typename T>
  30. std::vector<std::basic_string<T>> split(std::basic_string<T> const &s,
  31. T sep = T('\n'))
  32. {
  33. std::vector<std::basic_string<T>> ret;
  34. size_t start = 0, end = 0;
  35. while ((end = s.find(sep, start)) != std::basic_string<T>::npos)
  36. {
  37. ret.push_back(s.substr(start, end - start));
  38. start = end + 1;
  39. }
  40. ret.push_back(s.substr(start));
  41. return ret;
  42. }
  43. // Split a string along multiple separator
  44. template<typename T>
  45. std::vector<std::basic_string<T>> split(std::basic_string<T> const &s,
  46. std::basic_string<T> const &seps)
  47. {
  48. std::vector<std::string> ret;
  49. size_t start = s.find_first_not_of(seps), end = 0;
  50. while ((end = s.find_first_of(seps, start)) != std::basic_string<T>::npos)
  51. {
  52. ret.push_back(s.substr(start, end - start));
  53. start = s.find_first_not_of(seps, end);
  54. }
  55. if (start != std::string::npos)
  56. ret.push_back(s.substr(start));
  57. return ret;
  58. }
  59. // Helper for template deduction
  60. template<typename T>
  61. std::vector<std::basic_string<T>> split(std::basic_string<T> const &s,
  62. T const *seps)
  63. {
  64. return split(s, std::basic_string<T>(seps));
  65. }
  66. // Check whether a string starts with a given substring
  67. template<typename T>
  68. bool starts_with(std::basic_string<T> const &s,
  69. std::basic_string<T> const &prefix)
  70. {
  71. return s.size() >= prefix.size() &&
  72. s.compare(0, prefix.size(), prefix) == 0;
  73. }
  74. template<typename T>
  75. bool starts_with(std::basic_string<T> const &s, T const *prefix)
  76. {
  77. return starts_with(s, std::basic_string<T>(prefix));
  78. }
  79. template<typename T>
  80. bool starts_with(T const *s, T const *suffix)
  81. {
  82. return starts_with(std::basic_string<T>(s), std::basic_string<T>(suffix));
  83. }
  84. // Check whether a string ends with a given substring
  85. template<typename T>
  86. bool ends_with(std::basic_string<T> const &s,
  87. std::basic_string<T> const &suffix)
  88. {
  89. return s.size() >= suffix.size() &&
  90. s.compare(s.size() - suffix.size(), suffix.size(), suffix) == 0;
  91. }
  92. template<typename T>
  93. bool ends_with(std::basic_string<T> const &s, T const *suffix)
  94. {
  95. return ends_with(s, std::basic_string<T>(suffix));
  96. }
  97. template<typename T>
  98. bool ends_with(T const *s, T const *suffix)
  99. {
  100. return ends_with(std::basic_string<T>(s), std::basic_string<T>(suffix));
  101. }
  102. // Convert a string to lowercase or uppercase
  103. template<typename T>
  104. std::basic_string<T> tolower(std::basic_string<T> const &s)
  105. {
  106. std::string ret;
  107. std::transform(s.begin(), s.end(), std::back_inserter(ret),
  108. [](T c){ return std::tolower(c); });
  109. return ret;
  110. }
  111. template<typename T>
  112. std::basic_string<T> tolower(T const *s)
  113. {
  114. return tolower(std::basic_string<T>(s));
  115. }
  116. template<typename T>
  117. std::basic_string<T> toupper(std::basic_string<T> const &s)
  118. {
  119. std::string ret;
  120. std::transform(s.begin(), s.end(), std::back_inserter(ret),
  121. [](T c){ return std::toupper(c); });
  122. return ret;
  123. }
  124. template<typename T>
  125. std::basic_string<T> toupper(T const *s)
  126. {
  127. return toupper(std::basic_string<T>(s));
  128. }
  129. // Format a string, printf-style
  130. template<typename T = char>
  131. std::basic_string<T> vformat(char const *fmt, va_list ap)
  132. {
  133. va_list ap2;
  134. #if defined va_copy || !defined _MSC_VER
  135. // Visual Studio 2010 does not support va_copy.
  136. va_copy(ap2, ap);
  137. #else
  138. ap2 = ap;
  139. #endif
  140. // vsnprintf() tells us how many characters we need, not counting
  141. // the terminating null character.
  142. size_t needed = vsnprintf(nullptr, 0, fmt, ap2);
  143. #if defined va_copy || !defined _MSC_VER
  144. // do not call va_end() if va_copy() wasn't called.
  145. va_end(ap2);
  146. #endif
  147. std::string ret;
  148. ret.resize(needed);
  149. vsnprintf(&ret[0], needed + 1, fmt, ap);
  150. return ret;
  151. }
  152. // XXX: we cheat by setting the argument time to char instead of T, because
  153. // I found no other way to use the printf attribute.
  154. template<typename T = char>
  155. std::basic_string<T> lol_attr_printf_format(1, 2) format(char const *fmt, ...)
  156. {
  157. va_list ap;
  158. va_start(ap, fmt);
  159. std::basic_string<T> ret = vformat(fmt, ap);
  160. va_end(ap);
  161. return ret;
  162. }
  163. } // namespace lol