String.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830
  1. #include "String.h"
  2. USING_NS_BF;
  3. //////////////////////////////////////////////////////////////////////////
  4. StringView::StringView(const StringImpl& str)
  5. {
  6. mPtr = str.GetPtr();
  7. mLength = str.mLength;
  8. }
  9. StringView::StringView(const StringImpl& str, int offset)
  10. {
  11. mPtr = str.GetPtr() + offset;
  12. mLength = str.mLength - offset;
  13. }
  14. StringView::StringView(const StringImpl& str, int offset, int length)
  15. {
  16. mPtr = str.GetPtr() + offset;
  17. mLength = length;
  18. }
  19. StringView& StringView::operator=(const StringImpl& str)
  20. {
  21. mPtr = str.GetPtr();
  22. mLength = str.mLength;
  23. return *this;
  24. }
  25. bool StringView::operator==(const StringImpl& strB) const
  26. {
  27. if (this->mLength != strB.mLength)
  28. return false;
  29. return strncmp(this->mPtr, strB.GetPtr(), this->mLength) == 0;
  30. }
  31. bool StringView::operator!=(const StringImpl& strB) const
  32. {
  33. if (this->mLength != strB.mLength)
  34. return true;
  35. return strncmp(this->mPtr, strB.GetPtr(), this->mLength) != 0;
  36. }
  37. intptr StringView::IndexOf(const StringView& subStr, bool ignoreCase) const
  38. {
  39. for (intptr ofs = 0; ofs <= mLength - subStr.mLength; ofs++)
  40. {
  41. if (String::Compare(*this, ofs, subStr, 0, subStr.mLength, ignoreCase) == 0)
  42. return ofs;
  43. }
  44. return -1;
  45. }
  46. intptr StringView::IndexOf(const StringView& subStr, int32 startIdx) const
  47. {
  48. return IndexOf(subStr, (int64)startIdx);
  49. }
  50. intptr StringView::IndexOf(const StringView& subStr, int64 startIdx) const
  51. {
  52. const char* ptr = mPtr;
  53. const char* subStrPtr = subStr.mPtr;
  54. for (intptr ofs = (intptr)startIdx; ofs <= (intptr)(mLength - subStr.mLength); ofs++)
  55. {
  56. if (strncmp(ptr + ofs, subStrPtr, subStr.mLength) == 0)
  57. return ofs;
  58. }
  59. return -1;
  60. }
  61. intptr StringView::IndexOf(char c, intptr startIdx) const
  62. {
  63. auto ptr = mPtr;
  64. for (intptr i = startIdx; i < mLength; i++)
  65. if (ptr[i] == c)
  66. return i;
  67. return -1;
  68. }
  69. intptr StringView::LastIndexOf(char c) const
  70. {
  71. auto ptr = mPtr;
  72. for (intptr i = mLength - 1; i >= 0; i--)
  73. if (ptr[i] == c)
  74. return i;
  75. return -1;
  76. }
  77. intptr StringView::LastIndexOf(char c, intptr startCheck) const
  78. {
  79. auto ptr = mPtr;
  80. for (intptr i = startCheck; i >= 0; i--)
  81. if (ptr[i] == c)
  82. return i;
  83. return -1;
  84. }
  85. String StringView::ToString() const
  86. {
  87. return String(this->mPtr, this->mLength);
  88. }
  89. void StringView::ToString(StringImpl& str) const
  90. {
  91. str.Append(mPtr, mLength);
  92. }
  93. //////////////////////////////////////////////////////////////////////////
  94. String Beefy::operator+(const StringImpl& lhs, const StringImpl& rhs)
  95. {
  96. String str;
  97. str.Reserve(lhs.mLength + rhs.mLength + 1);
  98. str.Append(lhs);
  99. str.Append(rhs);
  100. return str;
  101. }
  102. String Beefy::operator+(const StringImpl& lhs, const StringView& rhs)
  103. {
  104. String str;
  105. str.Reserve(lhs.mLength + rhs.mLength + 1);
  106. str.Append(lhs);
  107. str.Append(rhs);
  108. return str;
  109. }
  110. String Beefy::operator+(const StringImpl& lhs, const char* rhs)
  111. {
  112. String str;
  113. int rhsLen = (int)strlen(rhs);
  114. str.Reserve(lhs.mLength + rhsLen + 1);
  115. str.Append(lhs);
  116. str.Append(rhs, rhsLen);
  117. return str;
  118. }
  119. String Beefy::operator+(const StringImpl& lhs, char rhs)
  120. {
  121. String str;
  122. str.Reserve(lhs.mLength + 1 + 1);
  123. str.Append(lhs);
  124. str.Append(rhs);
  125. return str;
  126. }
  127. String Beefy::operator+(const char* lhs, const StringImpl& rhs)
  128. {
  129. String str;
  130. int lhsLen = (int)strlen(lhs);
  131. str.Reserve(rhs.mLength + lhsLen + 1);
  132. str.Append(lhs, lhsLen);
  133. str.Append(rhs);
  134. return str;
  135. }
  136. String Beefy::operator+(const char* lhs, const StringView& rhs)
  137. {
  138. String str;
  139. int lhsLen = (int)strlen(lhs);
  140. str.Reserve(rhs.mLength + lhsLen + 1);
  141. str.Append(lhs, lhsLen);
  142. str.Append(rhs);
  143. return str;
  144. }
  145. bool Beefy::operator==(const char* lhs, const StringImpl& rhs)
  146. {
  147. return rhs == lhs;
  148. }
  149. bool Beefy::operator!=(const char* lhs, const StringImpl& rhs)
  150. {
  151. return rhs != lhs;
  152. }
  153. // bool Beefy::operator==(const StringView& lhs, const StringImpl& rhs)
  154. // {
  155. // if (lhs.mLength != rhs.mLength)
  156. // return false;
  157. // return strncmp(lhs.mPtr, rhs.GetPtr(), lhs.mLength) == 0;
  158. // }
  159. //
  160. // bool Beefy::operator!=(const StringView& lhs, const StringImpl& rhs)
  161. // {
  162. // if (lhs.mLength != rhs.mLength)
  163. // return true;
  164. // return strncmp(lhs.mPtr, rhs.GetPtr(), lhs.mLength) != 0;
  165. // }
  166. //////////////////////////////////////////////////////////////////////////
  167. StringImpl::StringImpl(const StringView& str)
  168. {
  169. Init(str.mPtr, str.mLength);
  170. }
  171. void StringImpl::Reference(const char* str)
  172. {
  173. Reference(str, strlen(str));
  174. }
  175. void StringImpl::Reference(const char* str, intptr length)
  176. {
  177. if (IsDynAlloc())
  178. DeletePtr();
  179. mPtr = (char*)str;
  180. mLength = (int_strsize)length;
  181. mAllocSizeAndFlags = mLength | StrPtrFlag;
  182. }
  183. void StringImpl::Reference(const StringView& strView)
  184. {
  185. Reference(strView.mPtr, strView.mLength);
  186. }
  187. String StringImpl::CreateReference(const StringView& strView)
  188. {
  189. String str;
  190. str.Reference(strView);
  191. return str;
  192. }
  193. intptr StringImpl::CalcNewSize(intptr minSize)
  194. {
  195. // Grow factor is 1.5
  196. intptr bumpSize = GetAllocSize();
  197. bumpSize += bumpSize / 2;
  198. return (bumpSize > minSize) ? bumpSize : minSize;
  199. }
  200. void StringImpl::Realloc(intptr newSize, bool copyStr)
  201. {
  202. BF_ASSERT((uint32)newSize < 0x40000000);
  203. char* newPtr = AllocPtr(newSize);
  204. if (copyStr)
  205. memcpy(newPtr, GetPtr(), mLength + 1);
  206. if (IsDynAlloc())
  207. DeletePtr();
  208. mPtr = newPtr;
  209. mAllocSizeAndFlags = (uint32)newSize | DynAllocFlag | StrPtrFlag;
  210. }
  211. void StringImpl::Realloc(char* newPtr, intptr newSize)
  212. {
  213. BF_ASSERT((uint32)newSize < 0x40000000);
  214. // We purposely don't copy the terminating NULL here, it's assumed the caller will do so
  215. memcpy(newPtr, GetPtr(), mLength);
  216. if (IsDynAlloc())
  217. DeletePtr();
  218. mPtr = newPtr;
  219. mAllocSizeAndFlags = (uint32)newSize | DynAllocFlag | StrPtrFlag;
  220. }
  221. void StringImpl::Reserve(intptr newSize)
  222. {
  223. if (GetAllocSize() < newSize)
  224. Realloc(newSize, true);
  225. }
  226. bool StringImpl::EqualsHelper(const char * a, const char * b, intptr length)
  227. {
  228. return strncmp(a, b, length) == 0;
  229. }
  230. bool StringImpl::EqualsIgnoreCaseHelper(const char * a, const char * b, int length)
  231. {
  232. const char* curA = a;
  233. const char* curB = b;
  234. int curLength = length;
  235. /*Contract.Requires(strA != null);
  236. Contract.Requires(strB != null);
  237. Contract.EndContractBlock();*/
  238. while (curLength != 0)
  239. {
  240. int_strsize char8A = (int_strsize)*curA;
  241. int_strsize char8B = (int_strsize)*curB;
  242. //Contract.Assert((char8A | char8B) <= 0x7F, "strings have to be ASCII");
  243. // uppercase both char8s - notice that we need just one compare per char8
  244. if ((uint32)(char8A - 'a') <= (uint32)('z' - 'a')) char8A -= 0x20;
  245. if ((uint32)(char8B - 'a') <= (uint32)('z' - 'a')) char8B -= 0x20;
  246. //Return the (case-insensitive) difference between them.
  247. if (char8A != char8B)
  248. return false;
  249. // Next char8
  250. curA++; curB++;
  251. curLength--;
  252. }
  253. return true;
  254. }
  255. int StringImpl::CompareOrdinalIgnoreCaseHelper(const StringImpl & strA, const StringImpl & strB)
  256. {
  257. /*Contract.Requires(strA != null);
  258. Contract.Requires(strB != null);
  259. Contract.EndContractBlock();*/
  260. int_strsize length = BF_MIN(strA.mLength, strB.mLength);
  261. const char* a = strA.GetPtr();
  262. const char* b = strB.GetPtr();
  263. while (length != 0)
  264. {
  265. int_strsize char8A = (int_strsize)*a;
  266. int_strsize char8B = (int_strsize)*b;
  267. //Contract.Assert((char8A | char8B) <= 0x7F, "strings have to be ASCII");
  268. // uppercase both char8s - notice that we need just one compare per char8
  269. if ((uint32)(char8A - 'a') <= (uint32)('z' - 'a')) char8A -= 0x20;
  270. if ((uint32)(char8B - 'a') <= (uint32)('z' - 'a')) char8B -= 0x20;
  271. //Return the (case-insensitive) difference between them.
  272. if (char8A != char8B)
  273. return char8A - char8B;
  274. // Next char8
  275. a++; b++;
  276. length--;
  277. }
  278. return strA.mLength - strB.mLength;
  279. }
  280. intptr StringImpl::CompareOrdinalIgnoreCaseHelper(const char * strA, intptr lengthA, const char * strB, intptr lengthB)
  281. {
  282. const char* a = strA;
  283. const char* b = strB;
  284. intptr length = BF_MIN(lengthA, lengthB);
  285. while (length != 0)
  286. {
  287. int_strsize char8A = (int_strsize)*a;
  288. int_strsize char8B = (int_strsize)*b;
  289. //Contract.Assert((char8A | char8B) <= 0x7F, "strings have to be ASCII");
  290. // uppercase both char8s - notice that we need just one compare per char8
  291. if ((uint32)(char8A - 'a') <= (uint32)('z' - 'a')) char8A -= 0x20;
  292. if ((uint32)(char8B - 'a') <= (uint32)('z' - 'a')) char8B -= 0x20;
  293. //Return the (case-insensitive) difference between them.
  294. if (char8A != char8B)
  295. return char8A - char8B;
  296. // Next char8
  297. a++; b++;
  298. length--;
  299. }
  300. return lengthA - lengthB;
  301. }
  302. intptr StringImpl::CompareOrdinalIgnoreCaseHelper(const StringImpl & strA, intptr indexA, intptr lengthA, const StringImpl & strB, intptr indexB, intptr lengthB)
  303. {
  304. return CompareOrdinalIgnoreCaseHelper(strA.GetPtr() + indexA, lengthA, strB.GetPtr() + indexB, lengthB);
  305. }
  306. intptr StringImpl::CompareOrdinalHelper(const char * strA, intptr lengthA, const char * strB, intptr lengthB)
  307. {
  308. const char* a = strA;
  309. const char* b = strB;
  310. intptr length = BF_MIN(lengthA, lengthB);
  311. while (length != 0)
  312. {
  313. int_strsize char8A = (int_strsize)*a;
  314. int_strsize char8B = (int_strsize)*b;
  315. //Return the (case-insensitive) difference between them.
  316. if (char8A != char8B)
  317. return char8A - char8B;
  318. // Next char8
  319. a++; b++;
  320. length--;
  321. }
  322. return lengthA - lengthB;
  323. }
  324. intptr StringImpl::CompareOrdinalHelper(const StringImpl & strA, intptr indexA, intptr lengthA, const StringImpl & strB, intptr indexB, intptr lengthB)
  325. {
  326. return CompareOrdinalHelper(strA.GetPtr() + indexA, lengthA, strB.GetPtr() + indexB, lengthB);
  327. }
  328. void StringImpl::Append(const char* appendPtr)
  329. {
  330. Append(appendPtr, (int)strlen(appendPtr));
  331. }
  332. void StringImpl::Append(const char* appendPtr, intptr length)
  333. {
  334. intptr newCurrentIndex = mLength + length;
  335. char* ptr;
  336. if (newCurrentIndex >= GetAllocSize())
  337. {
  338. // This handles appending to ourselves, we invalidate 'ptr' after calling Realloc
  339. intptr newSize = CalcNewSize(newCurrentIndex + 1);
  340. char* newPtr = AllocPtr(newSize);
  341. memcpy(newPtr + mLength, appendPtr, length);
  342. Realloc(newPtr, newSize);
  343. ptr = newPtr;
  344. }
  345. else
  346. {
  347. ptr = GetMutablePtr();
  348. memcpy(ptr + mLength, appendPtr, length);
  349. }
  350. mLength = (int_strsize)newCurrentIndex;
  351. ptr[mLength] = 0;
  352. }
  353. void StringImpl::Append(const StringView& value)
  354. {
  355. //Contract.Ensures(Contract.Result<String>() != null);
  356. Append(value.mPtr, value.mLength);
  357. }
  358. void StringImpl::Append(const StringImpl& value)
  359. {
  360. //Contract.Ensures(Contract.Result<String>() != null);
  361. Append(value.GetPtr(), value.mLength);
  362. }
  363. void StringImpl::Append(const StringImpl& str, const StringImpl& str2)
  364. {
  365. Append(str.GetPtr(), str.mLength);
  366. Append(str2.GetPtr(), str2.mLength);
  367. }
  368. void StringImpl::Append(const StringImpl& str, const StringImpl& str2, const StringImpl& str3)
  369. {
  370. Append(str.GetPtr(), str.mLength);
  371. Append(str2.GetPtr(), str2.mLength);
  372. Append(str3.GetPtr(), str3.mLength);
  373. }
  374. void StringImpl::Append(char c, int count)
  375. {
  376. if (count == 0)
  377. return;
  378. if (mLength + count >= GetAllocSize())
  379. Realloc(CalcNewSize(mLength + count + 1));
  380. auto ptr = GetMutablePtr();
  381. for (int_strsize i = 0; i < count; i++)
  382. ptr[mLength++] = c;
  383. ptr[mLength] = 0;
  384. BF_ASSERT(mLength < GetAllocSize());
  385. }
  386. String StringImpl::Substring(intptr startIdx) const
  387. {
  388. BF_ASSERT((uintptr)startIdx <= (uintptr)mLength);
  389. return String(GetPtr() + startIdx, mLength - startIdx);
  390. }
  391. String StringImpl::Substring(intptr startIdx, intptr length) const
  392. {
  393. BF_ASSERT((startIdx >= 0) && (length >= 0) && (startIdx + length <= mLength));
  394. return String(GetPtr() + startIdx, length);
  395. }
  396. void StringImpl::Remove(intptr startIdx, intptr length)
  397. {
  398. BF_ASSERT((startIdx >= 0) && (length >= 0) && (startIdx + length <= mLength));
  399. intptr moveCount = mLength - startIdx - length;
  400. auto ptr = GetMutablePtr();
  401. if (moveCount > 0)
  402. memmove(ptr + startIdx, ptr + startIdx + length, mLength - startIdx - length);
  403. mLength -= (int_strsize)length;
  404. ptr[mLength] = 0;
  405. }
  406. void StringImpl::Remove(intptr char8Idx)
  407. {
  408. Remove(char8Idx, 1);
  409. }
  410. void StringImpl::RemoveToEnd(intptr startIdx)
  411. {
  412. Remove(startIdx, mLength - startIdx);
  413. }
  414. void StringImpl::Insert(intptr idx, const char* str, intptr length)
  415. {
  416. BF_ASSERT(idx >= 0);
  417. int_strsize newLength = mLength + (int_strsize)length;
  418. if (newLength >= GetAllocSize())
  419. {
  420. intptr newSize = max((int_strsize)GetAllocSize() * 2, newLength + 1);
  421. Realloc(newSize);
  422. }
  423. auto moveChars = mLength - idx;
  424. auto ptr = GetMutablePtr();
  425. if (moveChars > 0)
  426. memmove(ptr + idx + length, ptr + idx, moveChars);
  427. memcpy(ptr + idx, str, length);
  428. mLength = newLength;
  429. ptr[mLength] = 0;
  430. }
  431. void StringImpl::Insert(intptr idx, const StringImpl& addString)
  432. {
  433. BF_ASSERT(idx >= 0);
  434. int_strsize length = addString.mLength;
  435. int_strsize newLength = mLength + length;
  436. if (newLength >= GetAllocSize())
  437. {
  438. intptr newSize = max((int_strsize)GetAllocSize() * 2, newLength + 1);
  439. Realloc(newSize);
  440. }
  441. auto moveChars = mLength - idx;
  442. auto ptr = GetMutablePtr();
  443. if (moveChars > 0)
  444. memmove(ptr + idx + length, ptr + idx, moveChars);
  445. memcpy(ptr + idx, addString.GetPtr(), length);
  446. mLength = newLength;
  447. ptr[mLength] = 0;
  448. }
  449. void StringImpl::Insert(intptr idx, char c)
  450. {
  451. BF_ASSERT(idx >= 0);
  452. int_strsize newLength = mLength + 1;
  453. if (newLength >= GetAllocSize())
  454. {
  455. int newSize = max((int_strsize)GetAllocSize() * 2, newLength + 1);
  456. Realloc(newSize);
  457. }
  458. auto moveChars = mLength - idx;
  459. auto ptr = GetMutablePtr();
  460. if (moveChars > 0)
  461. memmove(ptr + idx + 1, ptr + idx, moveChars);
  462. ptr[idx] = c;
  463. mLength = newLength;
  464. ptr[mLength] = 0;
  465. }
  466. intptr StringImpl::Compare(const StringImpl & strA, intptr indexA, const StringImpl & strB, intptr indexB, intptr length, bool ignoreCase)
  467. {
  468. intptr lengthA = length;
  469. intptr lengthB = length;
  470. if (strA.GetLength() - indexA < lengthA)
  471. {
  472. lengthA = (strA.GetLength() - indexA);
  473. }
  474. if (strB.GetLength() - indexB < lengthB)
  475. {
  476. lengthB = (strB.GetLength() - indexB);
  477. }
  478. if (ignoreCase)
  479. return CompareOrdinalIgnoreCaseHelper(strA, indexA, lengthA, strB, indexB, lengthB);
  480. return CompareOrdinalHelper(strA, indexA, lengthA, strB, indexB, lengthB);
  481. }
  482. void StringImpl::ReplaceLargerHelper(const StringView& find, const StringView& replace)
  483. {
  484. Array<int> replaceEntries;
  485. int_strsize moveOffset = replace.mLength - find.mLength;
  486. for (int startIdx = 0; startIdx < mLength - find.mLength; startIdx++)
  487. {
  488. if (EqualsHelper(GetPtr() + startIdx, find.mPtr, find.mLength))
  489. {
  490. replaceEntries.Add(startIdx);
  491. startIdx += find.mLength - 1;
  492. }
  493. }
  494. if (replaceEntries.size() == 0)
  495. return;
  496. intptr destLength = mLength + moveOffset * replaceEntries.size();
  497. intptr needSize = destLength + 1;
  498. if (needSize > GetAllocSize())
  499. Realloc((int_strsize)needSize);
  500. auto replacePtr = replace.mPtr;
  501. auto ptr = GetMutablePtr();
  502. intptr lastDestStartIdx = destLength;
  503. for (intptr moveIdx = replaceEntries.size() - 1; moveIdx >= 0; moveIdx--)
  504. {
  505. intptr srcStartIdx = replaceEntries[moveIdx];
  506. intptr srcEndIdx = srcStartIdx + find.mLength;
  507. intptr destStartIdx = srcStartIdx + moveIdx * moveOffset;
  508. intptr destEndIdx = destStartIdx + replace.mLength;
  509. for (intptr i = lastDestStartIdx - destEndIdx - 1; i >= 0; i--)
  510. ptr[destEndIdx + i] = ptr[srcEndIdx + i];
  511. for (intptr i = 0; i < replace.mLength; i++)
  512. ptr[destStartIdx + i] = replacePtr[i];
  513. lastDestStartIdx = destStartIdx;
  514. }
  515. ptr[destLength] = 0;
  516. mLength = (int_strsize)destLength;
  517. }
  518. void StringImpl::Replace(const StringView& find, const StringView & replace)
  519. {
  520. if (replace.mLength > find.mLength)
  521. {
  522. ReplaceLargerHelper(find, replace);
  523. return;
  524. }
  525. auto ptr = GetMutablePtr();
  526. auto findPtr = find.mPtr;
  527. auto replacePtr = replace.mPtr;
  528. int_strsize inIdx = 0;
  529. int_strsize outIdx = 0;
  530. while (inIdx < mLength - find.mLength)
  531. {
  532. if (EqualsHelper(ptr + inIdx, findPtr, find.mLength))
  533. {
  534. for (int_strsize i = 0; i < replace.mLength; i++)
  535. ptr[outIdx++] = replacePtr[i];
  536. inIdx += find.mLength;
  537. }
  538. else if (inIdx == outIdx)
  539. {
  540. ++inIdx;
  541. ++outIdx;
  542. }
  543. else // We need to physically move char8acters once we've found an equal span
  544. {
  545. ptr[outIdx++] = ptr[inIdx++];
  546. }
  547. }
  548. while (inIdx < mLength)
  549. {
  550. if (inIdx == outIdx)
  551. {
  552. ++inIdx;
  553. ++outIdx;
  554. }
  555. else
  556. {
  557. ptr[outIdx++] = ptr[inIdx++];
  558. }
  559. }
  560. ptr[outIdx] = 0;
  561. mLength = outIdx;
  562. }
  563. void StringImpl::TrimEnd()
  564. {
  565. auto ptr = GetPtr();
  566. for (intptr i = mLength - 1; i >= 0; i--)
  567. {
  568. char c = ptr[i];
  569. if (!iswspace(c))
  570. {
  571. if (i < mLength - 1)
  572. RemoveToEnd(i + 1);
  573. return;
  574. }
  575. }
  576. Clear();
  577. }
  578. void StringImpl::TrimStart()
  579. {
  580. auto ptr = GetPtr();
  581. for (intptr i = 0; i < mLength; i++)
  582. {
  583. char c = ptr[i];
  584. if (!iswspace(c))
  585. {
  586. if (i > 0)
  587. Remove(0, i);
  588. return;
  589. }
  590. }
  591. Clear();
  592. }
  593. void StringImpl::Trim()
  594. {
  595. TrimStart();
  596. TrimEnd();
  597. }
  598. bool StringImpl::IsWhitespace() const
  599. {
  600. auto ptr = GetPtr();
  601. for (intptr i = 0; i < mLength; i++)
  602. if (!iswspace(ptr[i]))
  603. return false;
  604. return true;
  605. }
  606. bool StringImpl::HasMultibyteChars()
  607. {
  608. auto ptr = GetPtr();
  609. for (int i = 0; i < (int)mLength; i++)
  610. if ((uint8)ptr[i] >= (uint8)0x80)
  611. return true;
  612. return false;
  613. }
  614. intptr StringImpl::IndexOf(const StringView& subStr, bool ignoreCase) const
  615. {
  616. for (intptr ofs = 0; ofs <= mLength - subStr.mLength; ofs++)
  617. {
  618. if (Compare(*this, ofs, subStr, 0, subStr.mLength, ignoreCase) == 0)
  619. return ofs;
  620. }
  621. return -1;
  622. }
  623. intptr StringImpl::IndexOf(const StringView& subStr, int32 startIdx) const
  624. {
  625. return IndexOf(subStr, (int64)startIdx);
  626. }
  627. intptr StringImpl::IndexOf(const StringView& subStr, int64 startIdx) const
  628. {
  629. const char* ptr = GetPtr();
  630. const char* subStrPtr = subStr.mPtr;
  631. for (intptr ofs = (intptr)startIdx; ofs <= mLength - subStr.mLength; ofs++)
  632. {
  633. if (strncmp(ptr + ofs, subStrPtr, subStr.mLength) == 0)
  634. return ofs;
  635. }
  636. return -1;
  637. }
  638. intptr StringImpl::IndexOf(char c, intptr startIdx) const
  639. {
  640. auto ptr = GetPtr();
  641. for (intptr i = startIdx; i < mLength; i++)
  642. if (ptr[i] == c)
  643. return i;
  644. return -1;
  645. }
  646. intptr StringImpl::LastIndexOf(char c) const
  647. {
  648. auto ptr = GetPtr();
  649. for (intptr i = mLength - 1; i >= 0; i--)
  650. if (ptr[i] == c)
  651. return i;
  652. return -1;
  653. }
  654. intptr StringImpl::LastIndexOf(char c, intptr startCheck) const
  655. {
  656. auto ptr = GetPtr();
  657. for (intptr i = startCheck; i >= 0; i--)
  658. if (ptr[i] == c)
  659. return i;
  660. return -1;
  661. }
  662. //////////////////////////////////////////////////////////////////////////
  663. UTF16String::UTF16String()
  664. {
  665. }
  666. UTF16String::UTF16String(const wchar_t* str)
  667. {
  668. Set(str);
  669. }
  670. UTF16String::UTF16String(const wchar_t* str, int len)
  671. {
  672. Set(str, len);
  673. }
  674. void UTF16String::Set(const wchar_t* str, int len)
  675. {
  676. Clear();
  677. ResizeRaw(len + 1);
  678. memcpy(mVals, str, len * 2);
  679. mVals[len] = 0;
  680. }
  681. void UTF16String::Set(const wchar_t* str)
  682. {
  683. return Set(str, (int)wcslen(str));
  684. }
  685. const wchar_t* UTF16String::c_str() const
  686. {
  687. if (mVals == NULL)
  688. return L"";
  689. mVals[mSize - 1] = 0; // Re-terminate in case we modified the string
  690. return (wchar_t*)mVals;
  691. }
  692. size_t UTF16String::length() const
  693. {
  694. if (mSize == 0)
  695. return 0;
  696. return mSize - 1;
  697. }