Skip to content

Commit d82914f

Browse files
author
Olivier Deheurles
committed
Merge pull request aeron-io#89 from qed-/master
[C#] Allow DirectBuffer to be initialised from unmanaged buffer
2 parents 902ab77 + ff5a058 commit d82914f

File tree

2 files changed

+42
-9
lines changed

2 files changed

+42
-9
lines changed

main/csharp/DirectBuffer.cs

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ namespace Adaptive.SimpleBinaryEncoding
88
/// </summary>
99
public sealed unsafe class DirectBuffer : IDisposable
1010
{
11-
private readonly byte[] _buffer;
1211
private readonly byte* _pBuffer;
1312
private bool _disposed;
1413
private GCHandle _pinnedGCHandle;
14+
private readonly bool _needToFreeGCHandle;
1515
private readonly int _capacity;
1616

1717
/// <summary>
@@ -24,10 +24,25 @@ public DirectBuffer(byte[] byteArray)
2424

2525
// pin the buffer so it does not get moved around by GC, this is required since we use pointers
2626
_pinnedGCHandle = GCHandle.Alloc(byteArray, GCHandleType.Pinned);
27+
_needToFreeGCHandle = true;
2728

28-
_buffer = byteArray;
29-
_pBuffer = (byte*) _pinnedGCHandle.AddrOfPinnedObject().ToPointer();
30-
_capacity = _buffer.Length;
29+
_pBuffer = (byte*)_pinnedGCHandle.AddrOfPinnedObject().ToPointer();
30+
_capacity = byteArray.Length;
31+
}
32+
33+
/// <summary>
34+
/// Constructs a <see cref="DirectBuffer"/> from an unmanaged byte buffer owned by external code
35+
/// </summary>
36+
/// <param name="pBuffer">Unmanaged byte buffer</param>
37+
/// <param name="bufferLength">Length of the buffer</param>
38+
public DirectBuffer(byte* pBuffer, int bufferLength)
39+
{
40+
if (pBuffer == null) throw new ArgumentNullException("pBuffer");
41+
if (bufferLength < 0) throw new ArgumentException("Buffer size must be > 0", "bufferLength");
42+
43+
_pBuffer = pBuffer;
44+
_capacity = bufferLength;
45+
_needToFreeGCHandle = false;
3146
}
3247

3348
/// <summary>
@@ -38,7 +53,7 @@ public void CheckLimit(int limit)
3853
{
3954
if (limit > _capacity)
4055
{
41-
throw new IndexOutOfRangeException(string.Format("limit={0} is beyond capacity={1}", limit, _buffer.Length));
56+
throw new IndexOutOfRangeException(string.Format("limit={0} is beyond capacity={1}", limit, _capacity));
4257
}
4358
}
4459

@@ -480,7 +495,8 @@ public void DoublePutLittleEndian(int index, double value)
480495
public int GetBytes(int index, byte[] destination, int offsetDestination, int length)
481496
{
482497
int count = Math.Min(length, _capacity - index);
483-
Buffer.BlockCopy(_buffer, index, destination, offsetDestination, count);
498+
Marshal.Copy((IntPtr)(_pBuffer + index), destination, offsetDestination, count);
499+
484500
return count;
485501
}
486502

@@ -495,12 +511,11 @@ public int GetBytes(int index, byte[] destination, int offsetDestination, int le
495511
public int SetBytes(int index, byte[] src, int offset, int length)
496512
{
497513
int count = Math.Min(length, _capacity - index);
498-
Buffer.BlockCopy(src, offset, _buffer, index, count);
514+
Marshal.Copy(src, offset, (IntPtr)(_pBuffer + index), count);
499515

500516
return count;
501517
}
502518

503-
504519
/// <summary>
505520
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
506521
/// </summary>
@@ -521,7 +536,9 @@ private void Dispose(bool disposing)
521536
if (_disposed)
522537
return;
523538

524-
_pinnedGCHandle.Free();
539+
if (_needToFreeGCHandle)
540+
_pinnedGCHandle.Free();
541+
525542
_disposed = true;
526543
}
527544
}

test/csharp/DirectBufferTests.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,23 @@ public void CheckPositionShouldThrowWhenPositionIsNotInRange()
3434
_directBuffer.CheckLimit(_buffer.Length + 1);
3535
}
3636

37+
[Test]
38+
public void ConstructFromNativeBuffer()
39+
{
40+
var managedBuffer = new Byte[16];
41+
var handle = GCHandle.Alloc(managedBuffer, GCHandleType.Pinned);
42+
var unmanagedBuffer = (byte*) handle.AddrOfPinnedObject().ToPointer();
3743

44+
const int value = 5;
45+
const int index = 0;
46+
47+
using (var directBufferFromUnmanagedbuffer = new DirectBuffer(unmanagedBuffer, managedBuffer.Length))
48+
{
49+
directBufferFromUnmanagedbuffer.Int64PutLittleEndian(index, value);
50+
Assert.AreEqual(value, *(long*) (unmanagedBuffer + index));
51+
}
52+
}
53+
3854
#region Byte
3955

4056
[TestCase(5, 0)]

0 commit comments

Comments
 (0)