暂无描述
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

FixedStringMethods.cs 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. using System;
  2. using Unity.Collections.LowLevel.Unsafe;
  3. namespace Unity.Collections
  4. {
  5. /// <summary>
  6. /// Provides extension methods for FixedString*N*.
  7. /// </summary>
  8. [BurstCompatible]
  9. public unsafe static partial class FixedStringMethods
  10. {
  11. /// <summary>
  12. /// Returns the index of the first occurrence of a byte sequence in this string.
  13. /// </summary>
  14. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  15. /// <param name="fs">A string to search.</param>
  16. /// <param name="bytes">A byte sequence to search for within this string.</param>
  17. /// <param name="bytesLen">The number of bytes in the byte sequence.</param>
  18. /// <returns>The index of the first occurrence of the byte sequence in this string. Returns -1 if no occurrence is found.</returns>
  19. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  20. public static int IndexOf<T>(ref this T fs, byte* bytes, int bytesLen)
  21. where T : struct, INativeList<byte>, IUTF8Bytes
  22. {
  23. var dst = fs.GetUnsafePtr();
  24. var dstLen = fs.Length;
  25. for (var i = 0; i <= dstLen - bytesLen; ++i)
  26. {
  27. for (var j = 0; j < bytesLen; ++j)
  28. if (dst[i + j] != bytes[j])
  29. goto end_of_loop;
  30. return i;
  31. end_of_loop : {}
  32. }
  33. return -1;
  34. }
  35. /// <summary>
  36. /// Returns the index of the first occurrence of a byte sequence within a subrange of this string.
  37. /// </summary>
  38. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  39. /// <param name="fs">A string to search.</param>
  40. /// <param name="bytes">A byte sequence to search for within this string.</param>
  41. /// <param name="bytesLen">The number of bytes in the byte sequence.</param>
  42. /// <param name="startIndex">The first index in this string to consider as the first byte of the byte sequence.</param>
  43. /// <param name="distance">The last index in this string to consider as the first byte of the byte sequence.</param>
  44. /// <returns>The index of the first occurrence of the byte sequence in this string. Returns -1 if no occurrence is found.</returns>
  45. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  46. public static int IndexOf<T>(ref this T fs, byte* bytes, int bytesLen, int startIndex, int distance = Int32.MaxValue)
  47. where T : struct, INativeList<byte>, IUTF8Bytes
  48. {
  49. var dst = fs.GetUnsafePtr();
  50. var dstLen = fs.Length;
  51. var searchrange = Math.Min(distance - 1, dstLen - bytesLen);
  52. for (var i = startIndex; i <= searchrange; ++i)
  53. {
  54. for (var j = 0; j < bytesLen; ++j)
  55. if (dst[i + j] != bytes[j])
  56. goto end_of_loop;
  57. return i;
  58. end_of_loop : {}
  59. }
  60. return -1;
  61. }
  62. /// <summary>
  63. /// Returns the index of the first occurrence of a substring within this string.
  64. /// </summary>
  65. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  66. /// <typeparam name="T2">A FixedString*N* type.</typeparam>
  67. /// <param name="fs">A string to search.</param>
  68. /// <param name="other">A substring to search for within this string.</param>
  69. /// <returns>The index of the first occurrence of the second string within this string. Returns -1 if no occurrence is found.</returns>
  70. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
  71. public static int IndexOf<T,T2>(ref this T fs, in T2 other)
  72. where T : struct, INativeList<byte>, IUTF8Bytes
  73. where T2 : struct, INativeList<byte>, IUTF8Bytes
  74. {
  75. ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
  76. return fs.IndexOf(oref.GetUnsafePtr(), oref.Length);
  77. }
  78. /// <summary>
  79. /// Returns the index of the first occurrence of a substring within a subrange of this string.
  80. /// </summary>
  81. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  82. /// <typeparam name="T2">A FixedString*N* type.</typeparam>
  83. /// <param name="fs">A string to search.</param>
  84. /// <param name="other">A substring to search for within this string.</param>
  85. /// <param name="startIndex">The first index in this string to consider as an occurrence of the second string.</param>
  86. /// <param name="distance">The last index in this string to consider as an occurrence of the second string.</param>
  87. /// <returns>The index of the first occurrence of the substring within this string. Returns -1 if no occurrence is found.</returns>
  88. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
  89. public static int IndexOf<T,T2>(ref this T fs, in T2 other, int startIndex, int distance = Int32.MaxValue)
  90. where T : struct, INativeList<byte>, IUTF8Bytes
  91. where T2 : struct, INativeList<byte>, IUTF8Bytes
  92. {
  93. ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
  94. return fs.IndexOf(oref.GetUnsafePtr(), oref.Length, startIndex, distance);
  95. }
  96. /// <summary>
  97. /// Returns true if a given substring occurs within this string.
  98. /// </summary>
  99. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  100. /// <typeparam name="T2">A FixedString*N* type.</typeparam>
  101. /// <param name="fs">A string to search.</param>
  102. /// <param name="other">A substring to search for within this string.</param>
  103. /// <returns>True if the substring occurs within this string.</returns>
  104. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
  105. public static bool Contains<T,T2>(ref this T fs, in T2 other)
  106. where T : struct, INativeList<byte>, IUTF8Bytes
  107. where T2 : struct, INativeList<byte>, IUTF8Bytes
  108. {
  109. return fs.IndexOf(in other) != -1;
  110. }
  111. /// <summary>
  112. /// Returns the index of the last occurrence of a byte sequence within this string.
  113. /// </summary>
  114. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  115. /// <param name="fs">A string to search.</param>
  116. /// <param name="bytes">A byte sequence to search for within this string.</param>
  117. /// <param name="bytesLen">The number of bytes in the byte sequence.</param>
  118. /// <returns>The index of the last occurrence of the byte sequence within this string. Returns -1 if no occurrence is found.</returns>
  119. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  120. public static int LastIndexOf<T>(ref this T fs, byte* bytes, int bytesLen)
  121. where T : struct, INativeList<byte>, IUTF8Bytes
  122. {
  123. var dst = fs.GetUnsafePtr();
  124. var dstLen = fs.Length;
  125. for (var i = dstLen - bytesLen; i >= 0; --i)
  126. {
  127. for (var j = 0; j < bytesLen; ++j)
  128. if (dst[i + j] != bytes[j])
  129. goto end_of_loop;
  130. return i;
  131. end_of_loop : {}
  132. }
  133. return -1;
  134. }
  135. /// <summary>
  136. /// Returns the index of the last occurrence of a byte sequence within a subrange of this string.
  137. /// </summary>
  138. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  139. /// <param name="fs">A string to search.</param>
  140. /// <param name="bytes">A byte sequence to search for within this string.</param>
  141. /// <param name="bytesLen">The number of bytes in the byte sequence.</param>
  142. /// <param name="startIndex">The smallest index in this string to consider as the first byte of the byte sequence.</param>
  143. /// <param name="distance">The greatest index in this string to consider as the first byte of the byte sequence.</param>
  144. /// <returns>The index of the last occurrence of the byte sequence within this string. Returns -1 if no occurrences found.</returns>
  145. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  146. public static int LastIndexOf<T>(ref this T fs, byte* bytes, int bytesLen, int startIndex, int distance = int.MaxValue)
  147. where T : struct, INativeList<byte>, IUTF8Bytes
  148. {
  149. var dst = fs.GetUnsafePtr();
  150. var dstLen = fs.Length;
  151. startIndex = Math.Min(dstLen - bytesLen, startIndex);
  152. var searchrange = Math.Max(0, startIndex - distance);
  153. for (var i = startIndex; i >= searchrange; --i)
  154. {
  155. for (var j = 0; j < bytesLen; ++j)
  156. if (dst[i + j] != bytes[j])
  157. goto end_of_loop;
  158. return i;
  159. end_of_loop : {}
  160. }
  161. return -1;
  162. }
  163. /// <summary>
  164. /// Returns the index of the last occurrence of a substring within this string.
  165. /// </summary>
  166. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  167. /// <typeparam name="T2">A FixedString*N* type.</typeparam>
  168. /// <param name="fs">A string to search.</param>
  169. /// <param name="other">A substring to search for in the this string.</param>
  170. /// <returns>The index of the last occurrence of the substring within this string. Returns -1 if no occurrence is found.</returns>
  171. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
  172. public static int LastIndexOf<T,T2>(ref this T fs, in T2 other)
  173. where T : struct, INativeList<byte>, IUTF8Bytes
  174. where T2 : struct, INativeList<byte>, IUTF8Bytes
  175. {
  176. ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
  177. return fs.LastIndexOf(oref.GetUnsafePtr(), oref.Length);
  178. }
  179. /// <summary>
  180. /// Returns the index of the last occurrence of a substring within a subrange of this string.
  181. /// </summary>
  182. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  183. /// <typeparam name="T2">A FixedString*N* type.</typeparam>
  184. /// <param name="fs">A string to search.</param>
  185. /// <param name="other">A substring to search for within this string.</param>
  186. /// <param name="startIndex">The greatest index in this string to consider as an occurrence of the substring.</param>
  187. /// <param name="distance">The smallest index in this string to consider as an occurrence of the substring.</param>
  188. /// <returns>the index of the last occurrence of the substring within the first string. Returns -1 if no occurrence is found.</returns>
  189. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
  190. public static int LastIndexOf<T,T2>(ref this T fs, in T2 other, int startIndex, int distance = Int32.MaxValue)
  191. where T : struct, INativeList<byte>, IUTF8Bytes
  192. where T2 : struct, INativeList<byte>, IUTF8Bytes
  193. {
  194. ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
  195. return fs.LastIndexOf(oref.GetUnsafePtr(), oref.Length, startIndex, distance);
  196. }
  197. /// <summary>
  198. /// Returns the sort position of this string relative to a byte sequence.
  199. /// </summary>
  200. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  201. /// <param name="fs">A string to compare.</param>
  202. /// <param name="bytes">A byte sequence to compare.</param>
  203. /// <param name="bytesLen">The number of bytes in the byte sequence.</param>
  204. /// <returns>A number denoting the sort position of this string relative to the byte sequence:
  205. ///
  206. /// 0 denotes that this string and byte sequence have the same sort position.<br/>
  207. /// -1 denotes that this string should be sorted to precede the byte sequence.<br/>
  208. /// +1 denotes that this string should be sorted to follow the byte sequence.<br/>
  209. /// </returns>
  210. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  211. public static int CompareTo<T>(ref this T fs, byte* bytes, int bytesLen)
  212. where T : struct, INativeList<byte>, IUTF8Bytes
  213. {
  214. var a = fs.GetUnsafePtr();
  215. var aa = fs.Length;
  216. int chars = aa < bytesLen ? aa : bytesLen;
  217. for (var i = 0; i < chars; ++i)
  218. {
  219. if (a[i] < bytes[i])
  220. return -1;
  221. if (a[i] > bytes[i])
  222. return 1;
  223. }
  224. if (aa < bytesLen)
  225. return -1;
  226. if (aa > bytesLen)
  227. return 1;
  228. return 0;
  229. }
  230. /// <summary>
  231. /// Returns the sort position of this string relative to another.
  232. /// </summary>
  233. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  234. /// <typeparam name="T2">A FixedString*N* type.</typeparam>
  235. /// <param name="fs">A string to compare.</param>
  236. /// <param name="other">Another string to compare.</param>
  237. /// <returns>A number denoting the relative sort position of the strings:
  238. ///
  239. /// 0 denotes that the strings have the same sort position.<br/>
  240. /// -1 denotes that this string should be sorted to precede the other.<br/>
  241. /// +1 denotes that this first string should be sorted to follow the other.<br/>
  242. /// </returns>
  243. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
  244. public static int CompareTo<T,T2>(ref this T fs, in T2 other)
  245. where T : struct, INativeList<byte>, IUTF8Bytes
  246. where T2 : struct, INativeList<byte>, IUTF8Bytes
  247. {
  248. ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
  249. return fs.CompareTo(oref.GetUnsafePtr(), oref.Length);
  250. }
  251. /// <summary>
  252. /// Returns true if this string and a byte sequence are equal (meaning they have the same length and content).
  253. /// </summary>
  254. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  255. /// <param name="fs">A string to compare for equality.</param>
  256. /// <param name="bytes">A sequence of bytes to compare for equality.</param>
  257. /// <param name="bytesLen">The number of bytes in the byte sequence.</param>
  258. /// <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>
  259. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  260. public static bool Equals<T>(ref this T fs, byte* bytes, int bytesLen)
  261. where T : struct, INativeList<byte>, IUTF8Bytes
  262. {
  263. var a = fs.GetUnsafePtr();
  264. var aa = fs.Length;
  265. if (aa != bytesLen)
  266. return false;
  267. if (a == bytes)
  268. return true;
  269. return fs.CompareTo(bytes, bytesLen) == 0;
  270. }
  271. /// <summary>
  272. /// Returns true if this string is equal to another.
  273. /// </summary>
  274. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  275. /// <typeparam name="T2">A FixedString*N* type.</typeparam>
  276. /// <param name="fs">A string to compare for equality.</param>
  277. /// <param name="other">Another string to compare for equality.</param>
  278. /// <returns>true if the two strings have the same length and matching content.</returns>
  279. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes), typeof(FixedString128Bytes) })]
  280. public static bool Equals<T,T2>(ref this T fs, in T2 other)
  281. where T : struct, INativeList<byte>, IUTF8Bytes
  282. where T2 : struct, INativeList<byte>, IUTF8Bytes
  283. {
  284. ref var oref = ref UnsafeUtilityExtensions.AsRef(in other);
  285. return fs.Equals(oref.GetUnsafePtr(), oref.Length);
  286. }
  287. /// <summary>
  288. /// Returns the Unicode.Rune at an index of this string.
  289. /// </summary>
  290. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  291. /// <param name="fs">A string to read.</param>
  292. /// <param name="index">A reference to an index in bytes (not characters).</param>
  293. /// <returns>The Unicode.Rune (character) which starts at the byte index. Returns Unicode.BadRune
  294. /// if the byte(s) at the index do not form a valid UTF-8 encoded character.</returns>
  295. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  296. public static Unicode.Rune Peek<T>(ref this T fs, int index)
  297. where T : struct, INativeList<byte>, IUTF8Bytes
  298. {
  299. if (index >= fs.Length)
  300. return Unicode.BadRune;
  301. Unicode.Utf8ToUcs(out var rune, fs.GetUnsafePtr(), ref index, fs.Capacity);
  302. return rune;
  303. }
  304. /// <summary>
  305. /// Returns the Unicode.Rune at an index of this string. Increments the index to the position of the next character.
  306. /// </summary>
  307. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  308. /// <param name="fs">A string to read.</param>
  309. /// <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>
  310. /// <returns>The character (as a `Unicode.Rune`) which starts at the byte index. Returns `Unicode.BadRune`
  311. /// if the byte(s) at the index do not form a valid UTF-8 encoded character.</returns>
  312. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  313. public static Unicode.Rune Read<T>(ref this T fs, ref int index)
  314. where T : struct, INativeList<byte>, IUTF8Bytes
  315. {
  316. if (index >= fs.Length)
  317. return Unicode.BadRune;
  318. Unicode.Utf8ToUcs(out var rune, fs.GetUnsafePtr(), ref index, fs.Capacity);
  319. return rune;
  320. }
  321. /// <summary>
  322. /// Writes a Unicode.Rune at an index of this string. Increments the index to the position of the next character.
  323. /// </summary>
  324. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  325. /// <param name="fs">A string to modify.</param>
  326. /// <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>
  327. /// <param name="rune">A rune to write to the string, encoded as UTF-8.</param>
  328. /// <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>
  329. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  330. public static FormatError Write<T>(ref this T fs, ref int index, Unicode.Rune rune)
  331. where T : struct, INativeList<byte>, IUTF8Bytes
  332. {
  333. var err = Unicode.UcsToUtf8(fs.GetUnsafePtr(), ref index, fs.Capacity, rune);
  334. if (err != ConversionError.None)
  335. return FormatError.Overflow;
  336. return FormatError.None;
  337. }
  338. /// <summary>
  339. /// Returns a copy of this string as a managed string.
  340. /// </summary>
  341. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  342. /// <param name="fs">A string to copy.</param>
  343. /// <returns>A copy of this string as a managed string.</returns>
  344. [NotBurstCompatible]
  345. public static String ConvertToString<T>(ref this T fs)
  346. where T : struct, INativeList<byte>, IUTF8Bytes
  347. {
  348. var c = stackalloc char[fs.Length * 2];
  349. int length = 0;
  350. Unicode.Utf8ToUtf16(fs.GetUnsafePtr(), fs.Length, c, out length, fs.Length * 2);
  351. return new String(c, 0, length);
  352. }
  353. /// <summary>
  354. /// Returns a hash code of this string.
  355. /// </summary>
  356. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  357. /// <param name="fs">A string to get a hash code of.</param>
  358. /// <returns>A hash code of this string.</returns>
  359. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  360. public static int ComputeHashCode<T>(ref this T fs)
  361. where T : struct, INativeList<byte>, IUTF8Bytes
  362. {
  363. return (int)CollectionHelper.Hash(fs.GetUnsafePtr(), fs.Length);
  364. }
  365. /// <summary>
  366. /// Returns the effective size in bytes of this string.
  367. /// </summary>
  368. /// <remarks>
  369. /// "Effective size" is `Length + 3`, the number of bytes you need to copy when serializing the string.
  370. /// (The plus 3 accounts for the null-terminator byte and the 2 bytes that store the Length).
  371. ///
  372. /// Useful for checking whether this string will fit in the space of a smaller FixedString*N*.
  373. /// </remarks>
  374. /// <typeparam name="T">A FixedString*N* type.</typeparam>
  375. /// <param name="fs">A string to get the effective size of.</param>
  376. /// <returns>The effective size in bytes of this string.</returns>
  377. [BurstCompatible(GenericTypeArguments = new[] { typeof(FixedString128Bytes) })]
  378. public static int EffectiveSizeOf<T>(ref this T fs)
  379. where T : struct, INativeList<byte>, IUTF8Bytes
  380. {
  381. return sizeof(ushort) + fs.Length + 1;
  382. }
  383. }
  384. }