IMemory
IMemory is interface for types that manage memory regions.
/// <summary>Interface to memory segment.</summary>
/// <remarks>The underlying implementation may expose <see cref="IDecoration"/></remarks>
public interface IMemory : IList, IDisposable
{
/// <summary>Element type, <see cref="byte"/> or <see cref="char"/>.</summary>
Type ElementType { get; }
/// <summary>Return accessible bytes</summary>
/// <exception cref="NotSupportedException">If <see cref="IList.IsFixedSize"/> or <see cref="IList.IsReadOnly"/> is true.</exception>
new long Count { get; set; }
/// <summary>
/// Maximum possible number of elements this memory can grow up to.
/// If <see cref="IList.IsFixedSize"/> is true, then this returns same value as <see cref="Count"/>.
/// </summary>
long MaxCount { get; }
/// <summary>Insert <paramref name="count"/> elements at <paramref name="atIndex"/>. The newly added region is not initialized with default value of <see cref="ElementType"/>.</summary>
/// <exception cref="IOException"></exception>
/// <exception cref="NotSupportedException">If <see cref="IList.IsFixedSize"/> or <see cref="IList.IsReadOnly"/> is true.</exception>
void InsertElementsAt(long atIndex, long count);
/// <summary>Remove <paramref name="count"/> elements at <paramref name="atIndex"/>.</summary>
/// <exception cref="IOException"></exception>
/// <exception cref="NotSupportedException">If <see cref="IList.IsFixedSize"/> or <see cref="IList.IsReadOnly"/> is true.</exception>
void RemoveElementsAt(long atIndex, long count);
/// <summary>Flush changes to source.</summary>
/// <exception cref="IOException"></exception>
void Flush();
/// <summary>Create a sliced versio where offset is advanced by <paramref name="memoryIndex"/>.</summary>
/// <exception cref="ArgumentOutOfRangeException">An argument is out of range</exception>
IMemory Slice(long index);
/// <summary>Create a sliced versio where offset is advanced by <paramref name="memoryIndex"/> and has count limit of <paramref name="length"/>.</summary>
/// <exception cref="ArgumentOutOfRangeException">An argument is out of range</exception>
IMemory Slice(long index, long length);
/// <summary>Action that is invoked after writing. Note! Some implementations may process the event under lock.</summary>
event Action OnWrite;
/// <summary>Action that is invoked after reading content. Note! Some implementations may process the event under lock.</summary>
event Action OnRead;
}
/// <summary>Interface to memory segment.</summary>
/// <remarks>The underlying implementation may expose <see cref="IDecoration"/></remarks>
public interface IMemory<T> : IList<T>, IMemory
{
/// <summary>Are elements of the memory read-only.</summary>
new bool IsReadOnly { get; }
/// <summary>Number of elements</summary>
/// <exception cref="NotSupportedException">If count cannot be modified. See <see cref="IList.IsFixedSize"/> whether count is fixed.</exception>
new long Count { get; set; }
/// <summary>Indexer</summary>
/// <exception cref="IndexOutOfRangeException"> if <paramref name="memoryIndex"/> is out of range.</exception>
/// <exception cref="NotSupportedException">On 'set' if <see cref="IList.IsReadOnly"/> is true.</exception>
T this[long memoryIndex] { get; set; }
/// <summary>Read <paramref name="item"/> at <paramref name="atIndex"/>.</summary>
/// <param name="atIndex">Index on the memory object.</param>
/// <exception cref="ArgumentOutOfRangeException">An argument is out of range</exception>
/// <exception cref="NotSupportedException">If <see cref="IList.IsFixedSize"/> or <see cref="IList.IsReadOnly"/> is true.</exception>
void Insert(long atIndex, T item);
/// <summary>Insert all elements from <paramref name="srcItems"/> at <paramref name="atIndex"/>.</summary>
/// <param name="srcItems">A collection source for 32-bit operation, or a <see cref="IMemory{T}"/> for 64-bit operation. To read from array, cast to <see cref="IList{T}"/>.</param>
/// <param name="atIndex">Index on the memory object.</param>
/// <exception cref="ArgumentOutOfRangeException">An argument is out of range</exception>
/// <exception cref="NotSupportedException">If <see cref="IList.IsFixedSize"/> or <see cref="IList.IsReadOnly"/> is true.</exception>
/// <remarks>If a slice of <paramref name="srcItems"/> is needed, <![CDATA[Slice<T>]]> can be used.</remarks>
void InsertFrom(ICollection<T> srcItems, long atIndex);
/// <summary>Insert all elements from <paramref name="srcSpan"/> at <paramref name="atIndex"/>.</summary>
/// <param name="atIndex">Index on the memory object.</param>
/// <exception cref="ArgumentOutOfRangeException">An argument is out of range</exception>
/// <exception cref="NotSupportedException">If <see cref="IList.IsFixedSize"/> or <see cref="IList.IsReadOnly"/> is true.</exception>
void InsertFrom(ReadOnlySpan<T> srcSpan, long atIndex);
/// <summary>Read elements from <paramref name="srcItems"/> and write at <paramref name="atIndex"/> in the memory object.</summary>
/// <param name="srcItems">A collection source for 32-bit operation, or a <see cref="IMemory{T}"/> for 64-bit operation.</param>
/// <param name="atIndex">Index on the memory object.</param>
/// <exception cref="ArgumentOutOfRangeException">An argument is out of range</exception>
/// <exception cref="NotSupportedException">If <see cref="IList.IsReadOnly"/> is true.</exception>
/// <remarks>If a slice of <paramref name="srcItems"/> is needed, <![CDATA[Slice<T>]]> can be used.</remarks>
void ReadFrom(ICollection<T> srcItems, long atIndex);
/// <summary>Read elements from <paramref name="srcSpan"/> and write at <paramref name="atIndex"/> in the memory object.</summary>
/// <param name="atIndex">Index on the memory object.</param>
/// <exception cref="ArgumentOutOfRangeException">An argument is out of range</exception>
/// <exception cref="NotSupportedException">If <see cref="IList.IsReadOnly"/> is true.</exception>
void ReadFrom(ReadOnlySpan<T> srcSpan, long atIndex);
/// <summary>Write elements at <paramref name="atIndex"/> into <paramref name="dstSpan"/>.</summary>
/// <param name="atIndex">Index on the memory object.</param>
/// <exception cref="ArgumentOutOfRangeException">An argument is out of range</exception>
/// <exception cref="NotSupportedException">If <see cref="IList.IsReadOnly"/> is true.</exception>
void WriteTo(Span<T> dstSpan, long atIndex);
/// <summary>Write elements at <paramref name="atIndex"/> into <paramref name="dstItems"/>.</summary>
/// <param name="dstItems">A list target for 32-bit operation, or a <see cref="IMemory{T}"/> for 64-bit operation. To write to an array, cast to <see cref="IList{T}"/>.</param>
/// <param name="atIndex">Index on the memory object.</param>
/// <exception cref="ArgumentOutOfRangeException">An argument is out of range</exception>
/// <exception cref="NotSupportedException">If <see cref="IList.IsReadOnly"/> is true.</exception>
/// <remarks>Note that if <paramref name="dstItems"/> is struct-typed and on stack, then some changes will not be updated. Either box into heap, or use <see cref="ReadFrom(ICollection{T}, long)"/> on it.</remarks>
void WriteTo(IList<T> dstItems, long atIndex);
/// <summary>Determine index of <paramref name="item"/>.</summary>
/// <param name="startIndex">Start index (inclusive)</param>
/// <param name="endIndex">End index (exclusive). Value that exceeds content range is allowed and does not throw exception.</param>
/// <param name="equalityComparer">Optional overriding comparer.</param>
/// <returns>Index of <paramref name="item"/>, if not found then -1 is returned.</returns>
long IndexOf(T item, long startIndex = 0, long endIndex = long.MaxValue, IEqualityComparer<T>? equalityComparer = default);
/// <summary>Remove all elements by assigning Count to 0. May or may not assign default value to reserved contents.</summary>
/// <exception cref="NotSupportedException">If <see cref="IList.IsFixedSize"/> or <see cref="IList.IsReadOnly"/> is true.</exception>
new void Clear();
/// <summary>Create a sliced versio where offset is advanced by <paramref name="memoryIndex"/>.</summary>
/// <exception cref="ArgumentOutOfRangeException">An argument is out of range</exception>
new IMemory<T> Slice(long memoryIndex);
/// <summary>Create a sliced versio where offset is advanced by <paramref name="memoryIndex"/> and has count limit of <paramref name="length"/>.</summary>
/// <exception cref="ArgumentOutOfRangeException">An argument is out of range</exception>
new IMemory<T> Slice(long memoryIndex, long length);
}
IMemory inherits and is assignable to IList<T> and IList.
IMemory<T>
├── IMemory
│ ├── IDisposable
│ └── IList
│ ├── IEnumerable
│ └── ICollection
└── IList<T>
├── ICollection<T>
└── IEnumerable<T>
IMemory<T> has implementations to various memory content types.
// Create list as 'memory'
IMemory<byte> memory = new ListMemory<List<byte>, byte>(new());
Memory extends IList<T>.
// Adapt as 'memory'
IMemory<byte> memory = new ListMemory<List<byte>, byte>(new());
// Allocate
memory.Count = 10;
for (int i = 0; i < 10; i++) memory[i] = 10;
// Add more
for (int i = 0; i < 10; i++) memory.Add((byte)i);
// IEnumerable
byte[] array = memory.ToArray();
WriteLine(string.Join(", ", memory));
Array can be adapted to memory.
// Create 'array'
byte[] array = new byte[1024];
// Adapt 'array' as 'memory'
IMemory<byte> memory = new ListMemory<byte[], byte>(array);
If array is inserted or written to memory, it must be specific whether to use array as Span or ICollection.
// Create list as memory
IMemory<byte> memory = new ListMemory<List<byte>, byte>(new());
// Create 'array' for source
byte[] array = new byte[] { 1, 2, 3 };
// Copy 'array' contents to 'memory' twice
memory.InsertFrom(srcItems: array, 0L); // Insert as ICollection<byte>
memory.InsertFrom(srcSpan: array, 3L); // Insert as Span
Content can be copied between two memories.
// Create source and dst memories
IMemory<byte> src = new ListMemory<IList<byte>, byte>(new byte[] { 1, 2, 3 });
IMemory<byte> dst = new ListMemory<IList<byte>, byte>(new List<byte>());
// Copy from 'src' to 'dst'
dst.InsertFrom(src, 0L);
// Overwrite
dst.ReadFrom(src, 0L);
// Overwrite
src.WriteTo(dst, 0L);
.Slice(offset, count?) can be used to copy only a slice of memory.
// Create source and dst memories
IMemory<byte> src = new ListMemory<IList<byte>, byte>(new byte[] { 1, 2, 3, 4, 5, 6 });
IMemory<byte> dst = new ListMemory<IList<byte>, byte>(new List<byte>());
// Copy a slice from 'src' to 'dst'
dst.InsertFrom(src.Slice(2L, 2L), 0L);
Array are fixed-size memories, lists are variable-sized.
IMemory<byte> arrayMemory = new ListMemory<IList<byte>, byte>(new byte[] { 1, 2, 3, 4, 5, 6 });
IMemory<byte> listMemory = new ListMemory<IList<byte>, byte>(new List<byte>());
WriteLine(arrayMemory.IsFixedSize); // 'true'
WriteLine(listMemory.IsFixedSize); // 'false'
IMemory<byte> arrayAllocation = new Slice<IMemory<byte>, byte>(arrayMemory, offset: 0L, count: 0l, allocation: arrayMemory.Count);
WriteLine(arrayAllocation.IsFixedSize); // 'false'
arrayAllocation.Add(10); // Add to array
WriteLine(arrayMemory[0]); // '10'
Full Example
Full example
using Avalanche.Memory;
using static System.Console;
public class imemory
{
public static void Run()
{
{
// <01>
// Create list as 'memory'
IMemory<byte> memory = new ListMemory<List<byte>, byte>(new());
// </01>
}
{
// <02>
// Adapt as 'memory'
IMemory<byte> memory = new ListMemory<List<byte>, byte>(new());
// Allocate
memory.Count = 10;
for (int i = 0; i < 10; i++) memory[i] = 10;
// Add more
for (int i = 0; i < 10; i++) memory.Add((byte)i);
// IEnumerable
byte[] array = memory.ToArray();
WriteLine(string.Join(", ", memory));
// </02>
}
{
// <03>
// Create 'array'
byte[] array = new byte[1024];
// Adapt 'array' as 'memory'
IMemory<byte> memory = new ListMemory<byte[], byte>(array);
// </03>
}
{
// <04>
// Create list as memory
IMemory<byte> memory = new ListMemory<List<byte>, byte>(new());
// Create 'array' for source
byte[] array = new byte[] { 1, 2, 3 };
// Copy 'array' contents to 'memory' twice
memory.InsertFrom(srcItems: array, 0L); // Insert as ICollection<byte>
memory.InsertFrom(srcSpan: array, 3L); // Insert as Span
// </04>
}
{
// <05>
// Create source and dst memories
IMemory<byte> src = new ListMemory<IList<byte>, byte>(new byte[] { 1, 2, 3 });
IMemory<byte> dst = new ListMemory<IList<byte>, byte>(new List<byte>());
// Copy from 'src' to 'dst'
dst.InsertFrom(src, 0L);
// Overwrite
dst.ReadFrom(src, 0L);
// Overwrite
src.WriteTo(dst, 0L);
// </05>
}
{
// <06>
// Create source and dst memories
IMemory<byte> src = new ListMemory<IList<byte>, byte>(new byte[] { 1, 2, 3, 4, 5, 6 });
IMemory<byte> dst = new ListMemory<IList<byte>, byte>(new List<byte>());
// Copy a slice from 'src' to 'dst'
dst.InsertFrom(src.Slice(2L, 2L), 0L);
// </06>
}
{
// <07>
IMemory<byte> arrayMemory = new ListMemory<IList<byte>, byte>(new byte[] { 1, 2, 3, 4, 5, 6 });
IMemory<byte> listMemory = new ListMemory<IList<byte>, byte>(new List<byte>());
WriteLine(arrayMemory.IsFixedSize); // 'true'
WriteLine(listMemory.IsFixedSize); // 'false'
IMemory<byte> arrayAllocation = new Slice<IMemory<byte>, byte>(arrayMemory, offset: 0L, count: 0l, allocation: arrayMemory.Count);
WriteLine(arrayAllocation.IsFixedSize); // 'false'
arrayAllocation.Add(10); // Add to array
WriteLine(arrayMemory[0]); // '10'
// </07>
}
}
}