From 989300ecdf1aa61e00f0acb7ceaf5ba1d46f6481 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Mon, 13 Apr 2020 16:38:39 +0200 Subject: [PATCH] Added optimized IMemoryGroup.GetEnumerator() method --- .../DiscontiguousBuffers/IMemoryGroup{T}.cs | 10 ++++++++ .../MemoryGroupView{T}.cs | 15 ++++++++++-- .../MemoryGroup{T}.Consumed.cs | 23 +++++++++++++++---- .../MemoryGroup{T}.Owned.cs | 19 +++++++++++---- .../DiscontiguousBuffers/MemoryGroup{T}.cs | 16 ++++++++++--- 5 files changed, 70 insertions(+), 13 deletions(-) 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.