// System using System; using System.Collections; using System.Collections.Generic; // GUPS - AntiCheat - Core using GUPS.AntiCheat.Core.Integrity; namespace GUPS.AntiCheat.Protected.Collection { /// /// Represents a protected queue that implements the , , /// , and interfaces. This queue allows tracking changes and /// provides a hash code for verification purposes. Before interacting with the queue, you should call the /// to verify its integrity. /// /// The type of elements in the queue. public class ProtectedQueue : IEnumerable, IEnumerable, IReadOnlyCollection, ICollection, IDataIntegrity where T : struct { /// /// Stores the queue of items. /// private readonly Queue queue; /// /// Gets the hash code associated with the current state of the queue. /// public Int32 Hash { get; private set; } /// /// Gets the number of elements contained in the queue. /// public int Count => this.queue.Count; /// /// Gets a value indicating whether access to the queue is synchronized (thread-safe). /// bool ICollection.IsSynchronized => ((ICollection)this.queue).IsSynchronized; /// /// Gets an object that can be used to synchronize access to the queue. /// object ICollection.SyncRoot => ((ICollection)this.queue).SyncRoot; /// /// Get if the protected value has integrity, i.e., whether it has maintained its original state. /// public bool HasIntegrity { get; private set; } = true; /// /// Initializes a new instance of the class. /// public ProtectedQueue() { this.queue = new Queue(); this.Hash = this.GetHashCode(); } /// /// Initializes a new instance of the class that contains elements copied from the specified collection. /// /// The collection whose elements are copied to the new queue. public ProtectedQueue(IEnumerable _Collection) { this.queue = new Queue(_Collection); this.Hash = this.GetHashCode(); } /// /// Initializes a new instance of the class with the specified initial capacity. /// /// The initial number of elements that the queue can contain. public ProtectedQueue(int _Capacity) { this.queue = new Queue(_Capacity); this.Hash = this.GetHashCode(); } /// /// Determines whether the queue contains a specific value. /// /// The object to locate in the queue. /// true if item is found in the queue; otherwise, false. public bool Contains(T _Item) => this.queue.Contains(_Item); /// /// Adds an object to the end of the queue. /// /// The object to add to the queue. public void Enqueue(T _Item) { // Enqueue the new item to the queue. this.queue.Enqueue(_Item); // Add the new item to the hash code. this.Hash = this.AddToHashCode(this.Hash, _Item); } /// /// Returns the object at the beginning of the queue without removing it. /// /// The object at the beginning of the queue. public T Peek() => this.queue.Peek(); /// /// Removes and returns the object at the beginning of the queue. /// /// The object removed from the beginning of the queue. public T Dequeue() { // Dequeue the item from the queue. T var_Item = this.queue.Dequeue(); // Remove the item from the hash code. this.Hash = this.RemoveFromHashCode(this.Hash, var_Item); // Return the dequeued item. return var_Item; } /// /// Copies the elements of the ICollection to an Array, starting at a particular Array index. /// /// The one-dimensional Array that is the destination of the elements copied from the ICollection. /// The zero-based index in _Array at which copying begins. void ICollection.CopyTo(Array _Array, int _Index) => ((ICollection)this.queue).CopyTo(_Array, _Index); /// /// Copies the elements of the queue to an array, starting at a particular array index. /// /// The one-dimensional array that is the destination of the elements copied from the queue. /// The zero-based index in array at which copying begins. public void CopyTo(T[] _Array, int _ArrayIndex) => this.queue.CopyTo(_Array, _ArrayIndex); /// /// Sets the capacity to the actual number of elements in the queue, if that number is less than a threshold value. /// public void TrimExcess() => this.queue.TrimExcess(); /// /// Returns the object at the beginning of the queue without removing it and returns whether the operation succeeded. /// /// When this method returns, contains the object at the beginning of the queue, if the queue is not empty; otherwise, the default value for the element type. /// true if there was an object to return; otherwise, false. public bool TryPeek(out T _Result) { if (this.queue.Count > 0) { _Result = this.Peek(); return true; } _Result = default; return false; } /// /// Removes and returns the object at the beginning of the queue and returns whether the operation succeeded. /// /// When this method returns, contains the object removed from the beginning of the queue, if the queue is not empty; otherwise, the default value for the element type. /// true if there was an object to return; otherwise, false. public bool TryDequeue(out T _Result) { if (this.queue.Count > 0) { _Result = this.Dequeue(); return true; } _Result = default; return false; } /// /// Copies the elements of the queue to a new array. /// /// An array containing copies of the elements of the queue. public T[] ToArray() => this.queue.ToArray(); /// /// Removes all elements from the queue. /// public void Clear() { // Clear the queue. this.queue.Clear(); // Reset the hash code. this.Hash = this.GetHashCode(); } /// /// Verifies the integrity of the queue by comparing the current hash with the computed hash. /// /// True if the queue is verified successfully; otherwise, false. public bool CheckIntegrity() { Int32 currentHash = this.GetHashCode(); if (this.Hash != currentHash) { this.HasIntegrity = false; } return this.HasIntegrity; } /// /// Returns a hash code for the queue based on its elements. /// /// A hash code for the current queue. public override int GetHashCode() { // Initialize the hash code with a prime number. int var_Hash = 17; // Iterate through the queue and add each item to the hash code. foreach (T var_Item in this.queue) { var_Hash = this.AddToHashCode(var_Hash, var_Item); } // Return the final hash code. return var_Hash; } /// /// Add a new item to the hash, instead of calculating the hash code from scratch. /// /// The current hash code. /// The item to add to the hash code. /// The new hash code. private int AddToHashCode(int _HashCode, T _Item) { // Make sure to not throw an exception when an overflow occurs and wrap the result. unchecked { return _HashCode + _Item.GetHashCode() * 23; } } /// /// Remove an existing item from the hash, instead of calculating the hash code from scratch. /// /// The current hash code. /// The item to remove from the hash code. /// The new hash code. private int RemoveFromHashCode(int _HashCode, T _Item) { // Make sure to not throw an exception when an overflow occurs and wrap the result. unchecked { return _HashCode - _Item.GetHashCode() * 23; } } /// /// Returns an enumerator that iterates through the elements of the queue. /// /// An enumerator for the queue. public IEnumerator GetEnumerator() => this.queue.GetEnumerator(); /// /// Returns an enumerator that iterates through the elements of the queue. /// /// An enumerator for the queue. IEnumerator IEnumerable.GetEnumerator() => this.queue.GetEnumerator(); } }