ArrayString.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. #ifndef CORE_STRING_H
  2. #define CORE_STRING_H
  3. #include <stdarg.h>
  4. #include <stdio.h>
  5. #include "math/Math.h"
  6. #include "utils/Check.h"
  7. #include "utils/Types.h"
  8. #include "utils/Utility.h"
  9. namespace Core {
  10. template<int N>
  11. class ArrayString final {
  12. public:
  13. int length;
  14. u32 hash;
  15. static constexpr int DATA_LENGTH =
  16. (N - Math::max(CORE_SIZE(length), CORE_SIZE(hash))) /
  17. CORE_SIZE(u32);
  18. static_assert(DATA_LENGTH > 0, "Size of array string too small");
  19. u32 data[static_cast<unsigned int>(DATA_LENGTH)];
  20. public:
  21. ArrayString() : length(0), hash(0) {
  22. data[0] = '\0';
  23. }
  24. bool operator==(const char* s) const {
  25. for(int i = 0; i < length; i++) {
  26. u32 u = 0;
  27. if(readUnicode(u, s) || data[i] != u) {
  28. return false;
  29. }
  30. }
  31. return read(s) == 0;
  32. }
  33. template<int L>
  34. bool operator==(const ArrayString<L>& other) const {
  35. if(length != other.length) {
  36. return false;
  37. }
  38. for(int i = 0; i < length; i++) {
  39. if(data[i] != other[i]) {
  40. return false;
  41. }
  42. }
  43. return true;
  44. }
  45. bool operator!=(const char* s) const {
  46. return !((*this) == s);
  47. }
  48. template<int L>
  49. bool operator!=(const ArrayString<L>& other) const {
  50. return !((*this) == other);
  51. }
  52. u32 operator[](int index) const {
  53. return data[index];
  54. }
  55. int getLength() const {
  56. return length;
  57. }
  58. constexpr int getCapacity() const {
  59. return DATA_LENGTH;
  60. }
  61. // returns true on error
  62. check_return bool append(char c) {
  63. if(c < 0) {
  64. return true;
  65. }
  66. return appendUnicode(static_cast<u32>(c));
  67. }
  68. // returns true on error
  69. check_return bool append(signed char c) {
  70. if(c < 0) {
  71. return true;
  72. }
  73. return appendUnicode(static_cast<u32>(c));
  74. }
  75. // returns true on error
  76. check_return bool append(unsigned char c) {
  77. return appendUnicode(c);
  78. }
  79. // returns true on error
  80. check_return bool append(const char* s) {
  81. while(true) {
  82. u32 u = 0;
  83. if(readUnicode(u, s)) {
  84. return true;
  85. } else if(u == 0) {
  86. return false;
  87. } else if(appendUnicode(u)) {
  88. return true;
  89. }
  90. }
  91. return false;
  92. }
  93. // returns true on error
  94. check_return bool append(const signed char* s) {
  95. return append(reinterpret_cast<const char*>(s));
  96. }
  97. // returns true on error
  98. check_return bool append(const unsigned char* s) {
  99. return append(reinterpret_cast<const char*>(s));
  100. }
  101. // returns true on error
  102. check_return bool append(signed short s) {
  103. return appendFormat("%hd", s);
  104. }
  105. // returns true on error
  106. check_return bool append(unsigned short s) {
  107. return appendFormat("%hu", s);
  108. }
  109. // returns true on error
  110. check_return bool append(signed int i) {
  111. return appendFormat("%d", i);
  112. }
  113. // returns true on error
  114. check_return bool append(unsigned int i) {
  115. return appendFormat("%u", i);
  116. }
  117. // returns true on error
  118. check_return bool append(signed long l) {
  119. return appendFormat("%ld", l);
  120. }
  121. // returns true on error
  122. check_return bool append(unsigned long l) {
  123. return appendFormat("%lu", l);
  124. }
  125. // returns true on error
  126. check_return bool append(signed long long ll) {
  127. return appendFormat("%lld", ll);
  128. }
  129. // returns true on error
  130. check_return bool append(unsigned long long ll) {
  131. return appendFormat("%llu", ll);
  132. }
  133. // returns true on error
  134. check_return bool append(float f) {
  135. return appendFormat("%.2f", static_cast<double>(f));
  136. }
  137. // returns true on error
  138. check_return bool append(double d) {
  139. return appendFormat("%.2f", d);
  140. }
  141. // returns true on error
  142. check_return bool append(long double ld) {
  143. return appendFormat("%.2Lf", ld);
  144. }
  145. // returns true on error
  146. check_return bool append(bool b) {
  147. return b ? append("true") : append("false");
  148. }
  149. // returns true on error
  150. check_return bool appendUnicode(u32 c) {
  151. if(length >= DATA_LENGTH) {
  152. return true;
  153. }
  154. data[length++] = c;
  155. addToHash(c);
  156. return false;
  157. }
  158. // returns true on error
  159. template<typename T>
  160. check_return bool append(const T& t) {
  161. return t.toString(*this);
  162. }
  163. // returns true on error
  164. template<int L>
  165. check_return bool toString(ArrayString<L>& s) const {
  166. int l = length; // length changes if &s == this
  167. for(int i = 0; i < l; i++) {
  168. if(s.appendUnicode(data[i])) {
  169. return true;
  170. }
  171. }
  172. return false;
  173. }
  174. void clear() {
  175. length = 0;
  176. hash = 0;
  177. data[0] = '\0';
  178. }
  179. u32 hashCode() const {
  180. return hash;
  181. }
  182. // returns true on error
  183. check_return bool print() const {
  184. for(int i = 0; i < length; i++) {
  185. u32 c = data[i];
  186. if(c < (1 << 7)) {
  187. if(putchar(static_cast<int>(c & 0x7F)) == EOF) {
  188. return true;
  189. }
  190. } else if(c < (1 << 11)) {
  191. if(printChar(c, 6, 0x1F, 0xC0) ||
  192. printChar(c, 0, 0x3F, 0x80)) {
  193. return true;
  194. }
  195. } else if(c < (1 << 16)) {
  196. if(printChar(c, 12, 0x0F, 0xE0) ||
  197. printChar(c, 6, 0x3F, 0x80) ||
  198. printChar(c, 0, 0x3F, 0x80)) {
  199. return true;
  200. }
  201. } else if(c < (1 << 21)) {
  202. if(printChar(c, 18, 0x07, 0xF0) ||
  203. printChar(c, 12, 0x3F, 0x80) ||
  204. printChar(c, 6, 0x3F, 0x80) ||
  205. printChar(c, 0, 0x3F, 0x80)) {
  206. return true;
  207. }
  208. }
  209. }
  210. return false;
  211. }
  212. // returns true on error
  213. check_return bool printLine() const {
  214. return print() || putchar('\n') == EOF;
  215. }
  216. // returns true on error
  217. template<typename... Args>
  218. check_return bool format(Args&&... args) {
  219. ArrayString s;
  220. if(formatBuffer(s, 0, Core::forward<Args>(args)...)) {
  221. return true;
  222. }
  223. *this = s;
  224. return false;
  225. }
  226. private:
  227. static bool printChar(u32 u, u32 shift, u32 a, u32 o) {
  228. return putchar(static_cast<int>(((u >> shift) & a) | o)) == EOF;
  229. }
  230. static u32 read(const char*& s) {
  231. if(*s == '\0') {
  232. return 0;
  233. }
  234. return static_cast<u32>(*(s++));
  235. }
  236. // returns true on error
  237. static bool readUnicode(u32& u, const char*& s) {
  238. u = read(s);
  239. if((u & 0x80) == 0) {
  240. return false;
  241. }
  242. if((u & 0xE0) == 0xC0) {
  243. u32 u2 = read(s);
  244. if(u2 == 0) {
  245. return true;
  246. }
  247. u = ((u & 0x1F) << 6) | (u2 & 0x3F);
  248. return false;
  249. } else if((u & 0xF0) == 0xE0) {
  250. u32 u2 = read(s);
  251. u32 u3 = read(s);
  252. if(u2 == 0 || u3 == 0) {
  253. return true;
  254. }
  255. u = ((u & 0xF) << 12) | ((u2 & 0x3F) << 6) | (u3 & 0x3F);
  256. return false;
  257. } else if((u & 0xF8) == 0xF0) {
  258. u32 u2 = read(s);
  259. u32 u3 = read(s);
  260. u32 u4 = read(s);
  261. if(u2 == 0 || u3 == 0 || u4 == 0) {
  262. return true;
  263. }
  264. u = ((u & 0x07) << 18) | ((u2 & 0x3F) << 12) |
  265. ((u3 & 0x3F) << 6) | (u4 & 0x3F);
  266. return false;
  267. }
  268. return true;
  269. }
  270. void addToHash(u32 u) {
  271. hash = static_cast<u32>(2120251889) * hash + static_cast<u32>(u);
  272. }
  273. // returns true on error
  274. template<typename T, typename... Args>
  275. check_return bool formatBuffer(ArrayString& s, int index, const T& t,
  276. Args&&... args) {
  277. while(index < length) {
  278. u32 u = data[index++];
  279. if(u == '#') {
  280. if(index >= length ||
  281. (index < length && data[index] != '#')) {
  282. break;
  283. }
  284. index++;
  285. }
  286. if(s.appendUnicode(u)) {
  287. return true;
  288. }
  289. }
  290. if(s.append(t)) {
  291. return true;
  292. }
  293. return formatBuffer(s, index, Core::forward<Args>(args)...);
  294. }
  295. // returns true on error
  296. check_return bool formatBuffer(ArrayString& s, int index) {
  297. while(index < length) {
  298. if(s.appendUnicode(data[index++])) {
  299. return true;
  300. }
  301. }
  302. return false;
  303. }
  304. // returns true on error
  305. check_format(2, 3) check_return
  306. bool appendFormat(const char* format, ...) {
  307. constexpr int BUFFER_SIZE = 64;
  308. char buffer[BUFFER_SIZE];
  309. va_list args;
  310. va_start(args, format);
  311. int written = vsnprintf(buffer, BUFFER_SIZE, format, args);
  312. va_end(args);
  313. return written >= BUFFER_SIZE ||
  314. append(static_cast<const char*>(buffer));
  315. }
  316. };
  317. }
  318. template<int N>
  319. bool operator==(const char* cs, const Core::ArrayString<N>& s) {
  320. return s == cs;
  321. }
  322. template<int N>
  323. bool operator!=(const char* cs, const Core::ArrayString<N>& s) {
  324. return s != cs;
  325. }
  326. #endif