-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPluginDisposableMemory.cs
More file actions
108 lines (88 loc) · 3.53 KB
/
PluginDisposableMemory.cs
File metadata and controls
108 lines (88 loc) · 3.53 KB
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
using Hi3Helper.Plugin.Core.Utility;
using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// ReSharper disable UnusedMember.Global
namespace Hi3Helper.Plugin.Core;
[StructLayout(LayoutKind.Sequential, Pack = 8)]
[method: MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe struct PluginDisposableMemory<T>(T* handle, int count, bool isDisposable = true) : IDisposable
where T : unmanaged
{
private byte _isFreed = 0;
public byte IsDisposable = (byte)(isDisposable ? 1 : 0);
public int Length = count;
public readonly bool IsEmpty => Length == 0;
public static PluginDisposableMemory<T> Empty => new(null, 0, false);
public readonly ref T this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, Length, nameof(index));
return ref Unsafe.AsRef<T>(Unsafe.Add<T>(handle, index));
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly ref T AsRef() => ref Unsafe.AsRef<T>(handle);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly T* AsPointer() => handle;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly nint AsSafePointer() => (nint)AsPointer();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly UnmanagedMemoryStream AsStream() => new((byte*)AsPointer(), Length * sizeof(T));
public void* AsSpanPointer() => Unsafe.AsPointer(ref this);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Span<T> AsSpan(int offset = 0)
=> AsSpan(offset, Length - offset);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Span<T> AsSpan(int offset, int length)
=> new(Unsafe.Add<T>(handle, offset), length);
/// <summary>
/// Dispose the handle inside the span
/// </summary>
public void Dispose()
{
if (IsDisposable == 1)
{
ForceDispose();
}
}
/// <summary>
/// Forcefully freed the span, even though the object is not disposable.
/// </summary>
public void ForceDispose()
{
if (_isFreed == 1) return;
Mem.Free(handle);
_isFreed = 1;
}
/// <summary>
/// Create and allocate span of <typeparamref name="T"/>.<br/>
/// </summary>
/// <param name="count">How much object to allocate to unmanaged memory</param>
/// <param name="isZeroed">Whether the memory is zeroed</param>
/// <param name="isDisposable">Whether the </param>
/// <returns>Disposable Span of <typeparamref name="T"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static PluginDisposableMemory<T> Alloc(int count = 1, bool isZeroed = true, bool isDisposable = true)
{
// Allocate the instance of T and create a span from it.
PluginDisposableMemory<T> memory = new(Mem.Alloc<T>(count, isZeroed), count, isDisposable);
return memory;
}
public static implicit operator string?(PluginDisposableMemory<T> memory)
{
if (memory.IsEmpty)
{
return null;
}
int sizeofT = sizeof(T);
if (sizeofT > 2)
{
throw new InvalidCastException("Cannot convert the span type to string. You must pass PluginDisposableMemory<byte> or PluginDisposableMemory<char> to convert into string implicitly.");
}
return memory.CreateStringFromNullTerminated();
}
}