ArrayString.h 11 KB

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