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