-
Notifications
You must be signed in to change notification settings - Fork 10
/
MemoryBuffer.cs
110 lines (93 loc) · 4.43 KB
/
MemoryBuffer.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// -----------------------------------------------------------------------
// <copyright file="MemoryBuffer.cs" company="Ubiquity.NET Contributors">
// Copyright (c) Ubiquity.NET Contributors. All rights reserved.
// </copyright>
// -----------------------------------------------------------------------
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using Ubiquity.ArgValidators;
using Ubiquity.NET.Llvm.Interop;
using Ubiquity.NET.Llvm.Properties;
using static Ubiquity.NET.Llvm.Interop.NativeMethods;
namespace Ubiquity.NET.Llvm
{
/// <summary>LLVM MemoryBuffer</summary>
public sealed class MemoryBuffer
{
/// <summary>Initializes a new instance of the <see cref="MemoryBuffer"/> class from a file</summary>
/// <param name="path">Path of the file to load</param>
public MemoryBuffer( string path )
{
path.ValidateNotNullOrWhiteSpace( nameof( path ) );
if( LLVMCreateMemoryBufferWithContentsOfFile( path, out LLVMMemoryBufferRef handle, out string msg ).Failed )
{
throw new InternalCodeGeneratorException( msg );
}
BufferHandle = handle;
}
/// <summary>Gets the size of the buffer</summary>
public int Size => BufferHandle.IsInvalid ? 0 : ( int )LLVMGetBufferSize( BufferHandle );
/// <summary>Gets an array of bytes from the buffer</summary>
/// <returns>Array of bytes copied from the buffer</returns>
public byte[ ] ToArray( )
{
if( BufferHandle.IsInvalid )
{
throw new InvalidOperationException( );
}
IntPtr bufferStart = LLVMGetBufferStart( BufferHandle );
byte[ ] retVal = new byte[ Size ];
Marshal.Copy( bufferStart, retVal, 0, Size );
return retVal;
}
/// <summary>Implicit convert to a <see cref="ReadOnlySpan{T}"/></summary>
/// <param name="buffer">Buffer to convert</param>
/// <remarks>This is a simple wrapper around calling <see cref="Slice(int, int)"/> with default parameters</remarks>
[SuppressMessage( "Usage", "CA2225:Operator overloads have named alternates", Justification = "Named alternate exists - Slice()" )]
public static implicit operator ReadOnlySpan<byte>( MemoryBuffer buffer ) => buffer.ValidateNotNull( nameof( buffer ) ).Slice( 0, -1 );
/// <summary>Create a <see cref="System.ReadOnlySpan{T}"/> for a slice of the buffer</summary>
/// <param name="start">Starting index for the slice [default = 0]</param>
/// <param name="length">Length of the slice or -1 to include up to the end of the buffer [default = -1]</param>
/// <returns>New Span</returns>
/// <remarks>Creates an efficient means of accessing the raw data of a buffer</remarks>
public ReadOnlySpan<byte> Slice( int start = 0, int length = -1 )
{
if( BufferHandle.IsInvalid )
{
throw new InvalidOperationException( );
}
if( length == -1 )
{
length = Size - start;
}
start.ValidateRange( 0, Size - 1, nameof( start ) );
length.ValidateRange( 0, Size, nameof( length ) );
if( ( start + length ) > Size )
{
throw new ArgumentException( Resources.start_plus_length_exceeds_size_of_buffer );
}
unsafe
{
void* startSlice = ( LLVMGetBufferStart( BufferHandle ) + start ).ToPointer( );
return new ReadOnlySpan<byte>( startSlice, length );
}
}
/// <summary>Detaches the underlying buffer from automatic management</summary>
/// <remarks>
/// This is used when passing the memory buffer to an LLVM object (like <see cref="Ubiquity.NET.Llvm.ObjectFile.TargetBinary"/>
/// that takes ownership of the underlying buffer. Any use of the buffer after this point results in
/// an <see cref="InvalidOperationException"/>.
/// </remarks>
public void Detach( )
{
BufferHandle.SetHandleAsInvalid( );
}
internal MemoryBuffer( LLVMMemoryBufferRef bufferHandle )
{
bufferHandle.ValidateNotDefault( nameof( bufferHandle ) );
BufferHandle = bufferHandle;
}
internal LLVMMemoryBufferRef BufferHandle { get; }
}
}