157 lines
6.9 KiB
C#
157 lines
6.9 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using Unity.Collections.LowLevel.Unsafe;
|
|
using Unity.Mathematics;
|
|
using Unity.Jobs.LowLevel.Unsafe;
|
|
|
|
|
|
namespace Unity.Collections
|
|
{
|
|
[GenerateTestsForBurstCompatibility]
|
|
unsafe internal struct Memory
|
|
{
|
|
internal const long k_MaximumRamSizeInBytes = 1L << 40; // a terabyte
|
|
|
|
[GenerateTestsForBurstCompatibility]
|
|
internal struct Unmanaged
|
|
{
|
|
internal static void* Allocate(long size, int align, AllocatorManager.AllocatorHandle allocator)
|
|
{
|
|
return Array.Resize(null, 0, 1, allocator, size, align);
|
|
}
|
|
|
|
internal static void Free(void* pointer, AllocatorManager.AllocatorHandle allocator)
|
|
{
|
|
if (pointer == null)
|
|
return;
|
|
Array.Resize(pointer, 1, 0, allocator, 1, 1);
|
|
}
|
|
|
|
[GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
|
|
internal static T* Allocate<T>(AllocatorManager.AllocatorHandle allocator) where T : unmanaged
|
|
{
|
|
return Array.Resize<T>(null, 0, 1, allocator);
|
|
}
|
|
|
|
[GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
|
|
internal static void Free<T>(T* pointer, AllocatorManager.AllocatorHandle allocator) where T : unmanaged
|
|
{
|
|
if (pointer == null)
|
|
return;
|
|
Array.Resize(pointer, 1, 0, allocator);
|
|
}
|
|
|
|
[GenerateTestsForBurstCompatibility]
|
|
internal struct Array
|
|
{
|
|
static bool IsCustom(AllocatorManager.AllocatorHandle allocator)
|
|
{
|
|
return (int) allocator.Index >= AllocatorManager.FirstUserIndex;
|
|
}
|
|
|
|
static void* CustomResize(void* oldPointer, long oldCount, long newCount, AllocatorManager.AllocatorHandle allocator, long size, int align)
|
|
{
|
|
AllocatorManager.Block block = default;
|
|
block.Range.Allocator = allocator;
|
|
block.Range.Items = (int)newCount;
|
|
block.Range.Pointer = (IntPtr)oldPointer;
|
|
block.BytesPerItem = (int)size;
|
|
block.Alignment = align;
|
|
block.AllocatedItems = (int)oldCount;
|
|
var error = AllocatorManager.Try(ref block);
|
|
AllocatorManager.CheckFailedToAllocate(error);
|
|
return (void*)block.Range.Pointer;
|
|
}
|
|
|
|
internal static void* Resize(void* oldPointer, long oldCount, long newCount, AllocatorManager.AllocatorHandle allocator,
|
|
long size, int align)
|
|
{
|
|
// Make the alignment multiple of cacheline size
|
|
var alignment = math.max(JobsUtility.CacheLineSize, align);
|
|
|
|
if (IsCustom(allocator))
|
|
return CustomResize(oldPointer, oldCount, newCount, allocator, size, alignment);
|
|
void* newPointer = default;
|
|
if (newCount > 0)
|
|
{
|
|
long bytesToAllocate = newCount * size;
|
|
CheckByteCountIsReasonable(bytesToAllocate);
|
|
newPointer = UnsafeUtility.MallocTracked(bytesToAllocate, alignment, allocator.ToAllocator, 0);
|
|
if (oldCount > 0)
|
|
{
|
|
long count = math.min(oldCount, newCount);
|
|
long bytesToCopy = count * size;
|
|
CheckByteCountIsReasonable(bytesToCopy);
|
|
UnsafeUtility.MemCpy(newPointer, oldPointer, bytesToCopy);
|
|
}
|
|
}
|
|
if (oldCount > 0)
|
|
UnsafeUtility.FreeTracked(oldPointer, allocator.ToAllocator);
|
|
return newPointer;
|
|
}
|
|
|
|
[GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
|
|
internal static T* Resize<T>(T* oldPointer, long oldCount, long newCount, AllocatorManager.AllocatorHandle allocator) where T : unmanaged
|
|
{
|
|
return (T*)Resize((byte*)oldPointer, oldCount, newCount, allocator, UnsafeUtility.SizeOf<T>(), UnsafeUtility.AlignOf<T>());
|
|
}
|
|
|
|
[GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
|
|
internal static T* Allocate<T>(long count, AllocatorManager.AllocatorHandle allocator)
|
|
where T : unmanaged
|
|
{
|
|
return Resize<T>(null, 0, count, allocator);
|
|
}
|
|
|
|
[GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
|
|
internal static void Free<T>(T* pointer, long count, AllocatorManager.AllocatorHandle allocator)
|
|
where T : unmanaged
|
|
{
|
|
if (pointer == null)
|
|
return;
|
|
Resize(pointer, count, 0, allocator);
|
|
}
|
|
}
|
|
}
|
|
|
|
[GenerateTestsForBurstCompatibility]
|
|
internal struct Array
|
|
{
|
|
[GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
|
|
internal static void Set<T>(T* pointer, long count, T t = default) where T : unmanaged
|
|
{
|
|
long bytesToSet = count * UnsafeUtility.SizeOf<T>();
|
|
CheckByteCountIsReasonable(bytesToSet);
|
|
for (var i = 0; i < count; ++i)
|
|
pointer[i] = t;
|
|
}
|
|
|
|
[GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
|
|
internal static void Clear<T>(T* pointer, long count) where T : unmanaged
|
|
{
|
|
long bytesToClear = count * UnsafeUtility.SizeOf<T>();
|
|
CheckByteCountIsReasonable(bytesToClear);
|
|
UnsafeUtility.MemClear(pointer, bytesToClear);
|
|
}
|
|
|
|
[GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
|
|
internal static void Copy<T>(T* dest, T* src, long count) where T : unmanaged
|
|
{
|
|
long bytesToCopy = count * UnsafeUtility.SizeOf<T>();
|
|
CheckByteCountIsReasonable(bytesToCopy);
|
|
UnsafeUtility.MemCpy(dest, src, bytesToCopy);
|
|
}
|
|
}
|
|
|
|
[Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
|
|
internal static void CheckByteCountIsReasonable(long size)
|
|
{
|
|
if (size < 0)
|
|
throw new InvalidOperationException($"Attempted to operate on {size} bytes of memory: negative size");
|
|
if (size > k_MaximumRamSizeInBytes)
|
|
throw new InvalidOperationException($"Attempted to operate on {size} bytes of memory: size too big");
|
|
}
|
|
|
|
}
|
|
}
|