/// <summary> /// Returns a snapshot of the elements. /// </summary> /// <returns></returns> internal static T[] ToArray <T>(UnsafeMPSCQueue *queue) where T : unmanaged { UDebug.Assert(queue != null); UDebug.Assert(queue->_items.Ptr != null); UDebug.Assert(typeof(T).TypeHandle.Value == queue->_typeHandle); int count = GetCount(queue); var arr = new T[count]; var enumerator = GetEnumerator <T>(queue); int i = 0; while (enumerator.MoveNext() && i < count) { arr[i++] = enumerator.Current; } return(arr); }
public void ResetAll(params string[] excludeKeys) { UDebug.Log($"SaveService Reset All exlude => {excludeKeys.AsString()}".Colored(ConsoleTextColor.yellow)); foreach (var pair in registeredSaveables) { if (pair.Value != null) { string excludedKey = Array.Find(excludeKeys, key => key == pair.Value.SaveKey); if (string.IsNullOrEmpty(excludedKey)) { pair.Value.ResetFull(); } else { UDebug.Log($"Key => {pair.Value.SaveKey} was excluded from resetting".Colored(ConsoleTextColor.yellow)); } } } SaveAll(); }
/// <summary> /// Enqueues an item in the queue. Blocks the thread until there is space in the queue. /// </summary> public static void Enqueue <T>(UnsafeSPSCQueue *queue, T item) where T : unmanaged { UDebug.Assert(queue != null); UDebug.Assert(queue->_items.Ptr != null); UDebug.Assert(typeof(T).TypeHandle.Value == queue->_typeHandle); SpinWait spinner = default; var tail = Volatile.Read(ref queue->_headAndTail.Tail); var nextTail = GetNext(tail, queue->_items.Length); // Full Queue while (nextTail == Volatile.Read(ref queue->_headAndTail.Head)) { spinner.SpinOnce(); } *queue->_items.Element <T>(tail) = item; Volatile.Write(ref queue->_headAndTail.Tail, nextTail); }
/// <summary> /// Tries to enqueue an item in the queue. Returns false if there's no space in the queue. /// </summary> public static bool TryEnqueue <T>(UnsafeMPSCQueue *queue, T item) where T : unmanaged { UDebug.Assert(queue != null); UDebug.Assert(queue->_items.Ptr != null); UDebug.Assert(typeof(T).TypeHandle.Value == queue->_typeHandle); SpinWait spinner = default; // Temp copy of inner buffer var items = queue->_items; var offset = queue->_slotOffset; while (true) { int tail = Volatile.Read(ref queue->_headAndTail.Tail); int index = tail & queue->_mask; int seq = Volatile.Read(ref *(int *)items.Element(index, offset)); int dif = seq - tail; if (dif == 0) { // Reserve the slot if (Interlocked.CompareExchange(ref queue->_headAndTail.Tail, tail + 1, tail) == tail) { // Write the value and update the seq *items.Element <T>(index) = item; Volatile.Write(ref *(int *)items.Element(index, offset), tail + 1); return(true); } } else if (dif < 0) { // Slot was full return(false); } // Lost the race, try again spinner.SpinOnce(); } }
/// <summary> /// Tries to dequeue an item from the queue. Returns false if there's no items in the queue. /// </summary> public static bool TryDequeue <T>(UnsafeSPSCQueue *queue, out T result) where T : unmanaged { UDebug.Assert(queue != null); UDebug.Assert(queue->_items.Ptr != null); UDebug.Assert(typeof(T).TypeHandle.Value == queue->_typeHandle); var head = Volatile.Read(ref queue->_headAndTail.Head); // Queue empty if (Volatile.Read(ref queue->_headAndTail.Tail) == head) { result = default; return(false); } result = *queue->_items.Element <T>(head); var nextHead = GetNext(head, queue->_items.Length); Volatile.Write(ref queue->_headAndTail.Head, nextHead); return(true); }
/// <summary> /// Dequeues an item from the queue. Blocks the thread until there is space in the queue. /// </summary> public static T Dequeue <T>(UnsafeSPSCQueue *queue) where T : unmanaged { UDebug.Assert(queue != null); UDebug.Assert(queue->_items.Ptr != null); UDebug.Assert(typeof(T).TypeHandle.Value == queue->_typeHandle); SpinWait spinner = default; var head = Volatile.Read(ref queue->_headAndTail.Head); // Queue empty while (Volatile.Read(ref queue->_headAndTail.Tail) == head) { spinner.SpinOnce(); } var result = queue->_items.Element <T>(head); var nextHead = GetNext(head, queue->_items.Length); Volatile.Write(ref queue->_headAndTail.Head, nextHead); return(*result); }
static Entry *CreateEntry <T>(UnsafeOrderedCollection *collection, T key, out int entryIndex) where T : unmanaged { Entry *entry; if (collection->FreeHead > 0) { UDebug.Assert(collection->FreeCount > 0); // grab from free head entry = GetEntry(collection, entryIndex = collection->FreeHead); // new free-head is entrys left pointer collection->FreeHead = entry->Left; collection->FreeCount = collection->FreeCount - 1; // we have to clear left pointer entry->Left = 0; } else { // this has to hold, as Insert<T> checks and expands if needed UDebug.Assert(collection->UsedCount < collection->Entries.Length); // grab entry from UsedCount, we add increment before as entries are 1 indexed entry = GetEntry(collection, entryIndex = ++collection->UsedCount); } // when we get a new entry, it's left/right/balance all have to be zero UDebug.Assert(entry->Left == 0); UDebug.Assert(entry->Right == 0); UDebug.Assert(entry->Balance == 0); // write key to entry *(T *)((byte *)entry + collection->KeyOffset) = key; // return entry return(entry); }