Skip to content

Commit

Permalink
Fix Length for ReadOnlySequence created out of sliced Memory owned by…
Browse files Browse the repository at this point in the history
… MemoryManager (dotnet#57479)
  • Loading branch information
adamsitnik authored Aug 16, 2021
1 parent 4723f00 commit d7a7898
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ public ReadOnlySequence(ReadOnlyMemory<T> memory)
_startObject = manager;
_endObject = manager;
_startInteger = ReadOnlySequence.MemoryManagerToSequenceStart(index);
_endInteger = length;
_endInteger = index + length;
}
else if (MemoryMarshal.TryGetArray(memory, out ArraySegment<T> segment))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;

namespace System.Memory.Tests
{
public abstract class ReadOnlySequenceFactory<T>
{
public static ReadOnlySequenceFactory<T> ArrayFactory { get; } = new ArrayTestSequenceFactory();
public static ReadOnlySequenceFactory<T> MemoryFactory { get; } = new MemoryTestSequenceFactory();
public static ReadOnlySequenceFactory<T> MemoryManagerFactory { get; } = new MemoryManagerTestSequenceFactory();
public static ReadOnlySequenceFactory<T> SingleSegmentFactory { get; } = new SingleSegmentTestSequenceFactory();
public static ReadOnlySequenceFactory<T> SegmentPerItemFactory { get; } = new BytePerSegmentTestSequenceFactory();
public static ReadOnlySequenceFactory<T> SplitInThree { get; } = new SegmentsTestSequenceFactory(3);
Expand All @@ -37,7 +41,11 @@ internal class MemoryTestSequenceFactory : ReadOnlySequenceFactory<T>
{
public override ReadOnlySequence<T> CreateOfSize(int size)
{
return CreateWithContent(new T[size]);
#if DEBUG
return new ReadOnlySequence<T>(new ReadOnlyMemory<T>(new T[size + 1]).Slice(1));
#else
return new ReadOnlySequence<T>(new ReadOnlyMemory<T>(new T[size]));
#endif
}

public override ReadOnlySequence<T> CreateWithContent(T[] data)
Expand Down Expand Up @@ -112,6 +120,49 @@ public override ReadOnlySequence<T> CreateWithContent(T[] data)
}
}

internal class MemoryManagerTestSequenceFactory : ReadOnlySequenceFactory<T>
{
public override ReadOnlySequence<T> CreateOfSize(int size)
{
#if DEBUG
return new ReadOnlySequence<T>(new CustomMemoryManager(size + 1).Memory.Slice(1));
#else
return new ReadOnlySequence<T>(new CustomMemoryManager(size).Memory);
#endif
}

public override ReadOnlySequence<T> CreateWithContent(T[] data)
{
return new ReadOnlySequence<T>(new CustomMemoryManager(data).Memory);
}

private unsafe class CustomMemoryManager : MemoryManager<T>
{
private readonly T[] _buffer;

public CustomMemoryManager(int size) => _buffer = new T[size];

public CustomMemoryManager(T[] content) => _buffer = content;

public unsafe override Span<T> GetSpan() => _buffer;

public override unsafe MemoryHandle Pin(int elementIndex = 0)
{
if ((uint)elementIndex > (uint)_buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(elementIndex));
}

var handle = GCHandle.Alloc(_buffer, GCHandleType.Pinned);
return new MemoryHandle(Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), elementIndex), handle, this);
}

public override void Unpin() { }

protected override void Dispose(bool disposing) { }
}
}

public static ReadOnlySequence<T> CreateSegments(params T[][] inputs) => CreateSegments(inputs.Select(input => (ReadOnlyMemory<T>)input.AsMemory()));

public static ReadOnlySequence<T> CreateSegments(IEnumerable<ReadOnlyMemory<T>> inputs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ public class Memory : ReadOnlySequenceTestsByte
public Memory() : base(ReadOnlySequenceFactory<byte>.MemoryFactory) { }
}

public class MemoryManager : ReadOnlySequenceTestsByte
{
public MemoryManager() : base(ReadOnlySequenceFactory<byte>.MemoryManagerFactory) { }
}

public class SingleSegment : ReadOnlySequenceTestsByte
{
public SingleSegment() : base(ReadOnlySequenceFactory<byte>.SingleSegmentFactory) { }
Expand Down

0 comments on commit d7a7898

Please sign in to comment.