No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FixedString.tt 28KB

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