diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs
index 89aca914d0..3bb6b8d336 100644
--- a/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs
+++ b/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs
@@ -33,5 +33,15 @@ namespace SixLabors.ImageSharp.Memory
/// the image buffers internally.
///
bool IsValid { get; }
+
+ ///
+ /// Returns a value-type implementing an allocation-free enumerator of the memory groups in the current
+ /// instance. The return type shouldn't be used directly: just use a block on
+ /// the instance in use and the C# compiler will automatically invoke this
+ /// method behind the scenes. This method takes precedence over the
+ /// implementation, which is still available when casting to one of the underlying interfaces.
+ ///
+ /// A new instance mapping the current values in use.
+ new MemoryGroupEnumerator GetEnumerator();
}
}
diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs
index 3f39ba12f5..1698f08d17 100644
--- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs
+++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs
@@ -5,6 +5,7 @@ using System;
using System.Buffers;
using System.Collections;
using System.Collections.Generic;
+using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Memory
{
@@ -37,6 +38,7 @@ namespace SixLabors.ImageSharp.Memory
public int Count
{
+ [MethodImpl(InliningOptions.ShortMethod)]
get
{
this.EnsureIsValid();
@@ -73,7 +75,15 @@ namespace SixLabors.ImageSharp.Memory
}
}
- public IEnumerator> GetEnumerator()
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public MemoryGroupEnumerator GetEnumerator()
+ {
+ return new MemoryGroupEnumerator(this);
+ }
+
+ ///
+ IEnumerator> IEnumerable>.GetEnumerator()
{
this.EnsureIsValid();
for (int i = 0; i < this.Count; i++)
@@ -82,7 +92,8 @@ namespace SixLabors.ImageSharp.Memory
}
}
- IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
+ ///
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable>)this).GetEnumerator();
internal void Invalidate()
{
diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs
index 493fe6e336..1dfbaea932 100644
--- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs
+++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs
@@ -3,13 +3,16 @@
using System;
using System.Collections.Generic;
+using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Memory
{
internal abstract partial class MemoryGroup
{
- // Analogous to the "consumed" variant of MemorySource
- private sealed class Consumed : MemoryGroup
+ ///
+ /// A implementation that consumes the underlying memory buffers.
+ ///
+ public sealed class Consumed : MemoryGroup, IEnumerable>
{
private readonly Memory[] source;
@@ -20,11 +23,23 @@ namespace SixLabors.ImageSharp.Memory
this.View = new MemoryGroupView(this);
}
- public override int Count => this.source.Length;
+ public override int Count
+ {
+ [MethodImpl(InliningOptions.ShortMethod)]
+ get => this.source.Length;
+ }
public override Memory this[int index] => this.source[index];
- public override IEnumerator> GetEnumerator()
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public override MemoryGroupEnumerator GetEnumerator()
+ {
+ return new MemoryGroupEnumerator(this);
+ }
+
+ ///
+ IEnumerator> IEnumerable>.GetEnumerator()
{
/* The runtime sees the Array class as if it implemented the
* type-generic collection interfaces explicitly, so here we
diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs
index 276dee7ed0..5a86ac4268 100644
--- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs
+++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs
@@ -9,10 +9,12 @@ using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Memory
{
- // Analogous to the "owned" variant of MemorySource
internal abstract partial class MemoryGroup
{
- private sealed class Owned : MemoryGroup
+ ///
+ /// A implementation that owns the underlying memory buffers.
+ ///
+ public sealed class Owned : MemoryGroup, IEnumerable>
{
private IMemoryOwner[] memoryOwners;
@@ -30,6 +32,7 @@ namespace SixLabors.ImageSharp.Memory
public override int Count
{
+ [MethodImpl(InliningOptions.ShortMethod)]
get
{
this.EnsureNotDisposed();
@@ -46,7 +49,15 @@ namespace SixLabors.ImageSharp.Memory
}
}
- public override IEnumerator> GetEnumerator()
+ ///
+ [MethodImpl(InliningOptions.ShortMethod)]
+ public override MemoryGroupEnumerator GetEnumerator()
+ {
+ return new MemoryGroupEnumerator(this);
+ }
+
+ ///
+ IEnumerator> IEnumerable>.GetEnumerator()
{
this.EnsureNotDisposed();
return this.memoryOwners.Select(mo => mo.Memory).GetEnumerator();
@@ -70,7 +81,7 @@ namespace SixLabors.ImageSharp.Memory
this.IsValid = false;
}
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ [MethodImpl(InliningOptions.ShortMethod)]
private void EnsureNotDisposed()
{
if (this.memoryOwners is null)
diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs
index 38de57b4ac..6fd93f12ea 100644
--- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs
+++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs
@@ -6,7 +6,6 @@ using System.Buffers;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
-using SixLabors.ImageSharp.Memory.Internals;
namespace SixLabors.ImageSharp.Memory
{
@@ -48,10 +47,21 @@ namespace SixLabors.ImageSharp.Memory
public abstract void Dispose();
///
- public abstract IEnumerator> GetEnumerator();
+ public abstract MemoryGroupEnumerator GetEnumerator();
///
- IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator();
+ IEnumerator> IEnumerable>.GetEnumerator()
+ {
+ /* This method is implemented in each derived class.
+ * Implementing the method here as non-abstract and throwing,
+ * then reimplementing it explicitly in each derived class, is
+ * a workaround for the lack of support for abstract explicit
+ * interface method implementations in C#. */
+ throw new NotImplementedException($"The type {this.GetType()} needs to override IEnumerable>.GetEnumerator()");
+ }
+
+ ///
+ IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable>)this).GetEnumerator();
///
/// Creates a new memory group, allocating it's buffers with the provided allocator.