Browse Source

Added optimized IMemoryGroup<T>.GetEnumerator() method

pull/1574/head
Sergio Pedri 6 years ago
parent
commit
a6e70a9c3e
  1. 10
      src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs
  2. 15
      src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs
  3. 23
      src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs
  4. 19
      src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs
  5. 16
      src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs

10
src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs

@ -33,5 +33,15 @@ namespace SixLabors.ImageSharp.Memory
/// the image buffers internally. /// the image buffers internally.
/// </remarks> /// </remarks>
bool IsValid { get; } bool IsValid { get; }
/// <summary>
/// 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 <see langword="foreach"/> block on
/// the <see cref="IMemoryGroup{T}"/> instance in use and the C# compiler will automatically invoke this
/// method behind the scenes. This method takes precedence over the <see cref="IEnumerable{T}.GetEnumerator"/>
/// implementation, which is still available when casting to one of the underlying interfaces.
/// </summary>
/// <returns>A new <see cref="MemoryGroupEnumerator{T}"/> instance mapping the current <see cref="Memory{T}"/> values in use.</returns>
new MemoryGroupEnumerator<T> GetEnumerator();
} }
} }

15
src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs

@ -5,6 +5,7 @@ using System;
using System.Buffers; using System.Buffers;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Memory namespace SixLabors.ImageSharp.Memory
{ {
@ -37,6 +38,7 @@ namespace SixLabors.ImageSharp.Memory
public int Count public int Count
{ {
[MethodImpl(InliningOptions.ShortMethod)]
get get
{ {
this.EnsureIsValid(); this.EnsureIsValid();
@ -73,7 +75,15 @@ namespace SixLabors.ImageSharp.Memory
} }
} }
public IEnumerator<Memory<T>> GetEnumerator() /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public MemoryGroupEnumerator<T> GetEnumerator()
{
return new MemoryGroupEnumerator<T>(this);
}
/// <inheritdoc/>
IEnumerator<Memory<T>> IEnumerable<Memory<T>>.GetEnumerator()
{ {
this.EnsureIsValid(); this.EnsureIsValid();
for (int i = 0; i < this.Count; i++) for (int i = 0; i < this.Count; i++)
@ -82,7 +92,8 @@ namespace SixLabors.ImageSharp.Memory
} }
} }
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); /// <inheritdoc/>
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<Memory<T>>)this).GetEnumerator();
internal void Invalidate() internal void Invalidate()
{ {

23
src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs

@ -3,13 +3,16 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Memory namespace SixLabors.ImageSharp.Memory
{ {
internal abstract partial class MemoryGroup<T> internal abstract partial class MemoryGroup<T>
{ {
// Analogous to the "consumed" variant of MemorySource /// <summary>
private sealed class Consumed : MemoryGroup<T> /// A <see cref="MemoryGroup{T}"/> implementation that consumes the underlying memory buffers.
/// </summary>
public sealed class Consumed : MemoryGroup<T>, IEnumerable<Memory<T>>
{ {
private readonly Memory<T>[] source; private readonly Memory<T>[] source;
@ -20,11 +23,23 @@ namespace SixLabors.ImageSharp.Memory
this.View = new MemoryGroupView<T>(this); this.View = new MemoryGroupView<T>(this);
} }
public override int Count => this.source.Length; public override int Count
{
[MethodImpl(InliningOptions.ShortMethod)]
get => this.source.Length;
}
public override Memory<T> this[int index] => this.source[index]; public override Memory<T> this[int index] => this.source[index];
public override IEnumerator<Memory<T>> GetEnumerator() /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override MemoryGroupEnumerator<T> GetEnumerator()
{
return new MemoryGroupEnumerator<T>(this);
}
/// <inheritdoc/>
IEnumerator<Memory<T>> IEnumerable<Memory<T>>.GetEnumerator()
{ {
/* The runtime sees the Array class as if it implemented the /* The runtime sees the Array class as if it implemented the
* type-generic collection interfaces explicitly, so here we * type-generic collection interfaces explicitly, so here we

19
src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs

@ -9,10 +9,12 @@ using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Memory namespace SixLabors.ImageSharp.Memory
{ {
// Analogous to the "owned" variant of MemorySource
internal abstract partial class MemoryGroup<T> internal abstract partial class MemoryGroup<T>
{ {
private sealed class Owned : MemoryGroup<T> /// <summary>
/// A <see cref="MemoryGroup{T}"/> implementation that owns the underlying memory buffers.
/// </summary>
public sealed class Owned : MemoryGroup<T>, IEnumerable<Memory<T>>
{ {
private IMemoryOwner<T>[] memoryOwners; private IMemoryOwner<T>[] memoryOwners;
@ -30,6 +32,7 @@ namespace SixLabors.ImageSharp.Memory
public override int Count public override int Count
{ {
[MethodImpl(InliningOptions.ShortMethod)]
get get
{ {
this.EnsureNotDisposed(); this.EnsureNotDisposed();
@ -46,7 +49,15 @@ namespace SixLabors.ImageSharp.Memory
} }
} }
public override IEnumerator<Memory<T>> GetEnumerator() /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override MemoryGroupEnumerator<T> GetEnumerator()
{
return new MemoryGroupEnumerator<T>(this);
}
/// <inheritdoc/>
IEnumerator<Memory<T>> IEnumerable<Memory<T>>.GetEnumerator()
{ {
this.EnsureNotDisposed(); this.EnsureNotDisposed();
return this.memoryOwners.Select(mo => mo.Memory).GetEnumerator(); return this.memoryOwners.Select(mo => mo.Memory).GetEnumerator();
@ -70,7 +81,7 @@ namespace SixLabors.ImageSharp.Memory
this.IsValid = false; this.IsValid = false;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
private void EnsureNotDisposed() private void EnsureNotDisposed()
{ {
if (this.memoryOwners is null) if (this.memoryOwners is null)

16
src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs

@ -6,7 +6,6 @@ using System.Buffers;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory.Internals;
namespace SixLabors.ImageSharp.Memory namespace SixLabors.ImageSharp.Memory
{ {
@ -48,10 +47,21 @@ namespace SixLabors.ImageSharp.Memory
public abstract void Dispose(); public abstract void Dispose();
/// <inheritdoc /> /// <inheritdoc />
public abstract IEnumerator<Memory<T>> GetEnumerator(); public abstract MemoryGroupEnumerator<T> GetEnumerator();
/// <inheritdoc /> /// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); IEnumerator<Memory<T>> IEnumerable<Memory<T>>.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<Memory<T>>.GetEnumerator()");
}
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<Memory<T>>)this).GetEnumerator();
/// <summary> /// <summary>
/// Creates a new memory group, allocating it's buffers with the provided allocator. /// Creates a new memory group, allocating it's buffers with the provided allocator.

Loading…
Cancel
Save