ArrayString.h 13 KB

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