123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272 |
- using System;
- using System.Diagnostics;
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
- using Unity.Burst;
- using Unity.Collections.LowLevel.Unsafe;
- using Unity.Jobs;
-
- namespace Unity.Collections
- {
- /// <summary>
- /// A fixed-size circular buffer. For single-threaded uses only.
- /// </summary>
- /// <remarks>
- /// This container can't be used in parallel jobs, just on single-thread (for example: main thread, or single IJob).
- /// </remarks>
- /// <typeparam name="T">The type of the elements.</typeparam>
- [StructLayout(LayoutKind.Sequential)]
- [NativeContainer]
- [DebuggerDisplay("Length = {Length}, Capacity = {Capacity}, IsCreated = {IsCreated}, IsEmpty = {IsEmpty}")]
- [DebuggerTypeProxy(typeof(NativeRingQueueDebugView<>))]
- [GenerateTestsForBurstCompatibility(GenericTypeArguments = new[] { typeof(int) })]
- public unsafe struct NativeRingQueue<T>
- : INativeDisposable
- where T : unmanaged
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- internal AtomicSafetyHandle m_Safety;
- static readonly SharedStatic<int> s_staticSafetyId = SharedStatic<int>.GetOrCreate<NativeRingQueue<T>>();
- #endif
- [NativeDisableUnsafePtrRestriction]
- internal UnsafeRingQueue<T>* m_RingQueue;
-
- /// <summary>
- /// Whether this queue has been allocated (and not yet deallocated).
- /// </summary>
- /// <value>True if this queue has been allocated (and not yet deallocated).</value>
- public readonly bool IsCreated
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => m_RingQueue != null && m_RingQueue->IsCreated;
- }
-
- /// <summary>
- /// Whether the queue is empty.
- /// </summary>
- /// <value>True if the queue is empty or the queue has not been constructed.</value>
- public readonly bool IsEmpty
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get => m_RingQueue == null || m_RingQueue->Length == 0;
- }
-
- /// <summary>
- /// The number of elements currently in this queue.
- /// </summary>
- /// <value>The number of elements currently in this queue.</value>
- public readonly int Length
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get
- {
- CheckRead();
- return CollectionHelper.AssumePositive(m_RingQueue->Length);
- }
- }
-
- /// <summary>
- /// The number of elements that fit in the internal buffer.
- /// </summary>
- /// <value>The number of elements that fit in the internal buffer.</value>
- public readonly int Capacity
- {
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- get
- {
- CheckRead();
- return CollectionHelper.AssumePositive(m_RingQueue->Capacity);
- }
- }
-
- /// <summary>
- /// Initializes and returns an instance of NativeRingQueue.
- /// </summary>
- /// <param name="capacity">The capacity.</param>
- /// <param name="allocator">The allocator to use.</param>
- /// <param name="options">Whether newly allocated bytes should be zeroed out.</param>
- public NativeRingQueue(int capacity, AllocatorManager.AllocatorHandle allocator, NativeArrayOptions options = NativeArrayOptions.ClearMemory)
- {
- CollectionHelper.CheckAllocator(allocator);
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- m_Safety = CollectionHelper.CreateSafetyHandle(allocator);
- CollectionHelper.SetStaticSafetyId<NativeRingQueue<T>>(ref m_Safety, ref s_staticSafetyId.Data);
- #endif
- m_RingQueue = UnsafeRingQueue<T>.Alloc(allocator);
- *m_RingQueue = new UnsafeRingQueue<T>(capacity, allocator, options);
- }
-
- /// <summary>
- /// Releases all resources (memory and safety handles).
- /// </summary>
- public void Dispose()
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- if (!AtomicSafetyHandle.IsDefaultValue(m_Safety))
- {
- AtomicSafetyHandle.CheckExistsAndThrow(m_Safety);
- }
- #endif
- if (!IsCreated)
- {
- return;
- }
-
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- CollectionHelper.DisposeSafetyHandle(ref m_Safety);
- #endif
- UnsafeRingQueue<T>.Free(m_RingQueue);
- m_RingQueue = null;
- }
-
- /// <summary>
- /// Creates and schedules a job that will dispose this queue.
- /// </summary>
- /// <param name="inputDeps">The handle of a job which the new job will depend upon.</param>
- /// <returns>The handle of a new job that will dispose this queue. The new job depends upon inputDeps.</returns>
- public JobHandle Dispose(JobHandle inputDeps)
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- if (!AtomicSafetyHandle.IsDefaultValue(m_Safety))
- {
- AtomicSafetyHandle.CheckExistsAndThrow(m_Safety);
- }
- #endif
- if (!IsCreated)
- {
- return inputDeps;
- }
-
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- var jobHandle = new NativeRingQueueDisposeJob { Data = new NativeRingQueueDispose { m_QueueData = (UnsafeRingQueue<int>*)m_RingQueue, m_Safety = m_Safety } }.Schedule(inputDeps);
- AtomicSafetyHandle.Release(m_Safety);
- #else
- var jobHandle = new NativeRingQueueDisposeJob { Data = new NativeRingQueueDispose { m_QueueData = (UnsafeRingQueue<int>*)m_RingQueue } }.Schedule(inputDeps);
- #endif
- m_RingQueue = null;
-
- return jobHandle;
- }
-
- /// <summary>
- /// Adds an element at the front of the queue.
- /// </summary>
- /// <remarks>Does nothing if the queue is full.</remarks>
- /// <param name="value">The value to be added.</param>
- /// <returns>True if the value was added.</returns>
- public bool TryEnqueue(T value)
- {
- CheckWrite();
- return m_RingQueue->TryEnqueue(value);
- }
-
- /// <summary>
- /// Adds an element at the front of the queue.
- /// </summary>
- /// <param name="value">The value to be added.</param>
- /// <exception cref="InvalidOperationException">Thrown if the queue was full.</exception>
- public void Enqueue(T value)
- {
- CheckWrite();
- m_RingQueue->Enqueue(value);
- }
-
- /// <summary>
- /// Removes the element from the end of the queue.
- /// </summary>
- /// <remarks>Does nothing if the queue is empty.</remarks>
- /// <param name="item">Outputs the element removed.</param>
- /// <returns>True if an element was removed.</returns>
- public bool TryDequeue(out T item)
- {
- CheckRead();
- return m_RingQueue->TryDequeue(out item);
- }
-
- /// <summary>
- /// Removes the element from the end of the queue.
- /// </summary>
- /// <exception cref="InvalidOperationException">Thrown if the queue was empty.</exception>
- /// <returns>Returns the removed element.</returns>
- public T Dequeue()
- {
- CheckRead();
- return m_RingQueue->Dequeue();
- }
-
- [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- readonly void CheckRead()
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- AtomicSafetyHandle.CheckReadAndThrow(m_Safety);
- #endif
- }
-
- [Conditional("ENABLE_UNITY_COLLECTIONS_CHECKS")]
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- readonly void CheckWrite()
- {
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- AtomicSafetyHandle.CheckWriteAndThrow(m_Safety);
- #endif
- }
- }
-
- internal unsafe sealed class NativeRingQueueDebugView<T>
- where T : unmanaged
- {
- UnsafeRingQueue<T>* Data;
-
- public NativeRingQueueDebugView(NativeRingQueue<T> data)
- {
- Data = data.m_RingQueue;
- }
-
- public T[] Items
- {
- get
- {
- T[] result = new T[Data->Length];
-
- var read = Data->m_Read;
- var capacity = Data->m_Capacity;
-
- for (var i = 0; i < result.Length; ++i)
- {
- result[i] = Data->Ptr[(read + i) % capacity];
- }
-
- return result;
- }
- }
- }
-
- [NativeContainer]
- [GenerateTestsForBurstCompatibility]
- internal unsafe struct NativeRingQueueDispose
- {
- [NativeDisableUnsafePtrRestriction]
- public UnsafeRingQueue<int>* m_QueueData;
-
- #if ENABLE_UNITY_COLLECTIONS_CHECKS
- public AtomicSafetyHandle m_Safety;
- #endif
-
- public void Dispose()
- {
- UnsafeRingQueue<int>.Free(m_QueueData);
- }
- }
-
- [BurstCompile]
- internal unsafe struct NativeRingQueueDisposeJob : IJob
- {
- public NativeRingQueueDispose Data;
-
- public void Execute()
- {
- Data.Dispose();
- }
- }
- }
|