A game about forced loneliness, made by TACStudios
1 2<#/*THIS IS A T4 FILE - see t4_text_templating.md for what it is and how to run codegen*/#> 3<#@ template debug="True" #> 4<#@ output extension=".gen.cs" encoding="utf-8" #> 5<#@ assembly name="System.Core" #> 6 7//------------------------------------------------------------------------------ 8// <auto-generated> 9// This code was generated by a tool. 10// 11// TextTransform Samples/Packages/com.unity.collections/Unity.Collections/FixedString.tt 12// 13// Changes to this file may cause incorrect behavior and will be lost if 14// the code is regenerated. 15// </auto-generated> 16//------------------------------------------------------------------------------ 17 18using System.Collections.Generic; 19using System.Collections; 20using System.Diagnostics; 21using System.Runtime.CompilerServices; 22using System.Runtime.InteropServices; 23using System; 24using Unity.Collections.LowLevel.Unsafe; 25using Unity.Mathematics; 26using UnityEngine.Internal; 27using UnityEngine; 28using Unity.Properties; 29 30namespace Unity.Collections 31{ 32 // A temporary copy of a struct is made before it is displayed in a C# debugger. 33 // However, only the first element of data members with names is copied at this time. 34 // Therefore, it's important that all data visible in the debugger, has a name 35 // and includes no 'fixed' array. This is why we name every byte in the following struct. 36 37 /// <summary> 38 /// For internal use only. This type is 8 byte aligned 39 /// </summary> 40 [Serializable] 41 [StructLayout(LayoutKind.Explicit, Size=16)] 42 [GenerateTestsForBurstCompatibility] 43 internal struct FixedBytes16Align8 44 { 45<# 46 for(var i = 0; i < 2; ++i) 47 { 48 var offset = (i*8).ToString("D4"); 49#> 50 /// <summary> 51 /// For internal use only. 52 /// </summary> 53 [SerializeField] [FieldOffset(<#=i*8#>)] public ulong byte<#=offset#>; 54 55<# 56 } 57#> 58 } 59 60 /// <summary> 61 /// For internal use only. 62 /// </summary> 63 [Serializable] 64 [StructLayout(LayoutKind.Explicit, Size=16)] 65 [GenerateTestsForBurstCompatibility] 66 public struct FixedBytes16 67 { 68<# 69 for(var i = 0; i < 16; ++i) 70 { 71 var offset = i.ToString("D4"); 72#> 73 /// <summary> 74 /// For internal use only. 75 /// </summary> 76 [FieldOffset(<#=i#>)] public byte byte<#=offset#>; 77 78<# 79 } 80#> 81 } 82 83<# 84{ 85 var SIZES = new [] {32,64,128,512,4096}; 86 foreach (var BYTES in SIZES) { 87#> 88 89 // A temporary copy of a struct is made before it is displayed in a C# debugger. 90 // However, only the first element of data members with names is copied at this time. 91 // Therefore, it's important that all data visible in the debugger, has a name 92 // and includes no 'fixed' array. This is why we name every byte in the following struct. 93 94 /// <summary> 95 /// For internal use only. 96 /// </summary> 97 [Serializable] 98 [StructLayout(LayoutKind.Explicit, Size=<#=BYTES#>)] 99 [GenerateTestsForBurstCompatibility] 100 internal struct FixedBytes<#=BYTES#>Align8 101 { 102<# 103 for(var i = 0; i < (BYTES/16)*16; i += 16) 104 { 105 var offset = i.ToString("D4"); 106#> 107 /// <summary> 108 /// For internal use only. 109 /// </summary> 110 [SerializeField] [FieldOffset(<#=i#>)] internal FixedBytes16Align8 offset<#=offset#>; 111<# 112 } 113#> 114 } 115<# 116}} 117#> 118 119<# 120{ 121 var SIZES = new [] {32,64,128,512,4096}; 122 foreach (var BYTES in SIZES) { 123 // 2 bytes for the ushort length 124 var MAXLENGTH = BYTES - 2; 125 var TYPENAME = $"FixedString{BYTES}Bytes"; 126 var OLD_TYPENAME = $"FixedString{BYTES}"; 127#> 128 129 // A temporary copy of a struct is made before it is displayed in a C# debugger. 130 // However, only the first element of data members with names is copied at this time. 131 // Therefore, it's important that all data visible in the debugger, has a name 132 // and includes no 'fixed' array. This is why we name every byte in the following struct. 133 134 /// <summary> 135 /// For internal use only. 136 /// </summary> 137 [Serializable] 138 [StructLayout(LayoutKind.Explicit, Size=<#=MAXLENGTH#>)] 139 [GenerateTestsForBurstCompatibility] 140 public struct FixedBytes<#=MAXLENGTH#> 141 { 142<# 143 for(var i = 0; i < (MAXLENGTH/16)*16; i += 16) 144 { 145 var offset = i.ToString("D4"); 146#> 147 /// <summary> 148 /// For internal use only. 149 /// </summary> 150 [FieldOffset(<#=i#>)] public FixedBytes16 offset<#=offset#>; 151 152<# 153 } 154 for(var i = (MAXLENGTH/16)*16; i < MAXLENGTH; ++i) 155 { 156 var offset = i.ToString("D4"); 157#> 158 /// <summary> 159 /// For internal use only. 160 /// </summary> 161 [FieldOffset(<#=i#>)] public byte byte<#=offset#>; 162 163<# 164 } 165#> 166 } 167 168 /// <summary> 169 /// An unmanaged UTF-8 string whose content is stored directly in the <#=BYTES#>-byte struct. 170 /// </summary> 171 /// <remarks> 172 /// The binary layout of this string is guaranteed, for now and all time, to be a length (a little-endian two byte integer) 173 /// followed by the bytes of the characters (with no padding). A zero byte always immediately follows the last character. 174 /// Effectively, the number of bytes for storing characters is 3 less than <#=BYTES#> (two length bytes and one null byte). 175 /// 176 /// This layout is identical to a <see cref="FixedList<#=BYTES#>Bytes{T}"/> of bytes, thus allowing reinterpretation between FixedString<#=BYTES#>Bytes and FixedList<#=BYTES#>Bytes. 177 /// 178 /// By virtue of being an unmanaged, non-allocated struct with no pointers, this string is fully compatible with jobs and Burst compilation. 179 /// Unlike managed string types, these strings can be put in any unmanaged ECS components, FixedList, or any other unmanaged structs. 180 /// </remarks> 181 [Serializable] 182 [StructLayout(LayoutKind.Sequential, Size=<#=BYTES#>)] 183 [GenerateTestsForBurstCompatibility] 184 public partial struct <#=TYPENAME#> 185 : INativeList<byte> 186 , IUTF8Bytes 187 , IComparable<String> 188 , IEquatable<String> 189<# 190 foreach (var OTHERBYTES in SIZES) 191 { 192#> 193 , IComparable<FixedString<#=OTHERBYTES#>Bytes> 194 , IEquatable<FixedString<#=OTHERBYTES#>Bytes> 195<# 196 } 197#> 198 { 199 internal const ushort utf8MaxLengthInBytes = <#=MAXLENGTH-1#>; 200 201 [SerializeField] internal ushort utf8LengthInBytes; 202 [SerializeField] internal FixedBytes<#=MAXLENGTH#> bytes; 203 204 /// <summary> 205 /// Returns the maximum number of UTF-8 bytes that can be stored in this string. 206 /// </summary> 207 /// <returns> 208 /// The maximum number of UTF-8 bytes that can be stored in this string. 209 /// </returns> 210 public static int UTF8MaxLengthInBytes => utf8MaxLengthInBytes; 211 212 /// <summary> 213 /// For internal use only. Use <see cref="ToString"/> instead. 214 /// </summary> 215 /// <value>For internal use only. Use <see cref="ToString"/> instead.</value> 216 [CreateProperty] 217 [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)] 218 [ExcludeFromBurstCompatTesting("Returns managed string")] 219 public string Value => ToString(); 220 221 /// <summary> 222 /// Returns a pointer to the character bytes. 223 /// </summary> 224 /// <remarks> 225 /// The pointer returned by this method points into the internals of the target FixedString object. It is the 226 /// caller's responsibility to ensure that the pointer is not used after the FixedString object is destroyed or goes 227 /// out of scope. 228 /// </remarks> 229 /// <returns>A pointer to the character bytes.</returns> 230 [MethodImpl(MethodImplOptions.AggressiveInlining)] 231 public readonly unsafe byte* GetUnsafePtr() 232 { 233 fixed(void* b = &bytes) 234 return (byte*)b; 235 } 236 237 /// <summary> 238 /// The current length in bytes of this string's content. 239 /// </summary> 240 /// <remarks> 241 /// The length value does not include the null-terminator byte. 242 /// </remarks> 243 /// <param name="value">The new length in bytes of the string's content.</param> 244 /// <exception cref="ArgumentOutOfRangeException">Thrown if the new length is out of bounds.</exception> 245 /// <value> 246 /// The current length in bytes of this string's content. 247 /// </value> 248 public int Length 249 { 250 [MethodImpl(MethodImplOptions.AggressiveInlining)] 251 readonly get 252 { 253 return utf8LengthInBytes; 254 } 255 256 set 257 { 258 CheckLengthInRange(value); 259 utf8LengthInBytes = (ushort)value; 260 unsafe 261 { 262 GetUnsafePtr()[utf8LengthInBytes] = 0; 263 } 264 } 265 } 266 267 /// <summary> 268 /// The number of bytes this string has for storing UTF-8 characters. 269 /// </summary> 270 /// <value>The number of bytes this string has for storing UTF-8 characters.</value> 271 /// <remarks> 272 /// Does not include the null-terminator byte. 273 /// 274 /// A setter is included for conformity with <see cref="INativeList{T}"/>, but <see cref="Capacity"/> is fixed at <#=BYTES-3#>. 275 /// Setting the value to anything other than <#=BYTES-3#> throws an exception. 276 /// 277 /// In UTF-8 encoding, each Unicode code point (character) requires 1 to 4 bytes, 278 /// so the number of characters that can be stored may be less than the capacity. 279 /// </remarks> 280 /// <exception cref="ArgumentOutOfRangeException">Thrown if attempting to set the capacity to anything other than <#=BYTES-3#>.</exception> 281 public int Capacity 282 { 283 [MethodImpl(MethodImplOptions.AggressiveInlining)] 284 readonly get 285 { 286 return utf8MaxLengthInBytes; 287 } 288 289 set 290 { 291 CheckCapacityInRange(value); 292 } 293 } 294 295 /// <summary> 296 /// Attempts to set the length in bytes. Does nothing if the new length is invalid. 297 /// </summary> 298 /// <param name="newLength">The desired length.</param> 299 /// <param name="clearOptions">Whether added or removed bytes should be cleared (zeroed). (Increasing the length adds bytes; decreasing the length removes bytes.)</param> 300 /// <returns>True if the new length is valid.</returns> 301 public bool TryResize(int newLength, NativeArrayOptions clearOptions = NativeArrayOptions.ClearMemory) 302 { 303 if (newLength < 0 || newLength > utf8MaxLengthInBytes) 304 return false; 305 if (newLength == utf8LengthInBytes) 306 return true; 307 unsafe 308 { 309 if (clearOptions == NativeArrayOptions.ClearMemory) 310 { 311 if (newLength > utf8LengthInBytes) 312 UnsafeUtility.MemClear(GetUnsafePtr() + utf8LengthInBytes, newLength - utf8LengthInBytes); 313 else 314 UnsafeUtility.MemClear(GetUnsafePtr() + newLength, utf8LengthInBytes - newLength); 315 } 316 utf8LengthInBytes = (ushort)newLength; 317 // always null terminate 318 GetUnsafePtr()[utf8LengthInBytes] = 0; 319 } 320 return true; 321 } 322 323 /// <summary> 324 /// Returns true if this string is empty (has no characters). 325 /// </summary> 326 /// <value>True if this string is empty (has no characters).</value> 327 public readonly bool IsEmpty 328 { 329 [MethodImpl(MethodImplOptions.AggressiveInlining)] 330 get => utf8LengthInBytes == 0; 331 } 332 333 /// <summary> 334 /// Returns the byte (not character) at an index. 335 /// </summary> 336 /// <param name="index">A byte index.</param> 337 /// <value>The byte at the index.</value> 338 /// <exception cref="IndexOutOfRangeException">Thrown if the index is out of bounds.</exception> 339 public byte this[int index] 340 { 341 [MethodImpl(MethodImplOptions.AggressiveInlining)] 342 readonly get 343 { 344 unsafe 345 { 346 CheckIndexInRange(index); 347 return GetUnsafePtr()[index]; 348 } 349 } 350 351 [MethodImpl(MethodImplOptions.AggressiveInlining)] 352 set 353 { 354 unsafe 355 { 356 CheckIndexInRange(index); 357 GetUnsafePtr()[index] = value; 358 } 359 } 360 } 361 362 363 /// <summary> 364 /// Returns the reference to a byte (not character) at an index. 365 /// </summary> 366 /// <param name="index">A byte index.</param> 367 /// <returns>A reference to the byte at the index.</returns> 368 /// <exception cref="IndexOutOfRangeException">Thrown if the index is out of bounds.</exception> 369 [MethodImpl(MethodImplOptions.AggressiveInlining)] 370 public ref byte ElementAt(int index) 371 { 372 unsafe 373 { 374 CheckIndexInRange(index); 375 return ref GetUnsafePtr()[index]; 376 } 377 } 378 379 /// <summary> 380 /// Sets the length to 0. 381 /// </summary> 382 public void Clear() 383 { 384 Length = 0; 385 } 386 387 /// <summary> 388 /// Appends a byte. 389 /// </summary> 390 /// <remarks> 391 /// A zero byte will always follow the newly appended byte. 392 /// 393 /// No validation is performed: it is your responsibility for the bytes of the string to form valid UTF-8 when you're done appending bytes. 394 /// </remarks> 395 /// <param name="value">A byte to append.</param> 396 public void Add(in byte value) 397 { 398 this[Length++] = value; 399 } 400 401 /// <summary> 402 /// An enumerator over the characters (not bytes) of a FixedString<#=BYTES#>Bytes. 403 /// </summary> 404 /// <remarks> 405 /// In an enumerator's initial state, <see cref="Current"/> is not valid to read. 406 /// The first <see cref="MoveNext"/> call advances the enumerator's index to the first character. 407 /// </remarks> 408 public struct Enumerator : IEnumerator 409 { 410 FixedString<#=BYTES#>Bytes target; 411 int offset; 412 Unicode.Rune current; 413 414 /// <summary> 415 /// Initializes and returns an instance of FixedString<#=BYTES#>Bytes.Enumerator. 416 /// </summary> 417 /// <param name="other">A FixeString<#=BYTES#> for which to create an enumerator.</param> 418 public Enumerator(FixedString<#=BYTES#>Bytes other) 419 { 420 target = other; 421 offset = 0; 422 current = default; 423 } 424 425 /// <summary> 426 /// Does nothing. 427 /// </summary> 428 public void Dispose() 429 { 430 } 431 432 433 /// <summary> 434 /// Advances the enumerator to the next character. 435 /// </summary> 436 /// <returns>True if <see cref="Current"/> is valid to read after the call.</returns> 437 [MethodImpl(MethodImplOptions.AggressiveInlining)] 438 public bool MoveNext() 439 { 440 if (offset >= target.Length) 441 return false; 442 443 unsafe 444 { 445 Unicode.Utf8ToUcs(out current, target.GetUnsafePtr(), ref offset, target.Length); 446 } 447 448 return true; 449 } 450 451 /// <summary> 452 /// Resets the enumerator to its initial state. 453 /// </summary> 454 public void Reset() 455 { 456 offset = 0; 457 current = default; 458 } 459 460 /// <summary> 461 /// The current character. 462 /// </summary> 463 /// <remarks> 464 /// In an enumerator's initial state, <see cref="Current"/> is not valid to read. 465 /// </remarks> 466 /// <value>The current character.</value> 467 public Unicode.Rune Current 468 { 469 [MethodImpl(MethodImplOptions.AggressiveInlining)] 470 get => current; 471 } 472 473 object IEnumerator.Current => Current; 474 } 475 476 /// <summary> 477 /// Returns an enumerator for iterating over the characters of this string. 478 /// </summary> 479 /// <returns>An enumerator for iterating over the characters of the FixedString<#=BYTES#>Bytes.</returns> 480 public Enumerator GetEnumerator() 481 { 482 return new Enumerator(this); 483 } 484 485 /// <summary> 486 /// Returns the lexicographical sort order of this string relative to another. 487 /// </summary> 488 /// <param name="other">A `System.String` to compare with.</param> 489 /// <returns>An integer denoting the lexicographical sort order of this string relative to the other: 490 /// 491 /// 0 denotes both strings have the same sort position.<br/> 492 /// -1 denotes that this string should be sorted to precede the other string.<br/> 493 /// +1 denotes that this string should be sorted to follow the other string.<br/> 494 /// </returns> 495 [ExcludeFromBurstCompatTesting("Takes managed string")] 496 public int CompareTo(String other) 497 { 498 return ToString().CompareTo(other); 499 } 500 501 /// <summary> 502 /// Returns true if this string and another have the same length and all the same characters. 503 /// </summary> 504 /// <param name="other">A string to compare for equality.</param> 505 /// <returns>True if this string and the other have the same length and all the same characters.</returns> 506 [ExcludeFromBurstCompatTesting("Takes managed string")] 507 public bool Equals(String other) 508 { 509 unsafe { 510 int alen = utf8LengthInBytes; 511 int blen = other.Length; 512 byte* aptr = (byte*) UnsafeUtilityExtensions.AddressOf(bytes); 513 fixed(char* bptr = other) 514 { 515 return UTF8ArrayUnsafeUtility.StrCmp(aptr, alen, bptr, blen) == 0; 516 } 517 } 518 } 519 520 /// <summary> 521 /// Returns a reference to a FixedList<#=BYTES#>Bytes&lt;byte&gt; representation of this string. 522 /// </summary> 523 /// <remarks> 524 /// The referenced FixedListByte<#=BYTES#> is the very same bytes as the original FixedString<#=BYTES#>Bytes, 525 /// so it is only valid as long as the original FixedString<#=BYTES#>Bytes is valid. 526 /// </remarks> 527 /// <returns>A ref to a FixedListByte<#=BYTES#> representation of the FixedString<#=BYTES#>Bytes.</returns> 528 public unsafe ref FixedList<#=BYTES#>Bytes<byte> AsFixedList() 529 { 530 return ref UnsafeUtility.AsRef<FixedList<#=BYTES#>Bytes<byte>>(UnsafeUtility.AddressOf(ref this)); 531 } 532 533 /// <summary> 534 /// Initializes and returns an instance of FixedString<#=BYTES#>Bytes with the characters copied from a string. 535 /// </summary> 536 /// <param name="source">The source string to copy.</param> 537 /// <exception cref="ArgumentException">Thrown if the string to copy's length exceeds the capacity of FixedString<#=BYTES#>Bytes.</exception> 538 [ExcludeFromBurstCompatTesting("Takes managed string")] 539 public FixedString<#=BYTES#>Bytes(String source) 540 { 541 this = default; 542 var error = Initialize(source); 543 CheckCopyError(error, source); 544 } 545 546 /// <summary> 547 /// Initializes an instance of FixedString<#=BYTES#>Bytes with the characters copied from a string. 548 /// </summary> 549 /// <param name="source">The source string to copy.</param> 550 /// <returns>If the length of the source string exceeds this fixed string's UTF8 capacity, only the portion that fits is copied in and CopyError.Truncation is returned.</returns> 551 [ExcludeFromBurstCompatTesting("Takes managed string")] 552 internal CopyError Initialize(String source) 553 { 554 return this.CopyFromTruncated(source); 555 } 556 557 /// <summary> 558 /// Initializes and returns an instance of FixedString<#=BYTES#>Bytes with a single character repeatedly appended some number of times. 559 /// </summary> 560 /// <param name="rune">The Unicode.Rune to repeat.</param> 561 /// <param name="count">The number of times to repeat the character. Default is 1.</param> 562 public FixedString<#=BYTES#>Bytes(Unicode.Rune rune, int count = 1) 563 { 564 this = default; 565 Initialize(rune, count); 566 } 567 568 /// <summary> 569 /// Initializes an instance of FixedString<#=BYTES#>Bytes with a single character repeatedly appended some number of times. 570 /// </summary> 571 /// <param name="rune">The Unicode.Rune to repeat.</param> 572 /// <param name="count">The number of times to repeat the character. Default is 1.</param> 573 /// <returns>If the length of the source string exceeds this fixed string's UTF8 capacity, the entire write operation will fail, and FormatError.Overflow is returned.</returns> 574 internal FormatError Initialize(Unicode.Rune rune, int count = 1) 575 { 576 this = default; 577 return this.Append(rune, count); 578 } 579 580 /// <summary> 581 /// Initializes an instance of FixedString<#=BYTES#>Bytes that is a copy of another string. 582 /// </summary> 583 /// <param name="srcBytes">The source buffer.</param> 584 /// <param name="srcLength">The number of bytes to read from the source.</param> 585 /// <returns>If the length of the source string exceeds this fixed string's UTF8 capacity, the entire write operation will fail, and FormatError.Overflow is returned.</returns> 586 unsafe internal FormatError Initialize(byte* srcBytes, int srcLength) 587 { 588 bytes = default; 589 utf8LengthInBytes = 0; 590 unsafe { 591 int len = 0; 592 byte* dstBytes = GetUnsafePtr(); 593 var error = UTF8ArrayUnsafeUtility.AppendUTF8Bytes(dstBytes, ref len, utf8MaxLengthInBytes, srcBytes, srcLength); 594 if(error != FormatError.None) 595 return error; 596 this.Length = len; 597 } 598 return FormatError.None; 599 } 600 601 /// <summary> 602 /// Initializes and returns an instance of FixedString<#=BYTES#>Bytes that is a copy of another string. 603 /// </summary> 604 /// <param name="other">The string to copy.</param> 605 /// <exception cref="ArgumentException">Thrown if the string to copy's length exceeds the capacity of FixedString<#=BYTES#>Bytes.</exception> 606 unsafe public FixedString<#=BYTES#>Bytes(NativeText.ReadOnly other) 607 { 608 this = default; 609 var error = Initialize(other.GetUnsafePtr(), other.Length); 610 CheckFormatError(error); 611 } 612 613 /// <summary> 614 /// Initializes and returns an instance of FixedString<#=BYTES#>Bytes that is a copy of another string. 615 /// </summary> 616 /// <param name="other">The UnsafeText to copy.</param> 617 /// <exception cref="ArgumentException">Thrown if the string to copy's length exceeds the capacity of FixedString<#=BYTES#>Bytes.</exception> 618 unsafe public FixedString<#=BYTES#>Bytes(in UnsafeText other) 619 { 620 this = default; 621 var error = Initialize(other.GetUnsafePtr(), other.Length); 622 CheckFormatError(error); 623 } 624<# 625 // 626 // Generate easy conversion and comparison between this and other FixedString types 627 // 628 foreach (var OTHERBYTES in SIZES) 629 { 630#> 631 632 /// <summary> 633 /// Returns the lexicographical sort order of this string relative to another. 634 /// </summary> 635 /// <param name="other">A string to compare with.</param> 636 /// <returns>A number denoting the lexicographical sort order of this string relative to the other: 637 /// 638 /// 0 denotes that both strings have the same sort position.<br/> 639 /// -1 denotes that this string should be sorted to precede the other.<br/> 640 /// +1 denotes that this string should be sorted to follow the other.<br/> 641 /// </returns> 642 public int CompareTo(FixedString<#=OTHERBYTES#>Bytes other) 643 { 644 return FixedStringMethods.CompareTo(ref this, other); 645 } 646 647 /// <summary> 648 /// Initializes and returns an instance of FixedString<#=BYTES#>Bytes that is a copy of another string. 649 /// </summary> 650 /// <param name="other">The string to copy.</param> 651 /// <exception cref="ArgumentException">Thrown if the string to copy's length exceeds the capacity of FixedString<#=BYTES#>Bytes.</exception> 652 public FixedString<#=BYTES#>Bytes(in FixedString<#=OTHERBYTES#>Bytes other) 653 { 654 this = default; 655 var error = Initialize(other); 656 CheckFormatError(error); 657 } 658 659 /// <summary> 660 /// Initializes an instance of FixedString<#=BYTES#>Bytes that is a copy of another string. 661 /// </summary> 662 /// <param name="other">The string to copy.</param> 663 /// <returns>If the length of the source string exceeds this fixed string's UTF8 capacity, the entire write operation will fail, and FormatError.Overflow is returned.</returns> 664 unsafe internal FormatError Initialize(in FixedString<#=OTHERBYTES#>Bytes other) 665 { 666 return Initialize((byte*) UnsafeUtilityExtensions.AddressOf(other.bytes), other.utf8LengthInBytes); 667 } 668 669 /// <summary> 670 /// Returns true if a FixedString<#=BYTES#>Bytes and another string are equal. 671 /// </summary> 672 /// <remarks>Two strings are equal if they have equal length and all their characters match.</remarks> 673 /// <param name="a">A FixedString<#=BYTES#>Bytes to compare for equality.</param> 674 /// <param name="b">A FixedString<#=OTHERBYTES#>Bytes to compare for equality.</param> 675 /// <returns>True if the two strings are equal.</returns> 676 public static bool operator ==(in FixedString<#=BYTES#>Bytes a, in FixedString<#=OTHERBYTES#>Bytes b) 677 { 678 // this must not call any methods on 'a' or 'b' 679 unsafe { 680 int alen = a.utf8LengthInBytes; 681 int blen = b.utf8LengthInBytes; 682 byte* aptr = (byte*) UnsafeUtilityExtensions.AddressOf(a.bytes); 683 byte* bptr = (byte*) UnsafeUtilityExtensions.AddressOf(b.bytes); 684 return UTF8ArrayUnsafeUtility.EqualsUTF8Bytes(aptr, alen, bptr, blen); 685 } 686 } 687 688 /// <summary> 689 /// Returns true if a FixedString<#=BYTES#>Bytes and another string are unequal. 690 /// </summary> 691 /// <remarks>Two strings are equal if they have equal length and all their characters match.</remarks> 692 /// <param name="a">A FixedString<#=BYTES#>Bytes to compare for inequality.</param> 693 /// <param name="b">A FixedString<#=OTHERBYTES#>Bytes to compare for inequality.</param> 694 /// <returns>True if the two strings are unequal.</returns> 695 public static bool operator !=(in FixedString<#=BYTES#>Bytes a, in FixedString<#=OTHERBYTES#>Bytes b) 696 { 697 return !(a == b); 698 } 699 700 /// <summary> 701 /// Returns true if this string and another string are equal. 702 /// </summary> 703 /// <remarks>Two strings are equal if they have equal length and all their characters match.</remarks> 704 /// <param name="other">A FixedString<#=OTHERBYTES#>Bytes to compare for equality.</param> 705 /// <returns>True if the two strings are equal.</returns> 706 public bool Equals(FixedString<#=OTHERBYTES#>Bytes other) 707 { 708 return this == other; 709 } 710 711<# 712 if (OTHERBYTES > BYTES) 713 { 714 // Generate implicit conversions to bigger-sized FixedStrings 715#> 716 /// <summary> 717 /// Returns a new FixedString<#=OTHERBYTES#>Bytes that is a copy of another string. 718 /// </summary> 719 /// <param name="fs">A FixedString<#=BYTES#>Bytes to copy.</param> 720 /// <returns>A new FixedString<#=OTHERBYTES#>Bytes that is a copy of the other string.</returns> 721 /// <exception cref="ArgumentException">Thrown if the string to copy's length exceeds the capacity of FixedString<#=OTHERBYTES#>Bytes.</exception> 722 public static implicit operator FixedString<#=OTHERBYTES#>Bytes(in FixedString<#=BYTES#>Bytes fs) => new FixedString<#=OTHERBYTES#>Bytes(in fs); 723 724<# 725 } 726 } 727#> 728 /// <summary> 729 /// Returns a new FixedString<#=BYTES#>Bytes that is a copy of another string. 730 /// </summary> 731 /// <param name="b">A string to copy.</param> 732 /// <returns>A new FixedString<#=BYTES#>Bytes that is a copy of another string.</returns> 733 /// <exception cref="ArgumentException">Thrown if the string to copy's length exceeds the capacity of FixedString<#=BYTES#>Bytes.</exception> 734 [ExcludeFromBurstCompatTesting("Takes managed string")] 735 public static implicit operator FixedString<#=BYTES#>Bytes(string b) => new FixedString<#=BYTES#>Bytes(b); 736 737 /// <summary> 738 /// Returns a new managed string that is a copy of this string. 739 /// </summary> 740 /// <returns>A new managed string that is a copy of this string.</returns> 741 [ExcludeFromBurstCompatTesting("Returns managed string")] 742 public override String ToString() 743 { 744 return this.ConvertToString(); 745 } 746 747 /// <summary> 748 /// Returns a hash code of this string. 749 /// </summary> 750 /// <remarks>Only the character bytes are included in the hash: any bytes beyond <see cref="Length"/> are not part of the hash.</remarks> 751 /// <returns>The hash code of this string.</returns> 752 public override int GetHashCode() 753 { 754 return this.ComputeHashCode(); 755 } 756 757 /// <summary> 758 /// Returns true if this string and an object are equal. 759 /// </summary> 760 /// <remarks> 761 /// Returns false if the object is neither a System.String or a FixedString. 762 /// 763 /// Two strings are equal if they have equal length and all their characters match.</remarks> 764 /// <param name="obj">An object to compare for equality.</param> 765 /// <returns>True if this string and the object are equal.</returns> 766 [ExcludeFromBurstCompatTesting("Takes managed object")] 767 public override bool Equals(object obj) 768 { 769 if(ReferenceEquals(null, obj)) return false; 770 if(obj is String aString) return Equals(aString); 771<# 772 foreach(var OTHERBYTES in SIZES) 773 { 774 var OTHERTYPENAME = "FixedString" + OTHERBYTES + "Bytes"; 775 WriteLine(" if(obj is {0} a{0}) return Equals(a{0});", OTHERTYPENAME); 776 } 777#> 778 return false; 779 } 780 781 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")] 782 [MethodImpl(MethodImplOptions.AggressiveInlining)] 783 readonly void CheckIndexInRange(int index) 784 { 785 if (index < 0) 786 throw new IndexOutOfRangeException($"Index {index} must be positive."); 787 if (index >= utf8LengthInBytes) 788 throw new IndexOutOfRangeException($"Index {index} is out of range in FixedString<#=BYTES#>Bytes of '{utf8LengthInBytes}' Length."); 789 } 790 791 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")] 792 void CheckLengthInRange(int length) 793 { 794 if (length < 0) 795 throw new ArgumentOutOfRangeException($"Length {length} must be positive."); 796 if (length > utf8MaxLengthInBytes) 797 throw new ArgumentOutOfRangeException($"Length {length} is out of range in FixedString<#=BYTES#>Bytes of '{utf8MaxLengthInBytes}' Capacity."); 798 } 799 800 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")] 801 void CheckCapacityInRange(int capacity) 802 { 803 if (capacity > utf8MaxLengthInBytes) 804 throw new ArgumentOutOfRangeException($"Capacity {capacity} must be lower than {utf8MaxLengthInBytes}."); 805 } 806 807 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")] 808 static void CheckCopyError(CopyError error, String source) 809 { 810 if (error != CopyError.None) 811 throw new ArgumentException($"FixedString<#=BYTES#>Bytes: {error} while copying \"{source}\""); 812 } 813 814 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")] 815 static void CheckFormatError(FormatError error) 816 { 817 if (error != FormatError.None) 818 throw new ArgumentException("Source is too long to fit into fixed string of this size"); 819 } 820 } 821<#}}#> 822 823}