ArrayString.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454
  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. ArrayString substring(int from, int to) const {
  259. from = Math::max(from, 0);
  260. to = Math::min(to, length - 1);
  261. ArrayString<N> s;
  262. for(int i = from; i <= to; i++) {
  263. (void)s.appendUnicode(data[i]);
  264. }
  265. return s;
  266. }
  267. ArrayString substring(int from = 0) const {
  268. return substring(from, length - 1);
  269. }
  270. template<int L1, int L2>
  271. bool replace(const ArrayString<L1>& search,
  272. const ArrayString<L2>& replace) {
  273. ArrayString<N> s;
  274. int i = 0;
  275. while(i < length) {
  276. if(startsWidth(search, i)) {
  277. if(s.append(replace)) {
  278. return true;
  279. }
  280. i += search.getLength();
  281. } else {
  282. if(s.appendUnicode(data[i])) {
  283. return true;
  284. }
  285. i++;
  286. }
  287. }
  288. *this = s;
  289. return false;
  290. }
  291. void replace(u32 search, u32 replace) {
  292. hash = 0;
  293. for(int i = 0; i < length; i++) {
  294. if(data[i] == search) {
  295. data[i] = replace;
  296. }
  297. addToHash(data[i]);
  298. }
  299. }
  300. private:
  301. // returns true on error and calls the error callback
  302. check_return static bool printChar(u32 u, u32 shift, u32 a, u32 o) {
  303. return Core::putChar(static_cast<int>(((u >> shift) & a) | o));
  304. }
  305. static u32 read(const char*& s) {
  306. if(*s == '\0') {
  307. return 0;
  308. }
  309. return static_cast<u32>(*(s++));
  310. }
  311. // returns true on error and calls the error callback
  312. static bool readUnicode(u32& u, const char*& s) {
  313. u = read(s);
  314. if((u & 0x80) == 0) {
  315. return false;
  316. }
  317. if((u & 0xE0) == 0xC0) {
  318. u32 u2 = read(s);
  319. if(u2 == 0) {
  320. return CORE_ERROR(Error::INVALID_CHAR);
  321. }
  322. u = ((u & 0x1F) << 6) | (u2 & 0x3F);
  323. return false;
  324. } else if((u & 0xF0) == 0xE0) {
  325. u32 u2 = read(s);
  326. u32 u3 = read(s);
  327. if(u2 == 0 || u3 == 0) {
  328. return CORE_ERROR(Error::INVALID_CHAR);
  329. }
  330. u = ((u & 0xF) << 12) | ((u2 & 0x3F) << 6) | (u3 & 0x3F);
  331. return false;
  332. } else if((u & 0xF8) == 0xF0) {
  333. u32 u2 = read(s);
  334. u32 u3 = read(s);
  335. u32 u4 = read(s);
  336. if(u2 == 0 || u3 == 0 || u4 == 0) {
  337. return CORE_ERROR(Error::INVALID_CHAR);
  338. }
  339. u = ((u & 0x07) << 18) | ((u2 & 0x3F) << 12) |
  340. ((u3 & 0x3F) << 6) | (u4 & 0x3F);
  341. return false;
  342. }
  343. return CORE_ERROR(Error::INVALID_CHAR);
  344. }
  345. void addToHash(u32 u) {
  346. hash = static_cast<u32>(2120251889) * hash + static_cast<u32>(u);
  347. }
  348. // returns true on error and calls the error callback
  349. template<typename T, typename... Args>
  350. check_return bool formatBuffer(ArrayString& s, int index, const T& t,
  351. Args&&... args) {
  352. while(index < length) {
  353. u32 u = data[index++];
  354. if(u == '#') {
  355. if(index >= length ||
  356. (index < length && data[index] != '#')) {
  357. break;
  358. }
  359. index++;
  360. }
  361. if(s.appendUnicode(u)) {
  362. return true;
  363. }
  364. }
  365. if(s.append(t)) {
  366. return true;
  367. }
  368. return formatBuffer(s, index, Core::forward<Args>(args)...);
  369. }
  370. // returns true on error and calls the error callback
  371. check_return bool formatBuffer(ArrayString& s, int index) {
  372. while(index < length) {
  373. if(s.appendUnicode(data[index++])) {
  374. return true;
  375. }
  376. }
  377. return false;
  378. }
  379. // returns true on error and calls the error callback
  380. template<typename T>
  381. check_return bool convertAppend(T t) {
  382. constexpr int BUFFER_SIZE = 64;
  383. char buffer[BUFFER_SIZE];
  384. if(Core::toString(t, buffer, BUFFER_SIZE)) {
  385. return true;
  386. }
  387. return append(static_cast<const char*>(buffer));
  388. }
  389. };
  390. }
  391. template<int N>
  392. bool operator==(const char* cs, const Core::ArrayString<N>& s) {
  393. return s == cs;
  394. }
  395. template<int N>
  396. bool operator!=(const char* cs, const Core::ArrayString<N>& s) {
  397. return s != cs;
  398. }
  399. #endif