using Misaki.HighPerformance.LowLevel.Utilities; using System.Collections; using System.Runtime.CompilerServices; namespace Misaki.HighPerformance.LowLevel.Collections; /// /// Provides a read-only, unsafe view over a contiguous region of unmanaged memory as an array of elements of type T. /// Enables efficient, low-level access to memory without copying or additional safety checks. /// /// /// This read only collection does not own the memory it points to. The user is responsible for ensuring the memory remains valid for the lifetime of this structure. /// The goal of this struc is similar to , but it can be used in contexts where spans are not allowed, such as fields in structs and shared across threads. /// /// The type of elements in the collection. Must be an unmanaged type. public readonly unsafe struct ReadOnlyUnsafeCollection : IEnumerable where T : unmanaged { public struct Enumerator : IEnumerator { private readonly ReadOnlyUnsafeCollection _collection; private int _index; private T _value; public readonly T Current { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _value; } readonly object IEnumerator.Current => Current; public Enumerator(ref readonly ReadOnlyUnsafeCollection array) { _collection = array; _index = -1; _value = default; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool MoveNext() { _index++; if (_index < _collection.Count) { _value = UnsafeUtility.ReadArrayElement(_collection._buffer, _index); return true; } _value = default; return false; } public void Reset() { _index = -1; } public void Dispose() { } } private readonly T* _buffer; private readonly int _count; public readonly int Count => _count; public readonly T this[int index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => UnsafeUtility.ReadArrayElement(_buffer, index); } public readonly T this[uint index] { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => UnsafeUtility.ReadArrayElement(_buffer, index); } public IEnumerator GetEnumerator() => new Enumerator(in this); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public ReadOnlyUnsafeCollection(T* buffer, int count) { _buffer = buffer; _count = count; } /// /// Returns a read-only span that represents the valid elements in the underlying buffer. /// /// A containing the elements of the buffer up to the current count. public ReadOnlySpan AsSpan() { return new ReadOnlySpan(_buffer, _count); } /// /// Reinterprets the underlying collection as a read-only collection of a different unmanaged type without copying the data. /// /// The unmanaged type to reinterpret the collection elements as. /// A new ReadOnlyUnsafeCollection that provides a read-only view of the same memory, interpreted as elements of type U. /// Thrown if the total size of the underlying collection is not a multiple of the size of type U, making the reinterpretation invalid. public ReadOnlyUnsafeCollection Reinterpret() where U : unmanaged { var totalSize = (nuint)(Count * sizeof(T)); if (totalSize % (nuint)sizeof(U) != 0) { throw new InvalidOperationException("Cannot reinterpret collection: size mismatch."); } var newCount = (int)(totalSize / (nuint)sizeof(U)); return new ReadOnlyUnsafeCollection((U*)_buffer, newCount); } }