using Misaki.HighPerformance.Unsafe.Collections.Contracts; using Misaki.HighPerformance.Unsafe.Helpers; using Misaki.HighPerformance.Unsafe.Services; using System.Collections; using System.Runtime.CompilerServices; namespace Misaki.HighPerformance.Unsafe.Collections; /// /// A structure for managing an array of unmanaged types with unsafe memory operations. /// /// Represents a type that can be stored in an unmanaged memory context. public unsafe struct UnsafeArray : IUnsafeCollection where T : unmanaged { public struct Enumerator : IEnumerator { private UnsafeArray* _collection; private int _index; private T _value; public Enumerator(UnsafeArray* collection) { _collection = collection; _index = -1; _value = default; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool MoveNext() { _index++; if (_index < _collection->_count) { _value = UnsafeUtilities.ReadArrayElement(_collection->_buffer, _index); return true; } _value = default; return false; } public void Reset() { _index = -1; } // Let NativeArray indexer check for out of range. public readonly T Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _value; } readonly object IEnumerator.Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Current; } public void Dispose() { } } private T* _buffer; private int _count; private readonly Allocator _allocator; public readonly int Count => _count; public readonly ref T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => ref UnsafeUtilities.ReadArrayElementRef(_buffer, index); } public readonly bool IsCreated { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _buffer != null; } public IEnumerator GetEnumerator() => new Enumerator((UnsafeArray*)UnsafeUtilities.AddressOf(ref this)); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); /// /// Initializes a new instance of UnsafeArray with a specified number of elements and an allocation type. It /// allocates memory and optionally clears it. /// /// Specifies the number of elements to allocate in the array, which must be greater than zero. /// Specifies the allocator to use for memory allocation, which determines the memory management strategy. /// Determines how the allocated memory should be initialized, either uninitialized or cleared. /// Thrown when the specified number of elements is less than or equal to zero. public UnsafeArray(int count, Allocator allocator, AllocationOption allocationOption = AllocationOption.None) { if (count <= 0) { throw new ArgumentOutOfRangeException(nameof(count), "Count must be greater than zero."); } _buffer = AllocationManager.Allocate((uint)count, (uint)AlignOf(), allocator, allocationOption); _count = count; _allocator = allocator; if (allocationOption == AllocationOption.Clear) { Clear(); } } /// /// Initializes an UnsafeArray with a pointer to a buffer and a count of elements. /// /// A pointer to the memory location that holds the elements of the array. /// The total size of the data. public UnsafeArray(void* buffer, int count) { _buffer = (T*)buffer; _count = count; } public void Resize(int newSize) { if (newSize == _count) { return; } _buffer = AllocationManager.Realloc(_buffer, (uint)newSize, (uint)AlignOf(), _allocator); _count = newSize; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void Clear() { MemClear(_buffer, (nuint)(_count * sizeof(T))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly void* GetUnsafePtr() { return _buffer; } public void Dispose() { AllocationManager.Free(_buffer, _allocator); _buffer = null; _count = 0; } }