using System; using System.Collections; using System.Collections.Generic; using Vanara.Extensions; using Vanara.InteropServices; namespace Vanara.PInvoke.Collections { /// Provides a generic enumerator over native memory. /// The type of the element to extract from memory. /// /// public class NativeMemoryEnumerator : UntypedNativeMemoryEnumerator, IEnumerator, IEnumerable { /// Initializes a new instance of the class. /// A pointer to the starting address of a specified number of elements in memory. /// The number of elements to be included in the enumeration. /// Bytes to skip before reading the first element. /// If known, the total number of bytes allocated to the native memory in . /// count /// public NativeMemoryEnumerator(IntPtr ptr, int length, int prefixBytes = 0, SizeT allocatedBytes = default) : base(ptr, typeof(T), length, prefixBytes, allocatedBytes) { } /// Gets the element in the collection at the current position of the enumerator. public new T Current => (T)base.Current; /// Returns an enumerator that iterates through the collection. /// A that can be used to iterate through the collection. public new IEnumerator GetEnumerator() => this; } /// Provides an enumerator over native memory. /// /// public class UntypedNativeMemoryEnumerator : IEnumerator, IEnumerable { /// The number of allocated bytes. protected SizeT allocated; /// The number of elements in the enumeration. protected int count; /// The index of the current item. (-2) signifies an error. (-1) means MoveNext has not been called.. protected int index = -1; /// The number of bytes to skip before reading the first element. protected int prefix; /// A pointer to the starting address of a specified number of elements in memory. protected IntPtr ptr; /// The size of . protected SizeT stSize; /// The type of the element to extract from memory. protected Type type; /// Initializes a new instance of the class. /// A pointer to the starting address of a specified number of elements in memory. /// The type of the element to extract from memory. /// The number of elements to be included in the enumeration. /// Bytes to skip before reading the first element. /// If known, the total number of bytes allocated to the native memory in . /// count /// type /// public UntypedNativeMemoryEnumerator(IntPtr ptr, Type type, int length, int prefixBytes = 0, SizeT allocatedBytes = default) { if (length < 0 || ptr == IntPtr.Zero && length != 0) throw new ArgumentOutOfRangeException(nameof(length)); if (type is null) throw new ArgumentNullException(nameof(type)); this.type = type; this.ptr = ptr; count = length; prefix = prefixBytes; allocated = allocatedBytes == default ? (SizeT)uint.MaxValue : allocatedBytes; stSize = InteropExtensions.SizeOf(type); if (allocatedBytes > 0 && stSize * length + prefixBytes > allocatedBytes) throw new InsufficientMemoryException(); } /// Gets the element in the collection at the current position of the enumerator. public virtual object Current { get { if (index < 0 || index >= count) throw new ArgumentOutOfRangeException(nameof(index)); var offset = prefix + index * stSize; return ptr.Offset(offset).Convert(allocated - (uint)offset - (uint)prefix, type); } } /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. public virtual void Dispose() { } /// Returns an enumerator that iterates through a collection. /// An object that can be used to iterate through the collection. public IEnumerator GetEnumerator() => this; /// Advances the enumerator to the next element of the collection. /// /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection. /// public bool MoveNext() { if (++index >= count) index = -2; return index >= 0; } /// Sets the enumerator to its initial position, which is before the first element in the collection. public void Reset() => index = -1; } }