Skip to content

Commit

Permalink
Add VirtualArray/VirtualBuffer Append() and AppendRange() met…
Browse files Browse the repository at this point in the history
…hods
  • Loading branch information
xoofx committed Sep 18, 2022
1 parent d7dc8eb commit 391fb1d
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 0 deletions.
33 changes: 33 additions & 0 deletions src/Varena.Tests/TestVirtualArray.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using NUnit.Framework;
using System;

namespace Varena.Tests
{
Expand Down Expand Up @@ -81,6 +82,38 @@ public void TestAllocateLoop()
Assert.Throws<VirtualMemoryException>(() => buffer.Allocate());
}

[Test]
public void TestAppend()
{
using var manager = new VirtualArenaManager();
var array = manager.CreateArray<byte>("Bytes", 1 << 20);
for (int i = 0; i < 1024; i++)
{
if ((i & 1) == 0)
{
array.Append((byte)i);
}
else
{
array.AppendByRef((byte)i);
}
}
Assert.AreEqual(1024, array.Count);
for (int i = 0; i < array.Count; i++)
{
Assert.AreEqual((byte)i, array[i]);
}

array.Reset(VirtualArenaResetKind.KeepAllCommitted);

array.AppendRange(new byte[] { 255, 254, 253, 252 });
Assert.AreEqual(4, array.Count);
Assert.AreEqual((byte)255, array[0]);
Assert.AreEqual((byte)254, array[1]);
Assert.AreEqual((byte)253, array[2]);
Assert.AreEqual((byte)252, array[3]);
}

[Test]
public void TestInvalidArguments()
{
Expand Down
27 changes: 27 additions & 0 deletions src/Varena.Tests/TestVirtualBuffer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using NUnit.Framework;
using System;

namespace Varena.Tests
{
Expand Down Expand Up @@ -38,6 +39,32 @@ public void TestAllocate()
Assert.AreEqual((nuint)0, buffer.AllocatedBytes);
}

[Test]
public void TestAppend()
{
using var manager = new VirtualArenaManager();
var buffer = manager.CreateBuffer("Bytes", 1 << 20);

for (int i = 0; i < 1024; i++)
{
buffer.Append((byte)i);
}
Assert.AreEqual((nuint)1024, buffer.AllocatedBytes);
var span = buffer.AsSpan(0, 1024);
for (int i = 0; i < span.Length; i++)
{
Assert.AreEqual((byte)i, span[i], "Invalid data in the buffer");
}

buffer.Reset(VirtualArenaResetKind.KeepAllCommitted);
buffer.AppendRange(new byte[] { 255, 254, 253, 252,});

Assert.AreEqual((nuint)4, buffer.AllocatedBytes);
Assert.AreEqual((byte)255, buffer[0]);
Assert.AreEqual((byte)254, buffer[1]);
Assert.AreEqual((byte)253, buffer[2]);
Assert.AreEqual((byte)252, buffer[3]);
}

[Test]
public void TestInvalidArguments()
Expand Down
49 changes: 49 additions & 0 deletions src/Varena/VirtualArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,55 @@ public Span<T> AllocateRange(int count, out int firstIndex)
return AllocateRange(count);
}

/// <summary>
/// Appends a single element.
/// </summary>
/// <param name="value">The value to append.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Append(T value)
{
unsafe
{
ref var localRef = ref *(T*)base.UnsafeAllocate((nuint)sizeof(T));
localRef = value;
_count++;
}
}

/// <summary>
/// Appends a single element by reference (for large structs to avoid a copy on the stack).
/// </summary>
/// <param name="value">The value to append.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AppendByRef(in T value)
{
unsafe
{
ref var localRef = ref *(T*)base.UnsafeAllocate((nuint)sizeof(T));
localRef = value;
_count++;
}
}

/// <summary>
/// Appends a range of elements.
/// </summary>
/// <param name="range">The range of elements to append.</param>
/// <returns>A span to the range of elements appended.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<T> AppendRange(ReadOnlySpan<T> range)
{
unsafe
{
var count = range.Length;
if (count == 0) return Span<T>.Empty;
var span = new Span<T>(base.UnsafeAllocate((nuint)count * (uint)sizeof(T)), count);
range.CopyTo(span);
_count += count;
return span;
}
}

/// <summary>
/// Gets the span over all the elements allocated.
/// </summary>
Expand Down
28 changes: 28 additions & 0 deletions src/Varena/VirtualBuffer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Licensed under the BSD-Clause 2 license.
// See license.txt file in the project root for full license information.

using System.Runtime.CompilerServices;

namespace Varena;

/// <summary>
Expand Down Expand Up @@ -63,6 +65,32 @@ public Span<byte> AllocateRange(int count, out ulong firstIndex)
return AllocateRange(count);
}

/// <summary>
/// Appends the specified value to this buffer.
/// </summary>
/// <param name="value">The value to append.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void Append(byte value)
{
*(byte*)UnsafeAllocate(1) = value;
}

/// <summary>
/// Appends the specified range to this buffer.
/// </summary>
/// <param name="range">The range of values to append.</param>
/// <returns>The span of the appended memory.</returns>
public Span<byte> AppendRange(ReadOnlySpan<byte> range)
{
if (range.Length == 0) return new Span<byte>();
unsafe
{
var toSpan = new Span<byte>(UnsafeAllocate((nuint)range.Length), range.Length);
range.CopyTo(toSpan);
return toSpan;
}
}

/// <summary>
/// Gets the span over all the elements allocated.
/// </summary>
Expand Down

0 comments on commit 391fb1d

Please sign in to comment.