Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
write a failing test
  • Loading branch information
adamsitnik committed Aug 16, 2021
commit 203b4ff3d66cf9ad75dd6025042de58ec33534ae
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<byte> 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 Down Expand Up @@ -112,6 +116,64 @@ public override ReadOnlySequence<T> CreateWithContent(T[] data)
}
}

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

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

private unsafe class CustomMemoryManager : MemoryManager<byte>
{
private readonly int _size;
private IntPtr _pointer;
private long _referenceCount;

public CustomMemoryManager(int size) => _pointer = Marshal.AllocHGlobal(_size = size);

public CustomMemoryManager(byte[] content)
{
_pointer = Marshal.AllocHGlobal(_size = content.Length);
content.AsSpan().CopyTo(new Span<byte>(_pointer.ToPointer(), _size));
}

public unsafe override Span<byte> GetSpan() => new Span<byte>(_pointer.ToPointer(), _size);

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

Interlocked.Increment(ref _referenceCount);

return default; // there is no need to pin anything, it's unmanaged memory
}

public override void Unpin() => Interlocked.Decrement(ref _referenceCount);

protected override void Dispose(bool disposing)
{
if (Interlocked.Read(ref _referenceCount) == 0)
{
// this code is not thread safe, don't copy and reuse it!
IntPtr pointer = Interlocked.Exchange(ref _pointer, IntPtr.Zero);
Marshal.FreeHGlobal(pointer);
}
}
}
}

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