using System;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;
namespace Pathfinding.Util {
/// Various utilities for handling arrays and memory
public static class Memory {
///
/// Returns a new array with at most length newLength.
/// The array will contain a copy of all elements of arr up to but excluding the index newLength.
///
public static T[] ShrinkArray(T[] arr, int newLength) {
newLength = Math.Min(newLength, arr.Length);
var shrunkArr = new T[newLength];
Array.Copy(arr, shrunkArr, newLength);
return shrunkArr;
}
/// Swaps the variables a and b
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static void Swap(ref T a, ref T b) {
T tmp = a;
a = b;
b = tmp;
}
public static void Realloc(ref NativeArray arr, int newSize, Allocator allocator, NativeArrayOptions options = NativeArrayOptions.ClearMemory) where T : struct {
if (arr.IsCreated && arr.Length >= newSize) return;
var newArr = new NativeArray(newSize, allocator, options);
if (arr.IsCreated) {
// Copy over old data
NativeArray.Copy(arr, newArr, arr.Length);
arr.Dispose();
}
arr = newArr;
}
public static void Realloc(ref T[] arr, int newSize) {
if (arr == null) {
arr = new T[newSize];
} else if (newSize > arr.Length) {
var newArr = new T[newSize];
arr.CopyTo(newArr, 0);
arr = newArr;
}
}
public static T[] UnsafeAppendBufferToArray(UnsafeAppendBuffer src) where T : unmanaged {
var elementCount = src.Length / UnsafeUtility.SizeOf();
var dst = new T[elementCount];
unsafe {
var gCHandle = System.Runtime.InteropServices.GCHandle.Alloc(dst, System.Runtime.InteropServices.GCHandleType.Pinned);
System.IntPtr value = gCHandle.AddrOfPinnedObject();
UnsafeUtility.MemCpy((byte*)(void*)value, src.Ptr, (long)elementCount * (long)UnsafeUtility.SizeOf());
gCHandle.Free();
}
return dst;
}
public static void Rotate3DArray(T[] arr, int3 size, int dx, int dz) {
int width = size.x;
int height = size.y;
int depth = size.z;
dx = dx % width;
dz = dz % depth;
if (dx != 0) {
if (dx < 0) dx = width + dx;
var tmp = ArrayPool.Claim(dx);
for (int y = 0; y < height; y++) {
var offset = y * width * depth;
for (int z = 0; z < depth; z++) {
Array.Copy(arr, offset + z * width + width - dx, tmp, 0, dx);
Array.Copy(arr, offset + z * width, arr, offset + z * width + dx, width - dx);
Array.Copy(tmp, 0, arr, offset + z * width, dx);
}
}
ArrayPool.Release(ref tmp);
}
if (dz != 0) {
if (dz < 0) dz = depth + dz;
var tmp = ArrayPool.Claim(dz * width);
for (int y = 0; y < height; y++) {
var offset = y * width * depth;
Array.Copy(arr, offset + (depth - dz) * width, tmp, 0, dz * width);
Array.Copy(arr, offset, arr, offset + dz * width, (depth - dz) * width);
Array.Copy(tmp, 0, arr, offset, dz * width);
}
ArrayPool.Release(ref tmp);
}
}
}
}