A game about forced loneliness, made by TACStudios
1using System;
2using System.Diagnostics;
3using Unity.Collections.LowLevel.Unsafe;
4using Unity.Mathematics;
5using Unity.Jobs.LowLevel.Unsafe;
6
7
8namespace Unity.Collections
9{
10 [GenerateTestsForBurstCompatibility]
11 unsafe internal struct Memory
12 {
13 internal const long k_MaximumRamSizeInBytes = 1L << 40; // a terabyte
14
15 [GenerateTestsForBurstCompatibility]
16 internal struct Unmanaged
17 {
18 internal static void* Allocate(long size, int align, AllocatorManager.AllocatorHandle allocator)
19 {
20 return Array.Resize(null, 0, 1, allocator, size, align);
21 }
22
23 internal static void Free(void* pointer, AllocatorManager.AllocatorHandle allocator)
24 {
25 if (pointer == null)
26 return;
27 Array.Resize(pointer, 1, 0, allocator, 1, 1);
28 }
29
30 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
31 internal static T* Allocate<T>(AllocatorManager.AllocatorHandle allocator) where T : unmanaged
32 {
33 return Array.Resize<T>(null, 0, 1, allocator);
34 }
35
36 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
37 internal static void Free<T>(T* pointer, AllocatorManager.AllocatorHandle allocator) where T : unmanaged
38 {
39 if (pointer == null)
40 return;
41 Array.Resize(pointer, 1, 0, allocator);
42 }
43
44 [GenerateTestsForBurstCompatibility]
45 internal struct Array
46 {
47 static bool IsCustom(AllocatorManager.AllocatorHandle allocator)
48 {
49 return (int) allocator.Index >= AllocatorManager.FirstUserIndex;
50 }
51
52 static void* CustomResize(void* oldPointer, long oldCount, long newCount, AllocatorManager.AllocatorHandle allocator, long size, int align)
53 {
54 AllocatorManager.Block block = default;
55 block.Range.Allocator = allocator;
56 block.Range.Items = (int)newCount;
57 block.Range.Pointer = (IntPtr)oldPointer;
58 block.BytesPerItem = (int)size;
59 block.Alignment = align;
60 block.AllocatedItems = (int)oldCount;
61 var error = AllocatorManager.Try(ref block);
62 AllocatorManager.CheckFailedToAllocate(error);
63 return (void*)block.Range.Pointer;
64 }
65
66 internal static void* Resize(void* oldPointer, long oldCount, long newCount, AllocatorManager.AllocatorHandle allocator,
67 long size, int align)
68 {
69 // Make the alignment multiple of cacheline size
70 var alignment = math.max(JobsUtility.CacheLineSize, align);
71
72 if (IsCustom(allocator))
73 return CustomResize(oldPointer, oldCount, newCount, allocator, size, alignment);
74 void* newPointer = default;
75 if (newCount > 0)
76 {
77 long bytesToAllocate = newCount * size;
78 CheckByteCountIsReasonable(bytesToAllocate);
79 newPointer = UnsafeUtility.MallocTracked(bytesToAllocate, alignment, allocator.ToAllocator, 0);
80 if (oldCount > 0)
81 {
82 long count = math.min(oldCount, newCount);
83 long bytesToCopy = count * size;
84 CheckByteCountIsReasonable(bytesToCopy);
85 UnsafeUtility.MemCpy(newPointer, oldPointer, bytesToCopy);
86 }
87 }
88 if (oldCount > 0)
89 UnsafeUtility.FreeTracked(oldPointer, allocator.ToAllocator);
90 return newPointer;
91 }
92
93 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
94 internal static T* Resize<T>(T* oldPointer, long oldCount, long newCount, AllocatorManager.AllocatorHandle allocator) where T : unmanaged
95 {
96 return (T*)Resize((byte*)oldPointer, oldCount, newCount, allocator, UnsafeUtility.SizeOf<T>(), UnsafeUtility.AlignOf<T>());
97 }
98
99 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
100 internal static T* Allocate<T>(long count, AllocatorManager.AllocatorHandle allocator)
101 where T : unmanaged
102 {
103 return Resize<T>(null, 0, count, allocator);
104 }
105
106 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
107 internal static void Free<T>(T* pointer, long count, AllocatorManager.AllocatorHandle allocator)
108 where T : unmanaged
109 {
110 if (pointer == null)
111 return;
112 Resize(pointer, count, 0, allocator);
113 }
114 }
115 }
116
117 [GenerateTestsForBurstCompatibility]
118 internal struct Array
119 {
120 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
121 internal static void Set<T>(T* pointer, long count, T t = default) where T : unmanaged
122 {
123 long bytesToSet = count * UnsafeUtility.SizeOf<T>();
124 CheckByteCountIsReasonable(bytesToSet);
125 for (var i = 0; i < count; ++i)
126 pointer[i] = t;
127 }
128
129 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
130 internal static void Clear<T>(T* pointer, long count) where T : unmanaged
131 {
132 long bytesToClear = count * UnsafeUtility.SizeOf<T>();
133 CheckByteCountIsReasonable(bytesToClear);
134 UnsafeUtility.MemClear(pointer, bytesToClear);
135 }
136
137 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })]
138 internal static void Copy<T>(T* dest, T* src, long count) where T : unmanaged
139 {
140 long bytesToCopy = count * UnsafeUtility.SizeOf<T>();
141 CheckByteCountIsReasonable(bytesToCopy);
142 UnsafeUtility.MemCpy(dest, src, bytesToCopy);
143 }
144 }
145
146 [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS"), Conditional("UNITY_DOTS_DEBUG")]
147 internal static void CheckByteCountIsReasonable(long size)
148 {
149 if (size < 0)
150 throw new InvalidOperationException($"Attempted to operate on {size} bytes of memory: negative size");
151 if (size > k_MaximumRamSizeInBytes)
152 throw new InvalidOperationException($"Attempted to operate on {size} bytes of memory: size too big");
153 }
154
155 }
156}