mirror of https://github.com/SixLabors/ImageSharp
12 changed files with 270 additions and 7 deletions
@ -0,0 +1,15 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Memory.DiscontinuousProto |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents a group of one or more uniformly-sized discontinuous memory segments.
|
||||
|
/// The last segment can be smaller than the preceding ones.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T">The element type.</typeparam>
|
||||
|
public interface IUniformMemoryGroup<T> : IReadOnlyList<Memory<T>> where T : struct |
||||
|
{ |
||||
|
bool IsValid { get; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,8 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Memory.DiscontinuousProto |
||||
|
{ |
||||
|
public class InvalidMemoryOperationException : InvalidOperationException |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,76 @@ |
|||||
|
using System; |
||||
|
using System.Buffers; |
||||
|
using System.Collections; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Memory.DiscontinuousProto |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Implements <see cref="IUniformMemoryGroup{T}"/>, defining a view for <see cref="UniformMemoryGroup{T}"/>
|
||||
|
/// rather than owning the segments.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// This type provides an indirection, protecting the users of publicly exposed memory API-s
|
||||
|
/// from internal memory-swaps. Whenever an internal swap happens, the <see cref="UniformMemoryGroupView{T}"/>
|
||||
|
/// instance becomes invalid, throwing an exception on all operations.
|
||||
|
/// </remarks>
|
||||
|
/// <typeparam name="T">The element type.</typeparam>
|
||||
|
public class UniformMemoryGroupView<T> : IUniformMemoryGroup<T> where T : struct |
||||
|
{ |
||||
|
private readonly UniformMemoryGroup<T> owner; |
||||
|
private readonly MemoryOwnerWrapper[] memoryWrappers; |
||||
|
|
||||
|
public UniformMemoryGroupView(UniformMemoryGroup<T> owner) |
||||
|
{ |
||||
|
this.IsValid = true; |
||||
|
this.owner = owner; |
||||
|
this.memoryWrappers = new MemoryOwnerWrapper[owner.Count]; |
||||
|
|
||||
|
for (int i = 0; i < owner.Count; i++) |
||||
|
{ |
||||
|
this.memoryWrappers[i] = new MemoryOwnerWrapper(this, i); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public IEnumerator<Memory<T>> GetEnumerator() => throw new NotImplementedException(); |
||||
|
|
||||
|
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); |
||||
|
|
||||
|
public int Count { get; } |
||||
|
|
||||
|
public Memory<T> this[int index] => throw new NotImplementedException(); |
||||
|
|
||||
|
public bool IsValid { get; internal set; } |
||||
|
|
||||
|
class MemoryOwnerWrapper : MemoryManager<T> |
||||
|
{ |
||||
|
private UniformMemoryGroupView<T> view; |
||||
|
|
||||
|
private int index; |
||||
|
|
||||
|
public MemoryOwnerWrapper(UniformMemoryGroupView<T> view, int index) |
||||
|
{ |
||||
|
this.view = view; |
||||
|
this.index = index; |
||||
|
} |
||||
|
|
||||
|
protected override void Dispose(bool disposing) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public override Span<T> GetSpan() |
||||
|
{ |
||||
|
if (!this.view.IsValid) |
||||
|
{ |
||||
|
throw new InvalidOperationException(); |
||||
|
} |
||||
|
|
||||
|
return this.view[this.index].Span; |
||||
|
} |
||||
|
|
||||
|
public override MemoryHandle Pin(int elementIndex = 0) => throw new NotImplementedException(); |
||||
|
|
||||
|
public override void Unpin() => throw new NotImplementedException(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,69 @@ |
|||||
|
using System; |
||||
|
using System.Buffers; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Memory.DiscontinuousProto |
||||
|
{ |
||||
|
public abstract partial class UniformMemoryGroup<T> |
||||
|
{ |
||||
|
private class Allocated : UniformMemoryGroup<T> |
||||
|
{ |
||||
|
private IMemoryOwner<T>[] memoryOwners; |
||||
|
|
||||
|
public Allocated(IMemoryOwner<T>[] memoryOwners) |
||||
|
{ |
||||
|
this.memoryOwners = memoryOwners; |
||||
|
} |
||||
|
|
||||
|
public override IEnumerator<Memory<T>> GetEnumerator() |
||||
|
{ |
||||
|
this.EnsureNotDisposed(); |
||||
|
return this.memoryOwners.Select(mo => mo.Memory).GetEnumerator(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
public override int Count |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
this.EnsureNotDisposed(); |
||||
|
return this.memoryOwners.Length; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override Memory<T> this[int index] |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
this.EnsureNotDisposed(); |
||||
|
return this.memoryOwners[index].Memory; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override void Dispose() |
||||
|
{ |
||||
|
if (this.memoryOwners == null) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
foreach (IMemoryOwner<T> memoryOwner in this.memoryOwners) |
||||
|
{ |
||||
|
memoryOwner.Dispose(); |
||||
|
} |
||||
|
|
||||
|
this.memoryOwners = null; |
||||
|
this.IsValid = false; |
||||
|
} |
||||
|
|
||||
|
private void EnsureNotDisposed() |
||||
|
{ |
||||
|
if (this.memoryOwners == null) |
||||
|
{ |
||||
|
throw new ObjectDisposedException(nameof(UniformMemoryGroup<T>)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,37 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Memory.DiscontinuousProto |
||||
|
{ |
||||
|
public abstract partial class UniformMemoryGroup<T> |
||||
|
{ |
||||
|
private class External : UniformMemoryGroup<T> |
||||
|
{ |
||||
|
private readonly ReadOnlyMemory<Memory<T>> source; |
||||
|
|
||||
|
public External(ReadOnlyMemory<Memory<T>> source) |
||||
|
{ |
||||
|
// TODO: sizes should be uniform, validate!
|
||||
|
|
||||
|
this.source = source; |
||||
|
} |
||||
|
|
||||
|
public override IEnumerator<Memory<T>> GetEnumerator() |
||||
|
{ |
||||
|
for (int i = 0; i < this.source.Length; i++) |
||||
|
{ |
||||
|
yield return this.source.Span[i]; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public override int Count => this.source.Length; |
||||
|
|
||||
|
public override Memory<T> this[int index] => this.source.Span[index]; |
||||
|
|
||||
|
public override void Dispose() |
||||
|
{ |
||||
|
// No ownership nothing to dispose
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,40 @@ |
|||||
|
using System; |
||||
|
using System.Collections; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Memory.DiscontinuousProto |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Represents a group of one or more uniformly-sized discontinuous memory segments, owned by this instance.
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T">The element type.</typeparam>
|
||||
|
public abstract partial class UniformMemoryGroup<T> : IUniformMemoryGroup<T>, IDisposable where T : struct |
||||
|
{ |
||||
|
public abstract IEnumerator<Memory<T>> GetEnumerator(); |
||||
|
|
||||
|
IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); |
||||
|
|
||||
|
public abstract int Count { get; } |
||||
|
|
||||
|
public abstract Memory<T> this[int index] { get; } |
||||
|
|
||||
|
public abstract void Dispose(); |
||||
|
|
||||
|
public bool IsValid { get; protected set; } |
||||
|
|
||||
|
public static UniformMemoryGroup<T> Allocate(MemoryAllocator allocator, long length) |
||||
|
{ |
||||
|
long bufferCount = length / allocator.GetMaximumContiguousBufferLength(); |
||||
|
|
||||
|
// TODO: Allocate bufferCount buffers
|
||||
|
throw new NotImplementedException(); |
||||
|
} |
||||
|
|
||||
|
public static UniformMemoryGroup<T> Wrap(params Memory<T>[] source) => Wrap(source.AsMemory()); |
||||
|
|
||||
|
public static UniformMemoryGroup<T> Wrap(ReadOnlyMemory<Memory<T>> source) |
||||
|
{ |
||||
|
return new External(source); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue