Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add basic Span<T> support #483

Merged
merged 19 commits into from
Sep 24, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
d70c022
Merge pull request #408 from Washi1337/development
Washi1337 Jan 29, 2023
d442f08
Merge pull request #425 from Washi1337/development
Washi1337 Mar 22, 2023
9d0fe83
Merge pull request #433 from Washi1337/development
Washi1337 May 13, 2023
82989a6
Merge pull request #470 from Washi1337/development
Washi1337 Jul 16, 2023
92c7010
Add netstandard2.1 target.
DaZombieKiller Sep 18, 2023
5066614
Add basic Span<T> support.
DaZombieKiller Sep 18, 2023
d35fecf
Add try/finally for SafeBuffer usage in MemoryMappedDataSource.
DaZombieKiller Sep 18, 2023
00eb41a
Add netstandard2.1 target to all projects.
DaZombieKiller Sep 18, 2023
cc512ba
Slice output Span<byte> before calling handle.ReadSpan<T>.
DaZombieKiller Sep 18, 2023
ef545d0
Handle Length property correctly for Span<T> in MemoryMappedDataSource.
DaZombieKiller Sep 18, 2023
df15a22
Do not clear more bytes than necessary in ZeroesDataSource.
DaZombieKiller Sep 19, 2023
5828f8c
Add netstandard2.1 target.
DaZombieKiller Sep 18, 2023
5c183f5
Add basic Span<T> support.
DaZombieKiller Sep 18, 2023
56e0d98
Add try/finally for SafeBuffer usage in MemoryMappedDataSource.
DaZombieKiller Sep 18, 2023
6325388
Add netstandard2.1 target to all projects.
DaZombieKiller Sep 18, 2023
fe2a0ba
Slice output Span<byte> before calling handle.ReadSpan<T>.
DaZombieKiller Sep 18, 2023
65d5088
Handle Length property correctly for Span<T> in MemoryMappedDataSource.
DaZombieKiller Sep 18, 2023
c9b0dd9
Do not clear more bytes than necessary in ZeroesDataSource.
DaZombieKiller Sep 19, 2023
a1b1760
Merge branch 'span-support' of https://github.com/DaZombieKiller/AsmR…
DaZombieKiller Sep 24, 2023
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
2 changes: 1 addition & 1 deletion src/AsmResolver/AsmResolver.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<NoWarn>1701;1702;NU5105</NoWarn>
<Nullable>enable</Nullable>
<TargetFrameworks>net6.0;netcoreapp3.1;netstandard2.0</TargetFrameworks>
<TargetFrameworks>net6.0;netcoreapp3.1;netstandard2.0;netstandard2.1</TargetFrameworks>
DaZombieKiller marked this conversation as resolved.
Show resolved Hide resolved
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>

Expand Down
14 changes: 14 additions & 0 deletions src/AsmResolver/IO/BinaryStreamReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,20 @@ public decimal ReadDecimal()
return new decimal(_buffer);
}

#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
/// <summary>
/// Attempts to read the provided amount of bytes from the input stream.
/// </summary>
/// <param name="buffer">The buffer that receives the read bytes.</param>
/// <returns>The number of bytes that were read.</returns>
public int ReadBytes(Span<byte> buffer)
{
int actualLength = DataSource.ReadBytes(Offset, buffer);
Offset += (uint) actualLength;
return actualLength;
}
#endif

/// <summary>
/// Attempts to read the provided amount of bytes from the input stream.
/// </summary>
Expand Down
11 changes: 11 additions & 0 deletions src/AsmResolver/IO/BinaryStreamWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ namespace AsmResolver.IO
/// Provides a default implementation of a binary writer that writes the data to an output stream.
/// </summary>
public class BinaryStreamWriter : IBinaryStreamWriter
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
, ISpanBinaryStreamWriter
#endif
{
/// <summary>
/// Creates a new binary stream writer using the provided output stream.
Expand Down Expand Up @@ -47,6 +50,14 @@ public void WriteBytes(byte[] buffer, int startIndex, int count)
BaseStream.Write(buffer, startIndex, count);
}

#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
/// <inheritdoc />
public void WriteBytes(ReadOnlySpan<byte> buffer)
{
BaseStream.Write(buffer);
}
#endif

/// <inheritdoc />
public void WriteByte(byte value)
{
Expand Down
14 changes: 14 additions & 0 deletions src/AsmResolver/IO/ByteArrayDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ namespace AsmResolver.IO
/// Provides a <see cref="IDataSource"/> wrapper around a raw byte array.
/// </summary>
public sealed class ByteArrayDataSource : IDataSource
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
, ISpanDataSource
#endif
{
private readonly byte[] _data;

Expand Down Expand Up @@ -60,5 +63,16 @@ public int ReadBytes(ulong address, byte[] buffer, int index, int count)
Buffer.BlockCopy(_data, relativeIndex, buffer, index, actualLength);
return actualLength;
}

#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
/// <inheritdoc />
public int ReadBytes(ulong address, Span<byte> buffer)
{
int relativeIndex = (int) (address - BaseAddress);
int actualLength = Math.Min(buffer.Length, _data.Length - relativeIndex);
_data.AsSpan(relativeIndex, actualLength).CopyTo(buffer);
return actualLength;
}
#endif
}
}
34 changes: 34 additions & 0 deletions src/AsmResolver/IO/DataSourceExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using System;
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP1_0_OR_GREATER
using System.Buffers;
#endif

namespace AsmResolver.IO
{
/// <summary>
/// Provides extension methods for <see cref="IDataSource"/>.
/// </summary>
public static class DataSourceExtensions
{
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
/// <summary>
/// Reads a block of data from the data source.
/// </summary>
/// <param name="dataSource">The <see cref="IDataSource"/> to read from.</param>
/// <param name="address">The starting address to read from.</param>
/// <param name="buffer">The buffer that receives the read bytes.</param>
/// <returns>The number of bytes that were read.</returns>
public static int ReadBytes(this IDataSource dataSource, ulong address, Span<byte> buffer)
{
if (dataSource is ISpanDataSource spanDataSource)
return spanDataSource.ReadBytes(address, buffer);

byte[] array = ArrayPool<byte>.Shared.Rent(buffer.Length);
int bytesRead = dataSource.ReadBytes(address, array, 0, buffer.Length);
new ReadOnlySpan<byte>(array, 0, bytesRead).CopyTo(buffer);
ArrayPool<byte>.Shared.Return(array);
Washi1337 marked this conversation as resolved.
Show resolved Hide resolved
return bytesRead;
}
#endif
}
}
12 changes: 12 additions & 0 deletions src/AsmResolver/IO/DataSourceSlice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ namespace AsmResolver.IO
/// Represents a data source that only exposes a part (slice) of another data source.
/// </summary>
public class DataSourceSlice : IDataSource
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
, ISpanDataSource
#endif
{
private readonly IDataSource _source;

Expand Down Expand Up @@ -64,5 +67,14 @@ public int ReadBytes(ulong address, byte[] buffer, int index, int count)
int maxCount = Math.Max(0, (int) (Length - (address - BaseAddress)));
return _source.ReadBytes(address, buffer, index, Math.Min(maxCount, count));
}

#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
/// <inheritdoc />
public int ReadBytes(ulong address, Span<byte> buffer)
{
int maxCount = Math.Max(0, (int) (Length - (address - BaseAddress)));
return _source.ReadBytes(address, buffer[..Math.Min(maxCount, buffer.Length)]);
}
#endif
}
}
11 changes: 11 additions & 0 deletions src/AsmResolver/IO/DisplacedDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ namespace AsmResolver.IO
/// Represents a data source that was moved in memory to a different address.
/// </summary>
public class DisplacedDataSource : IDataSource
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
, ISpanDataSource
#endif
{
private readonly IDataSource _dataSource;
private readonly long _displacement;
Expand Down Expand Up @@ -39,5 +42,13 @@ public int ReadBytes(ulong address, byte[] buffer, int index, int count)
{
return _dataSource.ReadBytes(address - (ulong) _displacement, buffer, index, count);
}

#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
/// <inheritdoc />
public int ReadBytes(ulong address, Span<byte> buffer)
{
return _dataSource.ReadBytes(address - (ulong) _displacement, buffer);
}
#endif
}
}
24 changes: 24 additions & 0 deletions src/AsmResolver/IO/IBinaryStreamWriter.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System;
using System.Text;
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP1_0_OR_GREATER
using System.Buffers;
#endif

namespace AsmResolver.IO
{
Expand Down Expand Up @@ -130,6 +133,27 @@ public static void WriteBytes(this IBinaryStreamWriter writer, byte[] buffer)
writer.WriteBytes(buffer, 0, buffer.Length);
}

#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
/// <summary>
/// Writes a buffer of data to the stream.
/// </summary>
/// <param name="writer">The writer to use.</param>
/// <param name="buffer">The data to write.</param>
public static void WriteBytes(this IBinaryStreamWriter writer, ReadOnlySpan<byte> buffer)
{
if (writer is ISpanBinaryStreamWriter spanWriter)
{
spanWriter.WriteBytes(buffer);
return;
}

byte[] array = ArrayPool<byte>.Shared.Rent(buffer.Length);
buffer.CopyTo(array);
writer.WriteBytes(array, 0, buffer.Length);
ArrayPool<byte>.Shared.Return(array);
Washi1337 marked this conversation as resolved.
Show resolved Hide resolved
}
#endif

/// <summary>
/// Writes a specified amount of zero bytes to the stream.
/// </summary>
Expand Down
18 changes: 18 additions & 0 deletions src/AsmResolver/IO/ISpanBinaryStreamWriter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System;

namespace AsmResolver.IO
{
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
/// <summary>
/// Provides span-based methods for writing data to a binary stream.
/// </summary>
public interface ISpanBinaryStreamWriter : IBinaryStreamWriter
{
/// <summary>
/// Writes a buffer of data to the stream.
/// </summary>
/// <param name="buffer">The buffer to write to the stream.</param>
void WriteBytes(ReadOnlySpan<byte> buffer);
}
#endif
}
20 changes: 20 additions & 0 deletions src/AsmResolver/IO/ISpanDataSource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;

namespace AsmResolver.IO
{
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
/// <summary>
/// Provides span-based members for reading data from a data source.
/// </summary>
public interface ISpanDataSource : IDataSource
{
/// <summary>
/// Reads a block of data from the data source.
/// </summary>
/// <param name="address">The starting address to read from.</param>
/// <param name="buffer">The buffer that receives the read bytes.</param>
/// <returns>The number of bytes that were read.</returns>
int ReadBytes(ulong address, Span<byte> buffer);
}
#endif
}
21 changes: 21 additions & 0 deletions src/AsmResolver/IO/MemoryMappedDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ namespace AsmResolver.IO
/// Represents a data source that obtains its data from a memory mapped file.
/// </summary>
public sealed class MemoryMappedDataSource : IDataSource, IDisposable
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
, ISpanDataSource
#endif
{
private readonly MemoryMappedViewAccessor _accessor;

Expand Down Expand Up @@ -40,6 +43,24 @@ public ulong Length
public int ReadBytes(ulong address, byte[] buffer, int index, int count) =>
_accessor.ReadArray((long) address, buffer, index, count);

#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
/// <inheritdoc />
public unsafe int ReadBytes(ulong address, Span<byte> buffer)
{
var handle = _accessor.SafeMemoryMappedViewHandle;
int actualLength = (int) Math.Min(handle.ByteLength, (uint) buffer.Length);
#if NET6_0_OR_GREATER
handle.ReadSpan(address, buffer);
#else
byte* pointer = null;
handle.AcquirePointer(ref pointer);
new ReadOnlySpan<byte>(pointer, actualLength).CopyTo(buffer);
handle.ReleasePointer();
DaZombieKiller marked this conversation as resolved.
Show resolved Hide resolved
#endif
return actualLength;
}
#endif

/// <inheritdoc />
public void Dispose() => _accessor?.Dispose();
}
Expand Down
17 changes: 17 additions & 0 deletions src/AsmResolver/IO/UnmanagedDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ namespace AsmResolver.IO
/// Represents a data source that obtains its data from a block of unmanaged memory.
/// </summary>
public sealed unsafe class UnmanagedDataSource : IDataSource
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
, ISpanDataSource
#endif
{
private readonly void* _basePointer;

Expand Down Expand Up @@ -66,5 +69,19 @@ public int ReadBytes(ulong address, byte[] buffer, int index, int count)
Marshal.Copy((IntPtr) address, buffer, index, actualLength);
return actualLength;
}

#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
/// <inheritdoc />
public int ReadBytes(ulong address, Span<byte> buffer)
{
if (!IsValidAddress(address))
return 0;

ulong relativeIndex = address - (ulong) _basePointer;
int actualLength = (int) Math.Min((uint) buffer.Length, Length - relativeIndex);
new ReadOnlySpan<byte>((byte*) address, actualLength).CopyTo(buffer);
return actualLength;
}
#endif
}
}
13 changes: 13 additions & 0 deletions src/AsmResolver/IO/ZeroesDataSource.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ namespace AsmResolver.IO
/// Implements a data source that reads zero bytes.
/// </summary>
public sealed class ZeroesDataSource : IDataSource
#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
, ISpanDataSource
#endif
{
/// <summary>
/// Creates a new zeroes data source.
Expand Down Expand Up @@ -54,5 +57,15 @@ public int ReadBytes(ulong address, byte[] buffer, int index, int count)
Array.Clear(buffer, index, count);
return actualLength;
}

#if NETSTANDARD2_1_OR_GREATER || NETCOREAPP2_1_OR_GREATER
/// <inheritdoc />
public int ReadBytes(ulong address, Span<byte> buffer)
{
int actualLength = (int) Math.Min(Length, (uint) buffer.Length);
buffer.Clear();
DaZombieKiller marked this conversation as resolved.
Show resolved Hide resolved
return actualLength;
}
#endif
}
}
Loading