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;
}
}