Нема описа
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.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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. [BurstCompatible]
  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. [BurstCompatible(GenericTypeArguments = new [] { typeof(int) })]
  47. public unsafe static T ReadArrayElementBoundsChecked<T>(void* source, int index, int capacity)
  48. {
  49. CheckIndexRange(index, capacity);
  50. return UnsafeUtility.ReadArrayElement<T>(source, index);
  51. }
  52. /// <summary>
  53. /// Writes an element to a buffer after bounds checking.
  54. /// </summary>
  55. /// <typeparam name="T">The type of element.</typeparam>
  56. /// <param name="destination">The buffer to write to.</param>
  57. /// <param name="value">The value to write.</param>
  58. /// <param name="index">The index at which to store the element.</param>
  59. /// <param name="capacity">The buffer capacity (in number of elements). Used for the bounds checking.</param>
  60. /// <exception cref="IndexOutOfRangeException">Thrown if the index is out of bounds.</exception>
  61. [BurstCompatible(GenericTypeArguments = new [] { typeof(int) })]
  62. public unsafe static void WriteArrayElementBoundsChecked<T>(void* destination, int index, T value, int capacity)
  63. {
  64. CheckIndexRange(index, capacity);
  65. UnsafeUtility.WriteArrayElement<T>(destination, index, value);
  66. }
  67. /// <summary>
  68. /// Returns the address of a read-only reference.
  69. /// </summary>
  70. /// <typeparam name="T">The type of referenced value.</typeparam>
  71. /// <param name="value">A read-only reference.</param>
  72. /// <returns>A pointer to the referenced value.</returns>
  73. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  74. [BurstCompatible(GenericTypeArguments = new [] { typeof(int) })]
  75. public static void* AddressOf<T>(in T value)
  76. where T : struct
  77. {
  78. return ILSupport.AddressOf(in value);
  79. }
  80. /// <summary>
  81. /// Returns a read-write reference from a read-only reference.
  82. /// <remarks>Useful when you want to pass an `in` arg (read-only reference) where a `ref` arg (read-write reference) is expected.
  83. /// Do not mutate the referenced value, as doing so may break the runtime's assumptions.</remarks>
  84. /// </summary>
  85. /// <typeparam name="T">The type of referenced value.</typeparam>
  86. /// <param name="value">A read-only reference.</param>
  87. /// <returns>A read-write reference to the value referenced by `item`.</returns>
  88. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  89. [BurstCompatible(GenericTypeArguments = new [] { typeof(int) })]
  90. public static ref T AsRef<T>(in T value)
  91. where T : struct
  92. {
  93. return ref ILSupport.AsRef(in value);
  94. }
  95. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  96. static unsafe void CheckMemSwapOverlap(byte* dst, byte* src, long size)
  97. {
  98. if (dst + size > src && src + size > dst)
  99. {
  100. throw new InvalidOperationException("MemSwap memory blocks are overlapped.");
  101. }
  102. }
  103. [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
  104. static void CheckIndexRange(int index, int capacity)
  105. {
  106. if ((index > capacity - 1) || (index < 0))
  107. {
  108. throw new IndexOutOfRangeException(
  109. $"Attempt to read or write from array index {index}, which is out of bounds. Array capacity is {capacity}. "
  110. +"This may lead to a crash, data corruption, or reading invalid data."
  111. );
  112. }
  113. }
  114. }
  115. }