Browse Source

initial skeleton of discontinuous buffer object model

af/octree-no-pixelmap
Anton Firszov 6 years ago
parent
commit
d90ece2729
  1. 6
      src/ImageSharp/ImageSharp.csproj
  2. 10
      src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs
  3. 5
      src/ImageSharp/Memory/Allocators/MemoryAllocator.cs
  4. 5
      src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs
  5. 2
      src/ImageSharp/Memory/BufferArea{T}.cs
  6. 15
      src/ImageSharp/Memory/DiscontinuousProto/IUniformMemoryGroup{T}.cs
  7. 8
      src/ImageSharp/Memory/DiscontinuousProto/InvalidMemoryOperationException.cs
  8. 76
      src/ImageSharp/Memory/DiscontinuousProto/UniformMemoryGroupView{T}.cs
  9. 69
      src/ImageSharp/Memory/DiscontinuousProto/UniformMemoryGroup{T}.Allocated.cs
  10. 37
      src/ImageSharp/Memory/DiscontinuousProto/UniformMemoryGroup{T}.External.cs
  11. 40
      src/ImageSharp/Memory/DiscontinuousProto/UniformMemoryGroup{T}.cs
  12. 4
      tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs

6
src/ImageSharp/ImageSharp.csproj

@ -25,9 +25,9 @@
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('netstandard')) OR '$(TargetFramework)' == 'net472'">
<PackageReference Include="System.Numerics.Vectors"/>
<PackageReference Include="System.Buffers"/>
<PackageReference Include="System.Memory"/>
<PackageReference Include="System.Numerics.Vectors" />
<PackageReference Include="System.Buffers" />
<PackageReference Include="System.Memory" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3'">

10
src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs

@ -89,6 +89,14 @@ namespace SixLabors.ImageSharp.Memory
this.InitArrayPools();
}
/// <summary>
/// Gets or sets the length of the largest contiguous buffer that can be handled by this allocator instance.
/// </summary>
public int MaximumContiguousBufferLength { get; set; } = Int32.MaxValue;
/// <inheritdoc />
protected internal override int GetMaximumContiguousBufferLength() => this.MaximumContiguousBufferLength;
/// <inheritdoc />
public override IMemoryOwner<T> Allocate<T>(int length, AllocationOptions options = AllocationOptions.None)
{
@ -147,4 +155,4 @@ namespace SixLabors.ImageSharp.Memory
this.normalArrayPool = ArrayPool<byte>.Create(this.PoolSelectorThresholdInBytes, this.maxArraysPerBucketNormalPool);
}
}
}
}

5
src/ImageSharp/Memory/Allocators/MemoryAllocator.cs

@ -10,6 +10,11 @@ namespace SixLabors.ImageSharp.Memory
/// </summary>
public abstract class MemoryAllocator
{
/// <summary>
/// Gets the length of the largest contiguous buffer that can be handled by this allocator instance.
/// </summary>
protected internal abstract int GetMaximumContiguousBufferLength();
/// <summary>
/// Allocates an <see cref="IMemoryOwner{T}" />, holding a <see cref="System.Memory{T}"/> of length <paramref name="length"/>.
/// </summary>

5
src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs

@ -11,6 +11,9 @@ namespace SixLabors.ImageSharp.Memory
/// </summary>
public sealed class SimpleGcMemoryAllocator : MemoryAllocator
{
/// <inheritdoc />
protected internal override int GetMaximumContiguousBufferLength() => int.MaxValue;
/// <inheritdoc />
public override IMemoryOwner<T> Allocate<T>(int length, AllocationOptions options = AllocationOptions.None)
{
@ -27,4 +30,4 @@ namespace SixLabors.ImageSharp.Memory
return new BasicByteBuffer(new byte[length]);
}
}
}
}

2
src/ImageSharp/Memory/BufferArea{T}.cs

@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Memory
/// Represents a rectangular area inside a 2D memory buffer (<see cref="Buffer2D{T}"/>).
/// This type is kind-of 2D Span, but it can live on heap.
/// </summary>
/// <typeparam name="T">The element type</typeparam>
/// <typeparam name="T">The element type.</typeparam>
internal readonly struct BufferArea<T>
where T : struct
{

15
src/ImageSharp/Memory/DiscontinuousProto/IUniformMemoryGroup{T}.cs

@ -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; }
}
}

8
src/ImageSharp/Memory/DiscontinuousProto/InvalidMemoryOperationException.cs

@ -0,0 +1,8 @@
using System;
namespace SixLabors.ImageSharp.Memory.DiscontinuousProto
{
public class InvalidMemoryOperationException : InvalidOperationException
{
}
}

76
src/ImageSharp/Memory/DiscontinuousProto/UniformMemoryGroupView{T}.cs

@ -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();
}
}
}

69
src/ImageSharp/Memory/DiscontinuousProto/UniformMemoryGroup{T}.Allocated.cs

@ -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>));
}
}
}
}
}

37
src/ImageSharp/Memory/DiscontinuousProto/UniformMemoryGroup{T}.External.cs

@ -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
}
}
}
}

40
src/ImageSharp/Memory/DiscontinuousProto/UniformMemoryGroup{T}.cs

@ -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);
}
}
}

4
tests/ImageSharp.Tests/TestUtilities/TestMemoryAllocator.cs

@ -24,6 +24,8 @@ namespace SixLabors.ImageSharp.Tests.Memory
public IList<AllocationRequest> AllocationLog => this.allocationLog;
protected internal override int GetMaximumContiguousBufferLength() => int.MaxValue;
public override IMemoryOwner<T> Allocate<T>(int length, AllocationOptions options = AllocationOptions.None)
{
T[] array = this.AllocateArray<T>(length, options);
@ -152,4 +154,4 @@ namespace SixLabors.ImageSharp.Tests.Memory
}
}
}
}
}

Loading…
Cancel
Save