暫無描述
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.

UnsafeUtilityEx.cs 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. using System;
  2. using System.Diagnostics;
  3. using System.Runtime.CompilerServices;
  4. using Unity.Mathematics;
  5. namespace Unity.Collections.LowLevel.Unsafe
  6. {
  7. /// <summary>
  8. /// Provides utility methods for unsafe, untyped buffers.
  9. /// </summary>
  10. [GenerateTestsForBurstCompatibility]
  11. public unsafe static class UnsafeUtilityExtensions
  12. {
  13. /// <summary>
  14. /// Swaps bytes between two buffers.
  15. /// </summary>
  16. /// <param name="ptr">A buffer.</param>
  17. /// <param name="otherPtr">Another buffer.</param>
  18. /// <param name="size">The number of bytes to swap.</param>
  19. /// <exception cref="System.InvalidOperationException">Thrown if the two ranges of bytes to swap overlap in memory.</exception>
  20. internal static void MemSwap(void* ptr, void* otherPtr, long size)
  21. {
  22. byte* dst = (byte*) ptr;
  23. byte* src = (byte*) otherPtr;
  24. CheckMemSwapOverlap(dst, src, size);
  25. var tmp = stackalloc byte[1024];
  26. while (size > 0)
  27. {
  28. var numBytes = math.min(size, 1024);
  29. UnsafeUtility.MemCpy(tmp, dst, numBytes);
  30. UnsafeUtility.MemCpy(dst, src, numBytes);
  31. UnsafeUtility.MemCpy(src, tmp, numBytes);
  32. size -= numBytes;
  33. src += numBytes;
  34. dst += numBytes;
  35. }
  36. }
  37. /// <summary>
  38. /// Reads an element from a buffer after bounds checking.
  39. /// </summary>
  40. /// <typeparam name="T">The type of element.</typeparam>
  41. /// <param name="source">The buffer to read from.</param>
  42. /// <param name="index">The index of the element.</param>
  43. /// <param name="capacity">The buffer capacity (in number of elements). Used for the bounds checking.</param>
  44. /// <returns>The element read from the buffer.</returns>
  45. /// <exception cref="IndexOutOfRangeException">Thrown if the index is out of bounds.</exception>
  46. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
  47. public unsafe static T ReadArrayElementBoundsChecked<T>(void* source, int index, int capacity)
  48. where T : unmanaged
  49. {
  50. CheckIndexRange(index, capacity);
  51. return UnsafeUtility.ReadArrayElement<T>(source, index);
  52. }
  53. /// <summary>
  54. /// Writes an element to a buffer after bounds checking.
  55. /// </summary>
  56. /// <typeparam name="T">The type of element.</typeparam>
  57. /// <param name="destination">The buffer to write to.</param>
  58. /// <param name="value">The value to write.</param>
  59. /// <param name="index">The index at which to store the element.</param>
  60. /// <param name="capacity">The buffer capacity (in number of elements). Used for the bounds checking.</param>
  61. /// <exception cref="IndexOutOfRangeException">Thrown if the index is out of bounds.</exception>
  62. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
  63. public unsafe static void WriteArrayElementBoundsChecked<T>(void* destination, int index, T value, int capacity)
  64. where T : unmanaged
  65. {
  66. CheckIndexRange(index, capacity);
  67. UnsafeUtility.WriteArrayElement<T>(destination, index, value);
  68. }
  69. /// <summary>
  70. /// Returns the address of a read-only reference.
  71. /// </summary>
  72. /// <typeparam name="T">The type of referenced value.</typeparam>
  73. /// <param name="value">A read-only reference.</param>
  74. /// <returns>A pointer to the referenced value.</returns>
  75. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  76. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
  77. public static void* AddressOf<T>(in T value)
  78. where T : unmanaged
  79. {
  80. return ILSupport.AddressOf(in value);
  81. }
  82. /// <summary>
  83. /// Returns a read-write reference from a read-only reference.
  84. /// <remarks>Useful when you want to pass an `in` arg (read-only reference) where a `ref` arg (read-write reference) is expected.
  85. /// Do not mutate the referenced value, as doing so may break the runtime's assumptions.</remarks>
  86. /// </summary>
  87. /// <typeparam name="T">The type of referenced value.</typeparam>
  88. /// <param name="value">A read-only reference.</param>
  89. /// <returns>A read-write reference to the value referenced by `item`.</returns>
  90. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  91. [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
  92. public static ref T AsRef<T>(in T value)
  93. where T : unmanaged
  94. {
  95. return ref ILSupport.AsRef(in value);
  96. }
  97. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
  98. static unsafe void CheckMemSwapOverlap(byte* dst, byte* src, long size)
  99. {
  100. if (dst + size > src && src + size > dst)
  101. {
  102. throw new InvalidOperationException("MemSwap memory blocks are overlapped.");
  103. }
  104. }
  105. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
  106. static void CheckIndexRange(int index, int capacity)
  107. {
  108. if ((index > capacity - 1) || (index < 0))
  109. {
  110. throw new IndexOutOfRangeException(
  111. $"Attempt to read or write from array index {index}, which is out of bounds. Array capacity is {capacity}. "
  112. +"This may lead to a crash, data corruption, or reading invalid data."
  113. );
  114. }
  115. }
  116. }
  117. }