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<byte> 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}