forked from migueldeicaza/TensorFlowSharp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBuffer.cs
More file actions
173 lines (152 loc) · 5.78 KB
/
Buffer.cs
File metadata and controls
173 lines (152 loc) · 5.78 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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//
// TensorFlow.cs; Bindings to the TensorFlow C API for .NET
//
// Authors:
// Miguel de Icaza ([email protected])
//
using System;
using System.Runtime.InteropServices;
using System.Text;
using size_t = System.UIntPtr;
namespace TensorFlow
{
[StructLayout (LayoutKind.Sequential)]
internal struct LLBuffer
{
internal IntPtr data;
internal size_t length;
internal IntPtr data_deallocator;
}
/// <summary>
/// Holds a block of data.
/// </summary>
/// <remarks>
/// Use the TFBuffer to blobs of data into TensorFlow, or to retrieve blocks
/// of data out of TensorFlow.
///
/// There are two constructors to wrap existing data, one to wrap blocks that are
/// pointed to by an IntPtr and one that takes a byte array that we want to wrap.
///
/// The empty constructor can be used to create a new TFBuffer that can be populated
/// by the TensorFlow library and returned to user code.
///
/// Typically, the data consists of a serialized protocol buffer, but other data
/// may also be held in a buffer.
/// </remarks>
// TODO: the string ctor
// TODO: perhaps we should have an implicit byte [] conversion that just calls ToArray?
public class TFBuffer : TFDisposable
{
// extern TF_Buffer * TF_NewBufferFromString (const void *proto, size_t proto_len);
[DllImport (NativeBinding.TensorFlowLibrary)]
static extern unsafe LLBuffer* TF_NewBufferFromString (IntPtr proto, IntPtr proto_len);
// extern TF_Buffer * TF_NewBuffer ();
[DllImport (NativeBinding.TensorFlowLibrary)]
static extern unsafe LLBuffer* TF_NewBuffer ();
internal TFBuffer (IntPtr handle) : base (handle) { }
unsafe public TFBuffer () : base ((IntPtr)TF_NewBuffer ())
{
}
/// <summary>
/// Signature of the method that is invoked to release the data.
/// </summary>
/// <remarks>
/// Methods of this signature are invoked with the data pointer and the
/// lenght pointer when then TFBuffer no longer needs to hold on to the
/// data.
/// </remarks>
public delegate void BufferReleaseFunc (IntPtr data, IntPtr lenght);
/// <summary>
/// Initializes a new instance of the <see cref="T:TensorFlow.TFBuffer"/> by wrapping the unmanaged resource pointed by the buffer.
/// </summary>
/// <param name="buffer">Pointer to the data that will be wrapped.</param>
/// <param name="size">The size of the buffer to wrap.</param>
/// <param name="release">Optional, if not null, this method will be invoked to release the block.</param>
/// <remarks>
/// This constructor wraps the buffer as a the data to be held by the <see cref="T:TensorFlow.TFBuffer"/>,
/// if the release parameter is null, then you must ensure that the data is not released before the TFBuffer
/// is no longer in use. If the value is not null, the provided method will be invoked to release
/// the data when the TFBuffer is disposed, or the contents of the buffer replaced.
/// </remarks>
unsafe public TFBuffer (IntPtr buffer, long size, BufferReleaseFunc release) : base ((IntPtr)TF_NewBuffer ())
{
LLBuffer* buf = (LLBuffer*)handle;
buf->data = buffer;
buf->length = (size_t)size;
if (release == null)
buf->data_deallocator = IntPtr.Zero;
else
buf->data_deallocator = Marshal.GetFunctionPointerForDelegate (release);
}
internal static void FreeBlock (IntPtr data, IntPtr lenght)
{
Marshal.FreeHGlobal (data);
}
static IntPtr FreeBufferFunc;
static TFBuffer ()
{
FreeBufferFunc = Marshal.GetFunctionPointerForDelegate<BufferReleaseFunc> (FreeBlock);
}
/// <summary>
/// Initializes a new instance of the <see cref="T:TensorFlow.TFBuffer"/> by making a copy of the provided byte array.
/// </summary>
/// <param name="buffer">Buffer of data that will be wrapped.</param>
/// <remarks>
/// This constructor makes a copy of the data into an unmanaged buffer,
/// so the byte array is not pinned.
/// </remarks>
public TFBuffer (byte [] buffer) : this (buffer, 0, buffer.Length) { }
/// <summary>
/// Initializes a new instance of the <see cref="T:TensorFlow.TFBuffer"/> by making a copy of the provided byte array.
/// </summary>
/// <param name="buffer">Buffer of data that will be wrapped.</param>
/// <param name="start">Starting offset into the buffer to wrap.</param>
/// <param name="count">Number of bytes from the buffer to keep.</param>
/// <remarks>
/// This constructor makes a copy of the data into an unmanaged buffer,
/// so the byte array is not pinned.
/// </remarks>
public TFBuffer (byte [] buffer, int start, int count) : this ()
{
if (start < 0 || start >= buffer.Length)
throw new ArgumentException ("start");
if (count < 0 || count > buffer.Length - start)
throw new ArgumentException ("count");
unsafe
{
LLBuffer* buf = LLBuffer;
buf->data = Marshal.AllocHGlobal (count);
Marshal.Copy (buffer, start, buf->data, count);
buf->length = (size_t)count;
buf->data_deallocator = FreeBufferFunc;
}
}
unsafe internal LLBuffer* LLBuffer => (LLBuffer*)handle;
// extern void TF_DeleteBuffer (TF_Buffer *);
[DllImport (NativeBinding.TensorFlowLibrary)]
static extern unsafe void TF_DeleteBuffer (LLBuffer* buffer);
internal override void NativeDispose (IntPtr handle)
{
unsafe { TF_DeleteBuffer ((LLBuffer*)handle); }
}
// extern TF_Buffer TF_GetBuffer (TF_Buffer *buffer);
[DllImport (NativeBinding.TensorFlowLibrary)]
static extern unsafe LLBuffer TF_GetBuffer (LLBuffer* buffer);
/// <summary>
/// Returns a byte array representing the data wrapped by this buffer.
/// </summary>
/// <returns>The array.</returns>
public byte [] ToArray ()
{
if (handle == IntPtr.Zero)
return null;
unsafe
{
var lb = (LLBuffer*)handle;
var result = new byte [(int)lb->length];
Marshal.Copy (lb->data, result, 0, (int)lb->length);
return result;
}
}
}
}