Nenhuma descrição
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

FixedStringMethods.cs 60KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231
  1. using System;
  2. using System.Diagnostics;
  3. using Unity.Collections.LowLevel.Unsafe;
  4. using Unity.Mathematics;
  5. namespace Unity.Collections
  6. {
  7. /// <summary>
  8. /// Provides extension methods for string, UnsafeText, and NativeText.
  9. /// </summary>
  10. [GenerateTestsForBurstCompatibility]
  11. public unsafe static partial class FixedStringMethods
  12. {
  13. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
  14. internal static void CheckSubstringInRange(int strLength, int startIndex, int length)
  15. {
  16. if (startIndex < 0)
  17. {
  18. throw new ArgumentOutOfRangeException($"startIndex {startIndex} must be positive.");
  19. }
  20. if (length < 0)
  21. {
  22. throw new ArgumentOutOfRangeException($"length {length} cannot be negative.");
  23. }
  24. if (startIndex > strLength)
  25. {
  26. throw new ArgumentOutOfRangeException($"startIndex {startIndex} cannot be larger than string length {strLength}.");
  27. }
  28. }
  29. /// <summary>
  30. /// Retrieves a substring of this string. The substring starts from a specific character index, and has a specified length.
  31. /// </summary>
  32. /// <typeparam name="T">A string type.</typeparam>
  33. /// <param name="str">A string to get the substring from.</param>
  34. /// <param name="startIndex">Start index of substring.</param>
  35. /// <param name="length">Length of substring.</param>
  36. /// <returns>A new string with length equivalent to `length` that begins at `startIndex`.</returns>
  37. /// <exception cref="ArgumentOutOfRangeException">Thrown if startIndex or length parameter is negative, or if startIndex is larger than the string length.</exception>
  38. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  39. public static T Substring<T>(ref this T str, int startIndex, int length)
  40. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  41. {
  42. CheckSubstringInRange(str.Length, startIndex, length);
  43. length = math.min(length, str.Length - startIndex);
  44. var substr = new T();
  45. substr.Append(str.GetUnsafePtr() + startIndex, length);
  46. return substr;
  47. }
  48. /// <summary>
  49. /// Retrieves a substring of this string. The substring starts from a specific character index and continues to the end of the string.
  50. /// </summary>
  51. /// <typeparam name="T">A string type.</typeparam>
  52. /// <param name="str">A string to get the substring from.</param>
  53. /// <param name="startIndex">Start index of substring.</param>
  54. /// <returns>A new string that begins at `startIndex`.</returns>
  55. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  56. public static T Substring<T>(ref this T str, int startIndex)
  57. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  58. {
  59. return str.Substring(startIndex, str.Length - startIndex);
  60. }
  61. /// <summary>
  62. /// Retrieves a substring from this string. The substring starts from a specific character index, and has a specified length. Allocates memory to the new substring with the allocator specified.
  63. /// </summary>
  64. /// <param name="str">A <see cref="NativeText"/> string to get the substring from.</param>
  65. /// <param name="startIndex">Start index of substring.</param>
  66. /// <param name="length">Length of substring.</param>
  67. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  68. /// <returns>A `NativeText` string with a length equivalent to `length` that starts at `startIndex` and an allocator type of `allocator`.</returns>
  69. /// <exception cref="ArgumentOutOfRangeException">Thrown if startIndex or length parameter is negative, or if startIndex is larger than string length.</exception>
  70. public static NativeText Substring(ref this NativeText str, int startIndex, int length, AllocatorManager.AllocatorHandle allocator)
  71. {
  72. CheckSubstringInRange(str.Length, startIndex, length);
  73. length = math.min(length, str.Length - startIndex);
  74. var substr = new NativeText(length, allocator);
  75. substr.Append(str.GetUnsafePtr() + startIndex, length);
  76. return substr;
  77. }
  78. /// <summary>
  79. /// Retrieves a substring of this string. The substring starts from a specific character index and continues to the end of the string. Allocates memory to the new substring with the allocator specified.
  80. /// </summary>
  81. /// <param name="str">A <see cref="NativeText"/> string to get the substring from.</param>
  82. /// <param name="startIndex">Start index of substring.</param>
  83. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  84. /// <returns>A NativeText string that begins at `startIndex` and has an allocator of type `allocator`.</returns>
  85. public static NativeText Substring(ref this NativeText str, int startIndex, AllocatorManager.AllocatorHandle allocator)
  86. {
  87. return str.Substring(startIndex, str.Length - startIndex);
  88. }
  89. /// <summary>
  90. /// Retrieves a substring of this string. The substring starts from a specific character index, and has a specified length. The new substring has the same allocator as the string.
  91. /// </summary>
  92. /// <param name="str">A <see cref="NativeText"/> string to get the substring from.</param>
  93. /// <param name="startIndex">Start index of substring.</param>
  94. /// <param name="length">Length of substring.</param>
  95. /// <returns>A NativeText string that has length equivalent to `length` and begins at `startIndex`.</returns>
  96. /// <exception cref="ArgumentOutOfRangeException">Thrown if startIndex or length parameter is negative, or if startIndex is larger than string length.</exception>
  97. public static NativeText Substring(ref this NativeText str, int startIndex, int length)
  98. {
  99. return str.Substring(startIndex, length, str.m_Data->m_UntypedListData.Allocator);
  100. }
  101. /// <summary>
  102. /// Retrieves a substring of this string. The substring starts from a specific character index and continues to the end of the string. The new substring has the same allocator as the string.
  103. /// </summary>
  104. /// <param name="str">A <see cref="NativeText"/> to get the substring from.</param>
  105. /// <param name="startIndex">Start index of substring.</param>
  106. /// <returns>A NativeText string that begins at `startIndex`.</returns>
  107. public static NativeText Substring(ref this NativeText str, int startIndex)
  108. {
  109. return str.Substring(startIndex, str.Length - startIndex);
  110. }
  111. /// <summary>
  112. /// Returns the index of the first occurrence of a single Unicode rune in this string.
  113. /// </summary>
  114. /// <typeparam name="T">A string type.</typeparam>
  115. /// <param name="fs">A string to search.</param>
  116. /// <param name="rune">A single UTF-8 Unicode Rune to search for within this string.</param>
  117. /// <returns>The index of the first occurrence of the byte sequence in this string. Returns -1 if no occurrence is found.</returns>
  118. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  119. public static int IndexOf<T>(ref this T fs, Unicode.Rune rune)
  120. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  121. {
  122. var dstLen = fs.Length;
  123. int index = 0;
  124. while(index < dstLen)
  125. {
  126. int tempIndex = index;
  127. var runeAtIndex = Read(ref fs, ref tempIndex);
  128. if (runeAtIndex.value == rune.value)
  129. {
  130. return index;
  131. }
  132. index = tempIndex;
  133. }
  134. return -1;
  135. }
  136. /// <summary>
  137. /// Returns the index of the first occurrence of a byte sequence in this string.
  138. /// </summary>
  139. /// <typeparam name="T">A string type.</typeparam>
  140. /// <param name="fs">A string to search.</param>
  141. /// <param name="bytes">A byte sequence to search for within this string.</param>
  142. /// <param name="bytesLen">The number of bytes in the byte sequence.</param>
  143. /// <returns>The index of the first occurrence of the byte sequence in this string. Returns -1 if no occurrence is found.</returns>
  144. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  145. public static int IndexOf<T>(ref this T fs, byte* bytes, int bytesLen)
  146. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  147. {
  148. var dst = fs.GetUnsafePtr();
  149. var dstLen = fs.Length;
  150. for (var i = 0; i <= dstLen - bytesLen; ++i)
  151. {
  152. for (var j = 0; j < bytesLen; ++j)
  153. if (dst[i + j] != bytes[j])
  154. goto end_of_loop;
  155. return i;
  156. end_of_loop : {}
  157. }
  158. return -1;
  159. }
  160. /// <summary>
  161. /// Returns the index of the first occurrence of a byte sequence within a subrange of this string.
  162. /// </summary>
  163. /// <typeparam name="T">A string type.</typeparam>
  164. /// <param name="fs">A string to search.</param>
  165. /// <param name="bytes">A byte sequence to search for within this string.</param>
  166. /// <param name="bytesLen">The number of bytes in the byte sequence.</param>
  167. /// <param name="startIndex">The first index in this string to consider as the first byte of the byte sequence.</param>
  168. /// <param name="distance">The last index in this string to consider as the first byte of the byte sequence.</param>
  169. /// <returns>The index of the first occurrence of the byte sequence in this string. Returns -1 if no occurrence is found.</returns>
  170. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  171. public static int IndexOf<T>(ref this T fs, byte* bytes, int bytesLen, int startIndex, int distance = Int32.MaxValue)
  172. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  173. {
  174. var dst = fs.GetUnsafePtr();
  175. var dstLen = fs.Length;
  176. var searchrange = Math.Min(distance - 1, dstLen - bytesLen);
  177. for (var i = startIndex; i <= searchrange; ++i)
  178. {
  179. for (var j = 0; j < bytesLen; ++j)
  180. if (dst[i + j] != bytes[j])
  181. goto end_of_loop;
  182. return i;
  183. end_of_loop : {}
  184. }
  185. return -1;
  186. }
  187. /// <summary>
  188. /// Returns the index of the first occurrence of a substring within this string.
  189. /// </summary>
  190. /// <typeparam name="T">A string type.</typeparam>
  191. /// <typeparam name="T2">A string type.</typeparam>
  192. /// <param name="fs">A string to search.</param>
  193. /// <param name="other">A substring to search for within this string.</param>
  194. /// <returns>The index of the first occurrence of the second string within this string. Returns -1 if no occurrence is found.</returns>
  195. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
  196. public static int IndexOf<T,T2>(ref this T fs, in T2 other)
  197. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  198. where T2 : unmanaged, INativeList<byte>, IUTF8Bytes
  199. {
  200. ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
  201. return fs.IndexOf(oref.GetUnsafePtr(), oref.Length);
  202. }
  203. /// <summary>
  204. /// Returns the index of the first occurrence of a substring within a subrange of this string.
  205. /// </summary>
  206. /// <typeparam name="T">A string type.</typeparam>
  207. /// <typeparam name="T2">A string type.</typeparam>
  208. /// <param name="fs">A string to search.</param>
  209. /// <param name="other">A substring to search for within this string.</param>
  210. /// <param name="startIndex">The first index in this string to consider as an occurrence of the second string.</param>
  211. /// <param name="distance">The last index in this string to consider as an occurrence of the second string.</param>
  212. /// <returns>The index of the first occurrence of the substring within this string. Returns -1 if no occurrence is found.</returns>
  213. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
  214. public static int IndexOf<T,T2>(ref this T fs, in T2 other, int startIndex, int distance = Int32.MaxValue)
  215. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  216. where T2 : unmanaged, INativeList<byte>, IUTF8Bytes
  217. {
  218. ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
  219. return fs.IndexOf(oref.GetUnsafePtr(), oref.Length, startIndex, distance);
  220. }
  221. /// <summary>
  222. /// Returns true if a given substring occurs within this string.
  223. /// </summary>
  224. /// <typeparam name="T">A string type.</typeparam>
  225. /// <typeparam name="T2">A string type.</typeparam>
  226. /// <param name="fs">A string to search.</param>
  227. /// <param name="other">A substring to search for within this string.</param>
  228. /// <returns>True if the substring occurs within this string.</returns>
  229. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
  230. public static bool Contains<T,T2>(ref this T fs, in T2 other)
  231. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  232. where T2 : unmanaged, INativeList<byte>, IUTF8Bytes
  233. {
  234. return fs.IndexOf(in other) != -1;
  235. }
  236. /// <summary>
  237. /// Returns the index of the last occurrence of a single Unicode rune within this string.
  238. /// </summary>
  239. /// <typeparam name="T">A string type.</typeparam>
  240. /// <param name="fs">A string to search.</param>
  241. /// <param name="rune">A single Unicode.Rune to search for within this string.</param>
  242. /// <returns>The index of the last occurrence of the byte sequence within this string. Returns -1 if no occurrence is found.</returns>
  243. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  244. public static int LastIndexOf<T>(ref this T fs, Unicode.Rune rune)
  245. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  246. {
  247. if (Unicode.IsValidCodePoint(rune.value))
  248. {
  249. var dstLen = fs.Length;
  250. for (var i = dstLen - 1; i >= 0; --i)
  251. {
  252. var runeAtIndex = Peek(ref fs, i);
  253. if (Unicode.IsValidCodePoint(runeAtIndex.value) && runeAtIndex.value == rune.value)
  254. {
  255. return i;
  256. }
  257. }
  258. }
  259. return -1;
  260. }
  261. /// <summary>
  262. /// Returns the index of the last occurrence of a byte sequence within this string.
  263. /// </summary>
  264. /// <typeparam name="T">A string type.</typeparam>
  265. /// <param name="fs">A string to search.</param>
  266. /// <param name="bytes">A byte sequence to search for within this string.</param>
  267. /// <param name="bytesLen">The number of bytes in the byte sequence.</param>
  268. /// <returns>The index of the last occurrence of the byte sequence within this string. Returns -1 if no occurrence is found.</returns>
  269. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  270. public static int LastIndexOf<T>(ref this T fs, byte* bytes, int bytesLen)
  271. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  272. {
  273. var dst = fs.GetUnsafePtr();
  274. var dstLen = fs.Length;
  275. for (var i = dstLen - bytesLen; i >= 0; --i)
  276. {
  277. for (var j = 0; j < bytesLen; ++j)
  278. if (dst[i + j] != bytes[j])
  279. goto end_of_loop;
  280. return i;
  281. end_of_loop : {}
  282. }
  283. return -1;
  284. }
  285. /// <summary>
  286. /// Returns the index of the last occurrence of a byte sequence within a subrange of this string.
  287. /// </summary>
  288. /// <typeparam name="T">A string type.</typeparam>
  289. /// <param name="fs">A string to search.</param>
  290. /// <param name="bytes">A byte sequence to search for within this string.</param>
  291. /// <param name="bytesLen">The number of bytes in the byte sequence.</param>
  292. /// <param name="startIndex">The smallest index in this string to consider as the first byte of the byte sequence.</param>
  293. /// <param name="distance">The greatest index in this string to consider as the first byte of the byte sequence.</param>
  294. /// <returns>The index of the last occurrence of the byte sequence within this string. Returns -1 if no occurrences found.</returns>
  295. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  296. public static int LastIndexOf<T>(ref this T fs, byte* bytes, int bytesLen, int startIndex, int distance = int.MaxValue)
  297. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  298. {
  299. var dst = fs.GetUnsafePtr();
  300. var dstLen = fs.Length;
  301. startIndex = Math.Min(dstLen - bytesLen, startIndex);
  302. var searchrange = Math.Max(0, startIndex - distance);
  303. for (var i = startIndex; i >= searchrange; --i)
  304. {
  305. for (var j = 0; j < bytesLen; ++j)
  306. if (dst[i + j] != bytes[j])
  307. goto end_of_loop;
  308. return i;
  309. end_of_loop : {}
  310. }
  311. return -1;
  312. }
  313. /// <summary>
  314. /// Returns the index of the last occurrence of a substring within this string.
  315. /// </summary>
  316. /// <typeparam name="T">A string type.</typeparam>
  317. /// <typeparam name="T2">A string type.</typeparam>
  318. /// <param name="fs">A string to search.</param>
  319. /// <param name="other">A substring to search for in the this string.</param>
  320. /// <returns>The index of the last occurrence of the substring within this string. Returns -1 if no occurrence is found.</returns>
  321. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
  322. public static int LastIndexOf<T,T2>(ref this T fs, in T2 other)
  323. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  324. where T2 : unmanaged, INativeList<byte>, IUTF8Bytes
  325. {
  326. ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
  327. return fs.LastIndexOf(oref.GetUnsafePtr(), oref.Length);
  328. }
  329. /// <summary>
  330. /// Returns the index of the last occurrence of a substring within a subrange of this string.
  331. /// </summary>
  332. /// <typeparam name="T">A string type.</typeparam>
  333. /// <typeparam name="T2">A string type.</typeparam>
  334. /// <param name="fs">A string to search.</param>
  335. /// <param name="other">A substring to search for within this string.</param>
  336. /// <param name="startIndex">The greatest index in this string to consider as an occurrence of the substring.</param>
  337. /// <param name="distance">The smallest index in this string to consider as an occurrence of the substring.</param>
  338. /// <returns>the index of the last occurrence of the substring within the first string. Returns -1 if no occurrence is found.</returns>
  339. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
  340. public static int LastIndexOf<T,T2>(ref this T fs, in T2 other, int startIndex, int distance = Int32.MaxValue)
  341. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  342. where T2 : unmanaged, INativeList<byte>, IUTF8Bytes
  343. {
  344. ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
  345. return fs.LastIndexOf(oref.GetUnsafePtr(), oref.Length, startIndex, distance);
  346. }
  347. /// <summary>
  348. /// Returns the sort position of this string relative to a byte sequence.
  349. /// </summary>
  350. /// <typeparam name="T">A string type.</typeparam>
  351. /// <param name="fs">A string to compare.</param>
  352. /// <param name="bytes">A byte sequence to compare.</param>
  353. /// <param name="bytesLen">The number of bytes in the byte sequence.</param>
  354. /// <returns>A number denoting the sort position of this string relative to the byte sequence:
  355. ///
  356. /// 0 denotes that this string and byte sequence have the same sort position.<br/>
  357. /// -1 denotes that this string should be sorted to precede the byte sequence.<br/>
  358. /// +1 denotes that this string should be sorted to follow the byte sequence.<br/>
  359. /// </returns>
  360. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  361. public static int CompareTo<T>(ref this T fs, byte* bytes, int bytesLen)
  362. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  363. {
  364. var a = fs.GetUnsafePtr();
  365. var aa = fs.Length;
  366. int chars = aa < bytesLen ? aa : bytesLen;
  367. for (var i = 0; i < chars; ++i)
  368. {
  369. if (a[i] < bytes[i])
  370. return -1;
  371. if (a[i] > bytes[i])
  372. return 1;
  373. }
  374. if (aa < bytesLen)
  375. return -1;
  376. if (aa > bytesLen)
  377. return 1;
  378. return 0;
  379. }
  380. /// <summary>
  381. /// Returns the sort position of this string relative to another.
  382. /// </summary>
  383. /// <typeparam name="T">A string type.</typeparam>
  384. /// <typeparam name="T2">A string type.</typeparam>
  385. /// <param name="fs">A string to compare.</param>
  386. /// <param name="other">Another string to compare.</param>
  387. /// <returns>A number denoting the relative sort position of the strings:
  388. ///
  389. /// 0 denotes that the strings have the same sort position.<br/>
  390. /// -1 denotes that this string should be sorted to precede the other.<br/>
  391. /// +1 denotes that this first string should be sorted to follow the other.<br/>
  392. /// </returns>
  393. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
  394. public static int CompareTo<T,T2>(ref this T fs, in T2 other)
  395. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  396. where T2 : unmanaged, INativeList<byte>, IUTF8Bytes
  397. {
  398. ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
  399. return fs.CompareTo(oref.GetUnsafePtr(), oref.Length);
  400. }
  401. /// <summary>
  402. /// Returns true if this string and a byte sequence are equal (meaning they have the same length and content).
  403. /// </summary>
  404. /// <typeparam name="T">A string type.</typeparam>
  405. /// <param name="fs">A string to compare for equality.</param>
  406. /// <param name="bytes">A sequence of bytes to compare for equality.</param>
  407. /// <param name="bytesLen">The number of bytes in the byte sequence.</param>
  408. /// <returns>True if this string and the byte sequence have the same length and if this string's character bytes match the byte sequence.</returns>
  409. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  410. public static bool Equals<T>(ref this T fs, byte* bytes, int bytesLen)
  411. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  412. {
  413. var a = fs.GetUnsafePtr();
  414. var aa = fs.Length;
  415. if (aa != bytesLen)
  416. return false;
  417. if (a == bytes)
  418. return true;
  419. return fs.CompareTo(bytes, bytesLen) == 0;
  420. }
  421. /// <summary>
  422. /// Returns true if this string is equal to another.
  423. /// </summary>
  424. /// <typeparam name="T">A string type.</typeparam>
  425. /// <typeparam name="T2">A string type.</typeparam>
  426. /// <param name="fs">A string to compare for equality.</param>
  427. /// <param name="other">Another string to compare for equality.</param>
  428. /// <returns>true if the two strings have the same length and matching content.</returns>
  429. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
  430. public static bool Equals<T,T2>(ref this T fs, in T2 other)
  431. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  432. where T2 : unmanaged, INativeList<byte>, IUTF8Bytes
  433. {
  434. ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
  435. return fs.Equals(oref.GetUnsafePtr(), oref.Length);
  436. }
  437. /// <summary>
  438. /// Returns the Unicode.Rune at an index of this string.
  439. /// </summary>
  440. /// <typeparam name="T">A string type.</typeparam>
  441. /// <param name="fs">A string to read.</param>
  442. /// <param name="index">A reference to an index in bytes (not characters).</param>
  443. /// <returns>The Unicode.Rune (character) which starts at the byte index. Returns Unicode.BadRune
  444. /// if the byte(s) at the index do not form a valid UTF-8 encoded character.</returns>
  445. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  446. public static Unicode.Rune Peek<T>(ref this T fs, int index)
  447. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  448. {
  449. if (index >= fs.Length)
  450. return Unicode.BadRune;
  451. Unicode.Utf8ToUcs(out var rune, fs.GetUnsafePtr(), ref index, fs.Capacity);
  452. return rune;
  453. }
  454. /// <summary>
  455. /// Returns the Unicode.Rune at an index of this string. Increments the index to the position of the next character.
  456. /// </summary>
  457. /// <typeparam name="T">A string type.</typeparam>
  458. /// <param name="fs">A string to read.</param>
  459. /// <param name="index">A reference to an index in bytes (not characters). Incremented by 1 to 4 depending upon the UTF-8 encoded size of the character read.</param>
  460. /// <returns>The character (as a `Unicode.Rune`) which starts at the byte index. Returns `Unicode.BadRune`
  461. /// if the byte(s) at the index do not form a valid UTF-8 encoded character.</returns>
  462. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  463. public static Unicode.Rune Read<T>(ref this T fs, ref int index)
  464. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  465. {
  466. if (index >= fs.Length)
  467. return Unicode.BadRune;
  468. Unicode.Utf8ToUcs(out var rune, fs.GetUnsafePtr(), ref index, fs.Capacity);
  469. return rune;
  470. }
  471. /// <summary>
  472. /// Writes a Unicode.Rune at an index of this string. Increments the index to the position of the next character.
  473. /// </summary>
  474. /// <typeparam name="T">A string type.</typeparam>
  475. /// <param name="fs">A string to modify.</param>
  476. /// <param name="index">A reference to an index in bytes (not characters). Incremented by 1 to 4 depending upon the UTF-8 encoded size of the character written.</param>
  477. /// <param name="rune">A rune to write to the string, encoded as UTF-8.</param>
  478. /// <returns>FormatError.None if successful. Returns FormatError.Overflow if the index is invalid or if there is not enough space to store the encoded rune.</returns>
  479. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  480. public static FormatError Write<T>(ref this T fs, ref int index, Unicode.Rune rune)
  481. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  482. {
  483. var err = Unicode.UcsToUtf8(fs.GetUnsafePtr(), ref index, fs.Capacity, rune);
  484. if (err != ConversionError.None)
  485. return FormatError.Overflow;
  486. return FormatError.None;
  487. }
  488. /// <summary>
  489. /// Returns a copy of this string as a managed string.
  490. /// </summary>
  491. /// <typeparam name="T">A string type.</typeparam>
  492. /// <param name="fs">A string to copy.</param>
  493. /// <returns>A copy of this string as a managed string.</returns>
  494. [ExcludeFromBurstCompatTesting("Returns managed string")]
  495. public static String ConvertToString<T>(ref this T fs)
  496. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  497. {
  498. var c = stackalloc char[fs.Length * 2];
  499. int length = 0;
  500. Unicode.Utf8ToUtf16(fs.GetUnsafePtr(), fs.Length, c, out length, fs.Length * 2);
  501. return new String(c, 0, length);
  502. }
  503. /// <summary>
  504. /// Returns a hash code of this string.
  505. /// </summary>
  506. /// <typeparam name="T">A string type.</typeparam>
  507. /// <param name="fs">A string to get a hash code of.</param>
  508. /// <returns>A hash code of this string.</returns>
  509. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  510. public static int ComputeHashCode<T>(ref this T fs)
  511. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  512. {
  513. return (int)CollectionHelper.Hash(fs.GetUnsafePtr(), fs.Length);
  514. }
  515. /// <summary>
  516. /// Returns the effective size in bytes of this string.
  517. /// </summary>
  518. /// <remarks>
  519. /// "Effective size" is `Length + 3`, the number of bytes you need to copy when serializing the string.
  520. /// (The plus 3 accounts for the null-terminator byte and the 2 bytes that store the Length).
  521. ///
  522. /// Useful for checking whether this string will fit in the space of a smaller string.
  523. /// </remarks>
  524. /// <typeparam name="T">A string type.</typeparam>
  525. /// <param name="fs">A string to get the effective size of.</param>
  526. /// <returns>The effective size in bytes of this string.</returns>
  527. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  528. public static int EffectiveSizeOf<T>(ref this T fs)
  529. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  530. {
  531. return sizeof(ushort) + fs.Length + 1;
  532. }
  533. /// <summary>
  534. /// Returns true if a given character occurs at the beginning of this string.
  535. /// </summary>
  536. /// <typeparam name="T">A string type.</typeparam>
  537. /// <param name="fs">A string to search.</param>
  538. /// <param name="rune">A character to search for within this string.</param>
  539. /// <returns>True if the character occurs at the beginning of this string.</returns>
  540. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  541. public static bool StartsWith<T>(ref this T fs, Unicode.Rune rune)
  542. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  543. {
  544. var len = rune.LengthInUtf8Bytes();
  545. return fs.Length >= len
  546. && 0 == UTF8ArrayUnsafeUtility.StrCmp(fs.GetUnsafePtr(), len, &rune, 1)
  547. ;
  548. }
  549. /// <summary>
  550. /// Returns true if a given substring occurs at the beginning of this string.
  551. /// </summary>
  552. /// <typeparam name="T">A string type.</typeparam>
  553. /// <typeparam name="U">A string type.</typeparam>
  554. /// <param name="fs">A string to search.</param>
  555. /// <param name="other">A substring to search for within this string.</param>
  556. /// <returns>True if the substring occurs at the beginning of this string.</returns>
  557. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
  558. public static bool StartsWith<T, U>(ref this T fs, in U other)
  559. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  560. where U : unmanaged, INativeList<byte>, IUTF8Bytes
  561. {
  562. var len = other.Length;
  563. return fs.Length >= len
  564. && 0 == UTF8ArrayUnsafeUtility.StrCmp(fs.GetUnsafePtr(), len, other.GetUnsafePtr(), len)
  565. ;
  566. }
  567. /// <summary>
  568. /// Returns true if a given character occurs at the end of this string.
  569. /// </summary>
  570. /// <typeparam name="T">A string type.</typeparam>
  571. /// <param name="fs">A string to search.</param>
  572. /// <param name="rune">A character to search for within this string.</param>
  573. /// <returns>True if the character occurs at the end of this string.</returns>
  574. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  575. public static bool EndsWith<T>(ref this T fs, Unicode.Rune rune)
  576. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  577. {
  578. var len = rune.LengthInUtf8Bytes();
  579. return fs.Length >= len
  580. && 0 == UTF8ArrayUnsafeUtility.StrCmp(fs.GetUnsafePtr() + fs.Length - len, len, &rune, 1)
  581. ;
  582. }
  583. /// <summary>
  584. /// Returns true if a given substring occurs at the end of this string.
  585. /// </summary>
  586. /// <typeparam name="T">A string type.</typeparam>
  587. /// <typeparam name="U">A string type.</typeparam>
  588. /// <param name="fs">A string to search.</param>
  589. /// <param name="other">A substring to search for within this string.</param>
  590. /// <returns>True if the substring occurs at the end of this string.</returns>
  591. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
  592. public static bool EndsWith<T, U>(ref this T fs, in U other)
  593. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  594. where U : unmanaged, INativeList<byte>, IUTF8Bytes
  595. {
  596. var len = other.Length;
  597. return fs.Length >= len
  598. && 0 == UTF8ArrayUnsafeUtility.StrCmp(fs.GetUnsafePtr() + fs.Length - len, len, other.GetUnsafePtr(), len)
  599. ;
  600. }
  601. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  602. internal static int TrimStartIndex<T>(ref this T fs)
  603. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  604. {
  605. var lengthInBytes = fs.Length;
  606. var ptr = fs.GetUnsafePtr();
  607. int index = 0;
  608. while (true)
  609. {
  610. var prev = index;
  611. var error = Unicode.Utf8ToUcs(out var rune, ptr, ref index, lengthInBytes);
  612. if (error != ConversionError.None
  613. || !rune.IsWhiteSpace())
  614. {
  615. index -= index - prev;
  616. break;
  617. }
  618. }
  619. return index;
  620. }
  621. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  622. internal static int TrimStartIndex<T>(ref this T fs, ReadOnlySpan<Unicode.Rune> trimRunes)
  623. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  624. {
  625. var lengthInBytes = fs.Length;
  626. var ptr = fs.GetUnsafePtr();
  627. int index = 0;
  628. while (true)
  629. {
  630. var prev = index;
  631. var error = Unicode.Utf8ToUcs(out var rune, ptr, ref index, lengthInBytes);
  632. var doTrim = false;
  633. for (int i = 0, num = trimRunes.Length; i < num && !doTrim; i++)
  634. {
  635. doTrim |= trimRunes[i] == rune;
  636. }
  637. if (error != ConversionError.None
  638. || !doTrim)
  639. {
  640. index -= index - prev;
  641. break;
  642. }
  643. }
  644. return index;
  645. }
  646. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  647. internal static int TrimEndIndex<T>(ref this T fs)
  648. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  649. {
  650. var lengthInBytes = fs.Length;
  651. var ptr = fs.GetUnsafePtr();
  652. int index = lengthInBytes;
  653. while (true)
  654. {
  655. var prev = index;
  656. var error = Unicode.Utf8ToUcsReverse(out var rune, ptr, ref index, lengthInBytes);
  657. if (error != ConversionError.None
  658. || !rune.IsWhiteSpace())
  659. {
  660. index += prev - index;
  661. break;
  662. }
  663. }
  664. return index;
  665. }
  666. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  667. internal static int TrimEndIndex<T>(ref this T fs, ReadOnlySpan<Unicode.Rune> trimRunes)
  668. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  669. {
  670. var lengthInBytes = fs.Length;
  671. var ptr = fs.GetUnsafePtr();
  672. int index = lengthInBytes;
  673. while (true)
  674. {
  675. var prev = index;
  676. var error = Unicode.Utf8ToUcsReverse(out var rune, ptr, ref index, lengthInBytes);
  677. var doTrim = false;
  678. for (int i = 0, num = trimRunes.Length; i < num && !doTrim; i++)
  679. {
  680. doTrim |= trimRunes[i] == rune;
  681. }
  682. if (error != ConversionError.None
  683. || !doTrim)
  684. {
  685. index += prev - index;
  686. break;
  687. }
  688. }
  689. return index;
  690. }
  691. /// <summary>
  692. /// Removes whitespace characters from begining of the string.
  693. /// </summary>
  694. /// <typeparam name="T">A string type.</typeparam>
  695. /// <param name="fs">A string to perform operation.</param>
  696. /// <returns>Returns instance of this string with whitespace characters removed from the start of the string.</returns>
  697. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  698. public static T TrimStart<T>(ref this T fs)
  699. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  700. {
  701. var index = fs.TrimStartIndex();
  702. var result = new T();
  703. result.Append(fs.GetUnsafePtr() + index, fs.Length - index);
  704. return result;
  705. }
  706. /// <summary>
  707. /// Removes whitespace characters from begining of the string.
  708. /// </summary>
  709. /// <param name="fs">A <see cref="UnsafeText"/> string to perform operation.</param>
  710. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  711. /// <returns>Returns instance of this string with whitespace characters removed from the start of the string.</returns>
  712. public static UnsafeText TrimStart(ref this UnsafeText fs, AllocatorManager.AllocatorHandle allocator)
  713. {
  714. var index = fs.TrimStartIndex();
  715. var lengthInBytes = fs.Length - index;
  716. var result = new UnsafeText(lengthInBytes, allocator);
  717. result.Append(fs.GetUnsafePtr() + index, lengthInBytes);
  718. return result;
  719. }
  720. /// <summary>
  721. /// Removes whitespace characters from begining of the string.
  722. /// </summary>
  723. /// <param name="fs">A <see cref="NativeText"/> string to perform operation.</param>
  724. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  725. /// <returns>Returns instance of this string with whitespace characters removed from the start of the string.</returns>
  726. public static NativeText TrimStart(ref this NativeText fs, AllocatorManager.AllocatorHandle allocator)
  727. {
  728. var index = fs.TrimStartIndex();
  729. var lengthInBytes = fs.Length - index;
  730. var result = new NativeText(lengthInBytes, allocator);
  731. result.Append(fs.GetUnsafePtr() + index, lengthInBytes);
  732. return result;
  733. }
  734. /// <summary>
  735. /// Removes specific characters from begining of the string.
  736. /// </summary>
  737. /// <typeparam name="T">A string type.</typeparam>
  738. /// <param name="fs">A string to perform operation.</param>
  739. /// <param name="trimRunes">Runes that should be trimmed.</param>
  740. /// <returns>Returns instance of this string with specific characters removed from the start of the string.</returns>
  741. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  742. public static T TrimStart<T>(ref this T fs, ReadOnlySpan<Unicode.Rune> trimRunes)
  743. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  744. {
  745. var index = fs.TrimStartIndex(trimRunes);
  746. var result = new T();
  747. result.Append(fs.GetUnsafePtr() + index, fs.Length - index);
  748. return result;
  749. }
  750. /// <summary>
  751. /// Removes specific characters characters from begining of the string.
  752. /// </summary>
  753. /// <param name="fs">A <see cref="UnsafeText"/> string to perform operation.</param>
  754. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  755. /// <param name="trimRunes">Runes that should be trimmed.</param>
  756. /// <returns>Returns instance of this string with specific characters removed from the start of the string.</returns>
  757. public static UnsafeText TrimStart(ref this UnsafeText fs, AllocatorManager.AllocatorHandle allocator, ReadOnlySpan<Unicode.Rune> trimRunes)
  758. {
  759. var index = fs.TrimStartIndex(trimRunes);
  760. var lengthInBytes = fs.Length - index;
  761. var result = new UnsafeText(lengthInBytes, allocator);
  762. result.Append(fs.GetUnsafePtr() + index, lengthInBytes);
  763. return result;
  764. }
  765. /// <summary>
  766. /// Removes specific characters from begining of the string.
  767. /// </summary>
  768. /// <param name="fs">A <see cref="NativeText"/> string to perform operation.</param>
  769. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  770. /// <param name="trimRunes">Runes that should be trimmed.</param>
  771. /// <returns>Returns instance of this string with specific characters removed from the start of the string.</returns>
  772. public static NativeText TrimStart(ref this NativeText fs, AllocatorManager.AllocatorHandle allocator, ReadOnlySpan<Unicode.Rune> trimRunes)
  773. {
  774. var index = fs.TrimStartIndex(trimRunes);
  775. var lengthInBytes = fs.Length - index;
  776. var result = new NativeText(lengthInBytes, allocator);
  777. result.Append(fs.GetUnsafePtr() + index, lengthInBytes);
  778. return result;
  779. }
  780. /// <summary>
  781. /// Removes whitespace characters from the end of the string.
  782. /// </summary>
  783. /// <typeparam name="T">A string type.</typeparam>
  784. /// <param name="fs">A string to perform operation.</param>
  785. /// <returns>Returns instance of this string with whitespace characters removed from the end of the string.</returns>
  786. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  787. public static T TrimEnd<T>(ref this T fs)
  788. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  789. {
  790. var index = fs.TrimEndIndex();
  791. var result = new T();
  792. result.Append(fs.GetUnsafePtr(), index);
  793. return result;
  794. }
  795. /// <summary>
  796. /// Removes whitespace characters from the end of the string.
  797. /// </summary>
  798. /// <param name="fs">A <see cref="UnsafeText"/> string to perform operation.</param>
  799. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  800. /// <returns>Returns instance of this string with whitespace characters removed from the end of the string.</returns>
  801. public static UnsafeText TrimEnd(ref this UnsafeText fs, AllocatorManager.AllocatorHandle allocator)
  802. {
  803. var index = fs.TrimEndIndex();
  804. var lengthInBytes = index;
  805. var result = new UnsafeText(lengthInBytes, allocator);
  806. result.Append(fs.GetUnsafePtr(), lengthInBytes);
  807. return result;
  808. }
  809. /// <summary>
  810. /// Removes whitespace characters from the end of the string.
  811. /// </summary>
  812. /// <param name="fs">A <see cref="NativeText"/> string to perform operation.</param>
  813. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  814. /// <returns>Returns instance of this string with whitespace characters removed from the end of the string.</returns>
  815. public static NativeText TrimEnd(ref this NativeText fs, AllocatorManager.AllocatorHandle allocator)
  816. {
  817. var index = fs.TrimEndIndex();
  818. var lengthInBytes = index;
  819. var result = new NativeText(lengthInBytes, allocator);
  820. result.Append(fs.GetUnsafePtr(), lengthInBytes);
  821. return result;
  822. }
  823. /// <summary>
  824. /// Removes specific characters from the end of the string.
  825. /// </summary>
  826. /// <typeparam name="T">A string type.</typeparam>
  827. /// <param name="fs">A string to perform operation.</param>
  828. /// <param name="trimRunes">Runes that should be trimmed.</param>
  829. /// <returns>Returns instance of this string with specific characters removed from the end of the string.</returns>
  830. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  831. public static T TrimEnd<T>(ref this T fs, ReadOnlySpan<Unicode.Rune> trimRunes)
  832. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  833. {
  834. var index = fs.TrimEndIndex(trimRunes);
  835. var result = new T();
  836. result.Append(fs.GetUnsafePtr(), index);
  837. return result;
  838. }
  839. /// <summary>
  840. /// Removes specific characters from the end of the string.
  841. /// </summary>
  842. /// <param name="fs">A <see cref="UnsafeText"/> string to perform operation.</param>
  843. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  844. /// <param name="trimRunes">Runes that should be trimmed.</param>
  845. /// <returns>Returns instance of this string with specific characters removed from the end of the string.</returns>
  846. public static UnsafeText TrimEnd(ref this UnsafeText fs, AllocatorManager.AllocatorHandle allocator, ReadOnlySpan<Unicode.Rune> trimRunes)
  847. {
  848. var index = fs.TrimEndIndex(trimRunes);
  849. var lengthInBytes = index;
  850. var result = new UnsafeText(lengthInBytes, allocator);
  851. result.Append(fs.GetUnsafePtr(), lengthInBytes);
  852. return result;
  853. }
  854. /// <summary>
  855. /// Removes specific characters from the end of the string.
  856. /// </summary>
  857. /// <param name="fs">A <see cref="NativeText"/> string to perform operation.</param>
  858. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  859. /// <param name="trimRunes">Runes that should be trimmed.</param>
  860. /// <returns>Returns instance of this string with specific characters removed from the end of the string.</returns>
  861. public static NativeText TrimEnd(ref this NativeText fs, AllocatorManager.AllocatorHandle allocator, ReadOnlySpan<Unicode.Rune> trimRunes)
  862. {
  863. var index = fs.TrimEndIndex(trimRunes);
  864. var lengthInBytes = index;
  865. var result = new NativeText(lengthInBytes, allocator);
  866. result.Append(fs.GetUnsafePtr(), lengthInBytes);
  867. return result;
  868. }
  869. /// <summary>
  870. /// Removes whitespace characters from the begining and the end of the string.
  871. /// </summary>
  872. /// <typeparam name="T">A string type.</typeparam>
  873. /// <param name="fs">A string to perform operation.</param>
  874. /// <returns>Returns instance of this string with whitespace characters removed from the begining and the end of the string.</returns>
  875. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  876. public static T Trim<T>(ref this T fs)
  877. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  878. {
  879. var start = fs.TrimStartIndex();
  880. if (start == fs.Length)
  881. {
  882. return new T();
  883. }
  884. var end = fs.TrimEndIndex();
  885. var result = new T();
  886. result.Append(fs.GetUnsafePtr() + start, end - start);
  887. return result;
  888. }
  889. /// <summary>
  890. /// Removes whitespace characters from the begining and the end of the string.
  891. /// </summary>
  892. /// <param name="fs">A <see cref="UnsafeText"/> string to perform operation.</param>
  893. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  894. /// <returns>Returns instance of this string with whitespace characters removed from the begining and the end of the string.</returns>
  895. public static UnsafeText Trim(ref this UnsafeText fs, AllocatorManager.AllocatorHandle allocator)
  896. {
  897. var start = fs.TrimStartIndex();
  898. if (start == fs.Length)
  899. {
  900. return new UnsafeText(0, allocator);
  901. }
  902. var end = fs.TrimEndIndex();
  903. var lengthInBytes = end - start;
  904. var result = new UnsafeText(lengthInBytes, allocator);
  905. result.Append(fs.GetUnsafePtr() + start, lengthInBytes);
  906. return result;
  907. }
  908. /// <summary>
  909. /// Removes whitespace characters from the begining and the end of the string.
  910. /// </summary>
  911. /// <param name="fs">A <see cref="NativeText"/> string to perform operation.</param>
  912. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  913. /// <returns>Returns instance of this string with whitespace characters removed from the begining and the end of the string.</returns>
  914. public static NativeText Trim(ref this NativeText fs, AllocatorManager.AllocatorHandle allocator)
  915. {
  916. var start = fs.TrimStartIndex();
  917. if (start == fs.Length)
  918. {
  919. return new NativeText(0, allocator);
  920. }
  921. var end = fs.TrimEndIndex();
  922. var lengthInBytes = end - start;
  923. var result = new NativeText(lengthInBytes, allocator);
  924. result.Append(fs.GetUnsafePtr() + start, lengthInBytes);
  925. return result;
  926. }
  927. /// <summary>
  928. /// Removes specific characters from the begining and the end of the string.
  929. /// </summary>
  930. /// <typeparam name="T">A string type.</typeparam>
  931. /// <param name="fs">A string to perform operation.</param>
  932. /// <param name="trimRunes">Runes that should be trimmed.</param>
  933. /// <returns>Returns instance of this string with specific characters removed from the begining and the end of the string.</returns>
  934. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  935. public static T Trim<T>(ref this T fs, ReadOnlySpan<Unicode.Rune> trimRunes)
  936. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  937. {
  938. var start = fs.TrimStartIndex(trimRunes);
  939. if (start == fs.Length)
  940. {
  941. return new T();
  942. }
  943. var end = fs.TrimEndIndex(trimRunes);
  944. var result = new T();
  945. result.Append(fs.GetUnsafePtr() + start, end - start);
  946. return result;
  947. }
  948. /// <summary>
  949. /// Removes specific characters from the begining and the end of the string.
  950. /// </summary>
  951. /// <param name="fs">A <see cref="UnsafeText"/> string to perform operation.</param>
  952. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  953. /// <param name="trimRunes">Runes that should be trimmed.</param>
  954. /// <returns>Returns instance of this string with specific characters removed from the begining and the end of the string.</returns>
  955. public static UnsafeText Trim(ref this UnsafeText fs, AllocatorManager.AllocatorHandle allocator, ReadOnlySpan<Unicode.Rune> trimRunes)
  956. {
  957. var start = fs.TrimStartIndex(trimRunes);
  958. if (start == fs.Length)
  959. {
  960. return new UnsafeText(0, allocator);
  961. }
  962. var end = fs.TrimEndIndex();
  963. var lengthInBytes = end - start;
  964. var result = new UnsafeText(lengthInBytes, allocator);
  965. result.Append(fs.GetUnsafePtr() + start, lengthInBytes);
  966. return result;
  967. }
  968. /// <summary>
  969. /// Removes specific characters from the begining and the end of the string.
  970. /// </summary>
  971. /// <param name="fs">A <see cref="NativeText"/> string to perform operation.</param>
  972. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  973. /// <param name="trimRunes">Runes that should be trimmed.</param>
  974. /// <returns>Returns instance of this string with specific characters removed from the begining and the end of the string.</returns>
  975. public static NativeText Trim(ref this NativeText fs, AllocatorManager.AllocatorHandle allocator, ReadOnlySpan<Unicode.Rune> trimRunes)
  976. {
  977. var start = fs.TrimStartIndex(trimRunes);
  978. if (start == fs.Length)
  979. {
  980. return new NativeText(0, allocator);
  981. }
  982. var end = fs.TrimEndIndex();
  983. var lengthInBytes = end - start;
  984. var result = new NativeText(lengthInBytes, allocator);
  985. result.Append(fs.GetUnsafePtr() + start, lengthInBytes);
  986. return result;
  987. }
  988. /// <summary>
  989. /// Converts string to lowercase only ASCII characters.
  990. /// </summary>
  991. /// <typeparam name="T">A string type.</typeparam>
  992. /// <param name="fs">A string to perform operation.</param>
  993. /// <returns>Returns a copy of this string converted to lowercase ASCII.</returns>
  994. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  995. public static T ToLowerAscii<T>(ref this T fs)
  996. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  997. {
  998. var lengthInBytes = fs.Length;
  999. var ptr = fs.GetUnsafePtr();
  1000. T result = new T();
  1001. Unicode.Rune rune;
  1002. var error = ConversionError.None;
  1003. for (var i = 0; i < lengthInBytes && error == ConversionError.None;)
  1004. {
  1005. error = Unicode.Utf8ToUcs(out rune, ptr, ref i, lengthInBytes);
  1006. result.Append(rune.ToLowerAscii());
  1007. }
  1008. return result;
  1009. }
  1010. /// <summary>
  1011. /// Converts string to lowercase only ASCII characters.
  1012. /// </summary>
  1013. /// <param name="fs">A <see cref="UnsafeText"/> string to perform operation.</param>
  1014. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  1015. /// <returns>Returns a copy of this string converted to lowercase ASCII.</returns>
  1016. public static UnsafeText ToLowerAscii(ref this UnsafeText fs, AllocatorManager.AllocatorHandle allocator)
  1017. {
  1018. var lengthInBytes = fs.Length;
  1019. var ptr = fs.GetUnsafePtr();
  1020. var result = new UnsafeText(lengthInBytes, allocator);
  1021. Unicode.Rune rune;
  1022. var error = ConversionError.None;
  1023. for (var i = 0; i < lengthInBytes && error == ConversionError.None;)
  1024. {
  1025. error = Unicode.Utf8ToUcs(out rune, ptr, ref i, lengthInBytes);
  1026. result.Append(rune.ToLowerAscii());
  1027. }
  1028. return result;
  1029. }
  1030. /// <summary>
  1031. /// Converts string to lowercase only ASCII characters.
  1032. /// </summary>
  1033. /// <param name="fs">A <see cref="NativeText"/> string to perform operation.</param>
  1034. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  1035. /// <returns>Returns a copy of this string converted to lowercase ASCII.</returns>
  1036. public static NativeText ToLowerAscii(ref this NativeText fs, AllocatorManager.AllocatorHandle allocator)
  1037. {
  1038. var lengthInBytes = fs.Length;
  1039. var ptr = fs.GetUnsafePtr();
  1040. var result = new NativeText(lengthInBytes, allocator);
  1041. Unicode.Rune rune;
  1042. var error = ConversionError.None;
  1043. for (var i = 0; i < lengthInBytes && error == ConversionError.None;)
  1044. {
  1045. error = Unicode.Utf8ToUcs(out rune, ptr, ref i, lengthInBytes);
  1046. result.Append(rune.ToLowerAscii());
  1047. }
  1048. return result;
  1049. }
  1050. /// <summary>
  1051. /// Converts string to uppercase only ASCII characters.
  1052. /// </summary>
  1053. /// <typeparam name="T">A string type.</typeparam>
  1054. /// <param name="fs">A string to perform operation.</param>
  1055. /// <returns>Returns a copy of this string converted to uppercase ASCII.</returns>
  1056. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  1057. public static T ToUpperAscii<T>(ref this T fs)
  1058. where T : unmanaged, INativeList<byte>, IUTF8Bytes
  1059. {
  1060. var lengthInBytes = fs.Length;
  1061. var ptr = fs.GetUnsafePtr();
  1062. T result = new T();
  1063. Unicode.Rune rune;
  1064. var error = ConversionError.None;
  1065. for (var i = 0; i < lengthInBytes && error == ConversionError.None;)
  1066. {
  1067. error = Unicode.Utf8ToUcs(out rune, ptr, ref i, lengthInBytes);
  1068. result.Append(rune.ToUpperAscii());
  1069. }
  1070. return result;
  1071. }
  1072. /// <summary>
  1073. /// Converts string to uppercase only ASCII characters.
  1074. /// </summary>
  1075. /// <param name="fs">A <see cref="UnsafeText"/> string to perform operation.</param>
  1076. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  1077. /// <returns>Returns a copy of this string converted to uppercase ASCII.</returns>
  1078. public static UnsafeText ToUpperAscii(ref this UnsafeText fs, AllocatorManager.AllocatorHandle allocator)
  1079. {
  1080. var lengthInBytes = fs.Length;
  1081. var ptr = fs.GetUnsafePtr();
  1082. var result = new UnsafeText(lengthInBytes, allocator);
  1083. Unicode.Rune rune;
  1084. var error = ConversionError.None;
  1085. for (var i = 0; i < lengthInBytes && error == ConversionError.None;)
  1086. {
  1087. error = Unicode.Utf8ToUcs(out rune, ptr, ref i, lengthInBytes);
  1088. result.Append(rune.ToUpperAscii());
  1089. }
  1090. return result;
  1091. }
  1092. /// <summary>
  1093. /// Converts string to uppercase only ASCII characters.
  1094. /// </summary>
  1095. /// <param name="fs">A <see cref="NativeText"/> string to perform operation.</param>
  1096. /// <param name="allocator">The <see cref="AllocatorManager.AllocatorHandle"/> allocator type to use.</param>
  1097. /// <returns>Returns a copy of this string converted to uppercase ASCII.</returns>
  1098. public static NativeText ToUpperAscii(ref this NativeText fs, AllocatorManager.AllocatorHandle allocator)
  1099. {
  1100. var lengthInBytes = fs.Length;
  1101. var ptr = fs.GetUnsafePtr();
  1102. var result = new NativeText(lengthInBytes, allocator);
  1103. Unicode.Rune rune;
  1104. var error = ConversionError.None;
  1105. for (var i = 0; i < lengthInBytes && error == ConversionError.None;)
  1106. {
  1107. error = Unicode.Utf8ToUcs(out rune, ptr, ref i, lengthInBytes);
  1108. result.Append(rune.ToUpperAscii());
  1109. }
  1110. return result;
  1111. }
  1112. }
  1113. }