A game about forced loneliness, made by TACStudios
at master 427 lines 15 kB view raw
1using System; 2using System.Diagnostics; 3using System.Runtime.InteropServices; 4using Unity.Burst; 5using Unity.Collections.LowLevel.Unsafe; 6using Unity.Jobs; 7 8 9namespace Unity.Collections 10{ 11 /// <summary> 12 /// An unmanaged single value. 13 /// </summary> 14 /// <remarks>The functional equivalent of an array of length 1. 15 /// When you need just one value, NativeReference can be preferable to an array because it better conveys the intent.</remarks> 16 /// <typeparam name="T">The type of value.</typeparam> 17 [StructLayout(LayoutKind.Sequential)] 18 [NativeContainer] 19 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })] 20 public unsafe struct NativeReference<T> 21 : INativeDisposable 22 , IEquatable<NativeReference<T>> 23 where T : unmanaged 24 { 25 [NativeDisableUnsafePtrRestriction] 26 internal void* m_Data; 27 28#if ENABLE_UNITY_COLLECTIONS_CHECKS 29 internal AtomicSafetyHandle m_Safety; 30 31 static readonly SharedStatic<int> s_SafetyId = SharedStatic<int>.GetOrCreate<NativeReference<T>>(); 32#endif 33 34 internal AllocatorManager.AllocatorHandle m_AllocatorLabel; 35 36 /// <summary> 37 /// Initializes and returns an instance of NativeReference. 38 /// </summary> 39 /// <param name="allocator">The allocator to use.</param> 40 /// <param name="options">Whether newly allocated bytes should be zeroed out.</param> 41 public NativeReference(AllocatorManager.AllocatorHandle allocator, NativeArrayOptions options = NativeArrayOptions.ClearMemory) 42 { 43 Allocate(allocator, out this); 44 if (options == NativeArrayOptions.ClearMemory) 45 { 46 UnsafeUtility.MemClear(m_Data, UnsafeUtility.SizeOf<T>()); 47 } 48 } 49 50 /// <summary> 51 /// Initializes and returns an instance of NativeReference. 52 /// </summary> 53 /// <param name="allocator">The allocator to use.</param> 54 /// <param name="value">The initial value.</param> 55 public NativeReference(T value, AllocatorManager.AllocatorHandle allocator) 56 { 57 Allocate(allocator, out this); 58 *(T*)m_Data = value; 59 } 60 61 static void Allocate(AllocatorManager.AllocatorHandle allocator, out NativeReference<T> reference) 62 { 63 CollectionHelper.CheckAllocator(allocator); 64 65 reference = default; 66 reference.m_Data = Memory.Unmanaged.Allocate(UnsafeUtility.SizeOf<T>(), UnsafeUtility.AlignOf<T>(), allocator); 67 reference.m_AllocatorLabel = allocator; 68 69#if ENABLE_UNITY_COLLECTIONS_CHECKS 70 reference.m_Safety = CollectionHelper.CreateSafetyHandle(allocator); 71 72 CollectionHelper.InitNativeContainer<T>(reference.m_Safety); 73 CollectionHelper.SetStaticSafetyId<NativeQueue<T>>(ref reference.m_Safety, ref s_SafetyId.Data); 74#endif 75 } 76 77 /// <summary> 78 /// The value stored in this reference. 79 /// </summary> 80 /// <param name="value">The new value to store in this reference.</param> 81 /// <value>The value stored in this reference.</value> 82 public T Value 83 { 84 get 85 { 86#if ENABLE_UNITY_COLLECTIONS_CHECKS 87 AtomicSafetyHandle.CheckReadAndThrow(m_Safety); 88#endif 89 return *(T*)m_Data; 90 } 91 92 set 93 { 94#if ENABLE_UNITY_COLLECTIONS_CHECKS 95 AtomicSafetyHandle.CheckWriteAndThrow(m_Safety); 96#endif 97 *(T*)m_Data = value; 98 } 99 } 100 101 /// <summary> 102 /// Whether this reference has been allocated (and not yet deallocated). 103 /// </summary> 104 /// <value>True if this reference has been allocated (and not yet deallocated).</value> 105 public readonly bool IsCreated => m_Data != null; 106 107 /// <summary> 108 /// Releases all resources (memory and safety handles). 109 /// </summary> 110 public void Dispose() 111 { 112#if ENABLE_UNITY_COLLECTIONS_CHECKS 113 if (!AtomicSafetyHandle.IsDefaultValue(m_Safety)) 114 { 115 AtomicSafetyHandle.CheckExistsAndThrow(m_Safety); 116 } 117#endif 118 if (!IsCreated) 119 { 120 return; 121 } 122 123 if (CollectionHelper.ShouldDeallocate(m_AllocatorLabel)) 124 { 125#if ENABLE_UNITY_COLLECTIONS_CHECKS 126 CollectionHelper.DisposeSafetyHandle(ref m_Safety); 127#endif 128 Memory.Unmanaged.Free(m_Data, m_AllocatorLabel); 129 m_AllocatorLabel = Allocator.Invalid; 130 } 131 132 m_Data = null; 133 } 134 135 /// <summary> 136 /// Creates and schedules a job that will release all resources (memory and safety handles) of this reference. 137 /// </summary> 138 /// <param name="inputDeps">A job handle. The newly scheduled job will depend upon this handle.</param> 139 /// <returns>The handle of a new job that will release all resources (memory and safety handles) of this reference.</returns> 140 public JobHandle Dispose(JobHandle inputDeps) 141 { 142#if ENABLE_UNITY_COLLECTIONS_CHECKS 143 if (!AtomicSafetyHandle.IsDefaultValue(m_Safety)) 144 { 145 AtomicSafetyHandle.CheckExistsAndThrow(m_Safety); 146 } 147#endif 148 if (!IsCreated) 149 { 150 return inputDeps; 151 } 152 153 if (CollectionHelper.ShouldDeallocate(m_AllocatorLabel)) 154 { 155 var jobHandle = new NativeReferenceDisposeJob 156 { 157 Data = new NativeReferenceDispose 158 { 159 m_Data = m_Data, 160 m_AllocatorLabel = m_AllocatorLabel, 161#if ENABLE_UNITY_COLLECTIONS_CHECKS 162 m_Safety = m_Safety 163#endif 164 } 165 }.Schedule(inputDeps); 166 167#if ENABLE_UNITY_COLLECTIONS_CHECKS 168 AtomicSafetyHandle.Release(m_Safety); 169#endif 170 171 m_Data = null; 172 m_AllocatorLabel = Allocator.Invalid; 173 174 return jobHandle; 175 } 176 177 m_Data = null; 178 179 return inputDeps; 180 } 181 182 /// <summary> 183 /// Copy the value of another reference to this reference. 184 /// </summary> 185 /// <param name="reference">The reference to copy from.</param> 186 public void CopyFrom(NativeReference<T> reference) 187 { 188 Copy(this, reference); 189 } 190 191 /// <summary> 192 /// Copy the value of this reference to another reference. 193 /// </summary> 194 /// <param name="reference">The reference to copy to.</param> 195 public void CopyTo(NativeReference<T> reference) 196 { 197 Copy(reference, this); 198 } 199 200 /// <summary> 201 /// Returns true if the value stored in this reference is equal to the value stored in another reference. 202 /// </summary> 203 /// <param name="other">A reference to compare with.</param> 204 /// <returns>True if the value stored in this reference is equal to the value stored in another reference.</returns> 205 [ExcludeFromBurstCompatTesting("Equals boxes because Value does not implement IEquatable<T>")] 206 public bool Equals(NativeReference<T> other) 207 { 208 return Value.Equals(other.Value); 209 } 210 211 /// <summary> 212 /// Returns true if the value stored in this reference is equal to an object. 213 /// </summary> 214 /// <remarks>Can only be equal if the object is itself a NativeReference.</remarks> 215 /// <param name="obj">An object to compare with.</param> 216 /// <returns>True if the value stored in this reference is equal to the object.</returns> 217 [ExcludeFromBurstCompatTesting("Takes managed object")] 218 public override bool Equals(object obj) 219 { 220 if (ReferenceEquals(null, obj)) 221 { 222 return false; 223 } 224 return obj is NativeReference<T> && Equals((NativeReference<T>)obj); 225 } 226 227 /// <summary> 228 /// Returns the hash code of this reference. 229 /// </summary> 230 /// <returns>The hash code of this reference.</returns> 231 public override int GetHashCode() 232 { 233 return Value.GetHashCode(); 234 } 235 236 237 /// <summary> 238 /// Returns true if the values stored in two references are equal. 239 /// </summary> 240 /// <param name="left">A reference.</param> 241 /// <param name="right">Another reference.</param> 242 /// <returns>True if the two values are equal.</returns> 243 public static bool operator ==(NativeReference<T> left, NativeReference<T> right) 244 { 245 return left.Equals(right); 246 } 247 248 /// <summary> 249 /// Returns true if the values stored in two references are unequal. 250 /// </summary> 251 /// <param name="left">A reference.</param> 252 /// <param name="right">Another reference.</param> 253 /// <returns>True if the two values are unequal.</returns> 254 public static bool operator !=(NativeReference<T> left, NativeReference<T> right) 255 { 256 return !left.Equals(right); 257 } 258 259 /// <summary> 260 /// Copies the value of a reference to another reference. 261 /// </summary> 262 /// <param name="dst">The destination reference.</param> 263 /// <param name="src">The source reference.</param> 264 public static void Copy(NativeReference<T> dst, NativeReference<T> src) 265 { 266#if ENABLE_UNITY_COLLECTIONS_CHECKS 267 AtomicSafetyHandle.CheckReadAndThrow(src.m_Safety); 268 AtomicSafetyHandle.CheckWriteAndThrow(dst.m_Safety); 269#endif 270 UnsafeUtility.MemCpy(dst.m_Data, src.m_Data, UnsafeUtility.SizeOf<T>()); 271 } 272 273 /// <summary> 274 /// Returns a read-only reference aliasing the value of this reference. 275 /// </summary> 276 /// <returns>A read-only reference aliasing the value of this reference.</returns> 277 public ReadOnly AsReadOnly() 278 { 279#if ENABLE_UNITY_COLLECTIONS_CHECKS 280 return new ReadOnly(m_Data, ref m_Safety); 281#else 282 return new ReadOnly(m_Data); 283#endif 284 } 285 286 /// <summary> 287 /// Returns a read-only native reference that aliases the content of a native reference. 288 /// </summary> 289 /// <param name="nativeReference">NativeReference to alias.</param> 290 /// <returns>A read-only native reference that aliases the content of a native reference.</returns> 291 public static implicit operator ReadOnly(NativeReference<T> nativeReference) 292 { 293 return nativeReference.AsReadOnly(); 294 } 295 /// <summary> 296 /// A read-only alias for the value of a NativeReference. Does not have its own allocated storage. 297 /// </summary> 298 [NativeContainer] 299 [NativeContainerIsReadOnly] 300 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })] 301 public unsafe struct ReadOnly 302 { 303 [NativeDisableUnsafePtrRestriction] 304 readonly void* m_Data; 305 306#if ENABLE_UNITY_COLLECTIONS_CHECKS 307 AtomicSafetyHandle m_Safety; 308 internal static readonly SharedStatic<int> s_staticSafetyId = SharedStatic<int>.GetOrCreate<ReadOnly>(); 309 310 [GenerateTestsForBurstCompatibility(CompileTarget = GenerateTestsForBurstCompatibilityAttribute.BurstCompatibleCompileTarget.Editor)] 311 internal ReadOnly(void* data, ref AtomicSafetyHandle safety) 312 { 313 m_Data = data; 314 m_Safety = safety; 315 CollectionHelper.SetStaticSafetyId<ReadOnly>(ref m_Safety, ref s_staticSafetyId.Data); 316 } 317#else 318 internal ReadOnly(void* data) 319 { 320 m_Data = data; 321 } 322#endif 323 324 /// <summary> 325 /// The value aliased by this reference. 326 /// </summary> 327 /// <value>The value aliased by the reference.</value> 328 public T Value 329 { 330 get 331 { 332#if ENABLE_UNITY_COLLECTIONS_CHECKS 333 AtomicSafetyHandle.CheckReadAndThrow(m_Safety); 334#endif 335 return *(T*)m_Data; 336 } 337 } 338 } 339 } 340 341 [NativeContainer] 342 unsafe struct NativeReferenceDispose 343 { 344 [NativeDisableUnsafePtrRestriction] 345 internal void* m_Data; 346 347 internal AllocatorManager.AllocatorHandle m_AllocatorLabel; 348 349#if ENABLE_UNITY_COLLECTIONS_CHECKS 350 internal AtomicSafetyHandle m_Safety; 351#endif 352 353 public void Dispose() 354 { 355 Memory.Unmanaged.Free(m_Data, m_AllocatorLabel); 356 } 357 } 358 359 [BurstCompile] 360 struct NativeReferenceDisposeJob : IJob 361 { 362 internal NativeReferenceDispose Data; 363 364 public void Execute() 365 { 366 Data.Dispose(); 367 } 368 } 369} 370 371namespace Unity.Collections.LowLevel.Unsafe 372{ 373 /// <summary> 374 /// Provides extension methods for NativeReference. 375 /// </summary> 376 [GenerateTestsForBurstCompatibility] 377 public static class NativeReferenceUnsafeUtility 378 { 379 /// <summary> 380 /// Returns a pointer to this reference's stored value. 381 /// </summary> 382 /// <remarks>Performs a job safety check for read-write access.</remarks> 383 /// <typeparam name="T">The type of the value.</typeparam> 384 /// <param name="reference">The reference.</param> 385 /// <returns>A pointer to this reference's stored value.</returns> 386 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })] 387 public static unsafe T* GetUnsafePtr<T>(this NativeReference<T> reference) 388 where T : unmanaged 389 { 390#if ENABLE_UNITY_COLLECTIONS_CHECKS 391 AtomicSafetyHandle.CheckWriteAndThrow(reference.m_Safety); 392#endif 393 return (T*)reference.m_Data; 394 } 395 396 /// <summary> 397 /// Returns a pointer to this reference's stored value. 398 /// </summary> 399 /// <remarks>Performs a job safety check for read-only access.</remarks> 400 /// <typeparam name="T">The type of the value.</typeparam> 401 /// <param name="reference">The reference.</param> 402 /// <returns>A pointer to this reference's stored value.</returns> 403 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })] 404 public static unsafe T* GetUnsafeReadOnlyPtr<T>(this NativeReference<T> reference) 405 where T : unmanaged 406 { 407#if ENABLE_UNITY_COLLECTIONS_CHECKS 408 AtomicSafetyHandle.CheckReadAndThrow(reference.m_Safety); 409#endif 410 return (T*)reference.m_Data; 411 } 412 413 /// <summary> 414 /// Returns a pointer to this reference's stored value. 415 /// </summary> 416 /// <remarks>Performs no job safety checks.</remarks> 417 /// <typeparam name="T">The type of the value.</typeparam> 418 /// <param name="reference">The reference.</param> 419 /// <returns>A pointer to this reference's stored value.</returns> 420 [GenerateTestsForBurstCompatibility(GenericTypeArguments = new [] { typeof(int) })] 421 public static unsafe T* GetUnsafePtrWithoutChecks<T>(this NativeReference<T> reference) 422 where T : unmanaged 423 { 424 return (T*)reference.m_Data; 425 } 426 } 427}