1+ //
2+ // TensorFlow.cs; Bindings to the TensorFlow C API for .NET
3+ //
4+ // Authors:
5+ // Miguel de Icaza ([email protected] ) 6+ //
7+ using System ;
8+ using System . Runtime . InteropServices ;
9+ using System . Text ;
10+ using size_t = System . UIntPtr ;
11+
12+ namespace TensorFlow
13+ {
14+ [ StructLayout ( LayoutKind . Sequential ) ]
15+ internal struct LLBuffer
16+ {
17+ internal IntPtr data ;
18+ internal size_t length ;
19+ internal IntPtr data_deallocator ;
20+ }
21+
22+ /// <summary>
23+ /// Holds a block of data.
24+ /// </summary>
25+ /// <remarks>
26+ /// Use the TFBuffer to blobs of data into TensorFlow, or to retrieve blocks
27+ /// of data out of TensorFlow.
28+ ///
29+ /// There are two constructors to wrap existing data, one to wrap blocks that are
30+ /// pointed to by an IntPtr and one that takes a byte array that we want to wrap.
31+ ///
32+ /// The empty constructor can be used to create a new TFBuffer that can be populated
33+ /// by the TensorFlow library and returned to user code.
34+ ///
35+ /// Typically, the data consists of a serialized protocol buffer, but other data
36+ /// may also be held in a buffer.
37+ /// </remarks>
38+ // TODO: the string ctor
39+ // TODO: perhaps we should have an implicit byte [] conversion that just calls ToArray?
40+ public class TFBuffer : TFDisposable
41+ {
42+ // extern TF_Buffer * TF_NewBufferFromString (const void *proto, size_t proto_len);
43+ [ DllImport ( NativeBinding . TensorFlowLibrary ) ]
44+ static extern unsafe LLBuffer * TF_NewBufferFromString ( IntPtr proto , IntPtr proto_len ) ;
45+
46+ // extern TF_Buffer * TF_NewBuffer ();
47+ [ DllImport ( NativeBinding . TensorFlowLibrary ) ]
48+ static extern unsafe LLBuffer * TF_NewBuffer ( ) ;
49+
50+ internal TFBuffer ( IntPtr handle ) : base ( handle ) { }
51+
52+ unsafe public TFBuffer ( ) : base ( ( IntPtr ) TF_NewBuffer ( ) )
53+ {
54+ }
55+
56+ /// <summary>
57+ /// Signature of the method that is invoked to release the data.
58+ /// </summary>
59+ /// <remarks>
60+ /// Methods of this signature are invoked with the data pointer and the
61+ /// lenght pointer when then TFBuffer no longer needs to hold on to the
62+ /// data.
63+ /// </remarks>
64+ public delegate void BufferReleaseFunc ( IntPtr data , IntPtr lenght ) ;
65+
66+ /// <summary>
67+ /// Initializes a new instance of the <see cref="T:TensorFlow.TFBuffer"/> by wrapping the unmanaged resource pointed by the buffer.
68+ /// </summary>
69+ /// <param name="buffer">Pointer to the data that will be wrapped.</param>
70+ /// <param name="size">The size of the buffer to wrap.</param>
71+ /// <param name="release">Optional, if not null, this method will be invoked to release the block.</param>
72+ /// <remarks>
73+ /// This constructor wraps the buffer as a the data to be held by the <see cref="T:TensorFlow.TFBuffer"/>,
74+ /// if the release parameter is null, then you must ensure that the data is not released before the TFBuffer
75+ /// is no longer in use. If the value is not null, the provided method will be invoked to release
76+ /// the data when the TFBuffer is disposed, or the contents of the buffer replaced.
77+ /// </remarks>
78+ unsafe public TFBuffer ( IntPtr buffer , long size , BufferReleaseFunc release ) : base ( ( IntPtr ) TF_NewBuffer ( ) )
79+ {
80+ LLBuffer * buf = ( LLBuffer * ) handle ;
81+ buf ->data = buffer ;
82+ buf ->length = ( size_t ) size ;
83+ if ( release == null )
84+ buf ->data_deallocator = IntPtr . Zero ;
85+ else
86+ buf ->data_deallocator = Marshal . GetFunctionPointerForDelegate ( release ) ;
87+ }
88+
89+ internal static void FreeBlock ( IntPtr data , IntPtr lenght )
90+ {
91+ Marshal . FreeHGlobal ( data ) ;
92+ }
93+
94+ static IntPtr FreeBufferFunc ;
95+
96+ static TFBuffer ( )
97+ {
98+ FreeBufferFunc = Marshal . GetFunctionPointerForDelegate < BufferReleaseFunc > ( FreeBlock ) ;
99+ }
100+
101+
102+ /// <summary>
103+ /// Initializes a new instance of the <see cref="T:TensorFlow.TFBuffer"/> by making a copy of the provided byte array.
104+ /// </summary>
105+ /// <param name="buffer">Buffer of data that will be wrapped.</param>
106+ /// <remarks>
107+ /// This constructor makes a copy of the data into an unmanaged buffer,
108+ /// so the byte array is not pinned.
109+ /// </remarks>
110+ public TFBuffer ( byte [ ] buffer ) : this ( buffer , 0 , buffer . Length ) { }
111+
112+ /// <summary>
113+ /// Initializes a new instance of the <see cref="T:TensorFlow.TFBuffer"/> by making a copy of the provided byte array.
114+ /// </summary>
115+ /// <param name="buffer">Buffer of data that will be wrapped.</param>
116+ /// <param name="start">Starting offset into the buffer to wrap.</param>
117+ /// <param name="count">Number of bytes from the buffer to keep.</param>
118+ /// <remarks>
119+ /// This constructor makes a copy of the data into an unmanaged buffer,
120+ /// so the byte array is not pinned.
121+ /// </remarks>
122+ public TFBuffer ( byte [ ] buffer , int start , int count ) : this ( )
123+ {
124+ if ( start < 0 || start >= buffer . Length )
125+ throw new ArgumentException ( "start" ) ;
126+ if ( count < 0 || count > buffer . Length - start )
127+ throw new ArgumentException ( "count" ) ;
128+ unsafe
129+ {
130+ LLBuffer * buf = LLBuffer ;
131+ buf ->data = Marshal . AllocHGlobal ( count ) ;
132+ Marshal . Copy ( buffer , start , buf ->data , count ) ;
133+ buf ->length = ( size_t ) count ;
134+ buf ->data_deallocator = FreeBufferFunc ;
135+ }
136+ }
137+
138+ unsafe internal LLBuffer * LLBuffer => ( LLBuffer * ) handle ;
139+
140+ // extern void TF_DeleteBuffer (TF_Buffer *);
141+ [ DllImport ( NativeBinding . TensorFlowLibrary ) ]
142+ static extern unsafe void TF_DeleteBuffer ( LLBuffer * buffer ) ;
143+
144+ internal override void NativeDispose ( IntPtr handle )
145+ {
146+ unsafe { TF_DeleteBuffer ( ( LLBuffer * ) handle ) ; }
147+ }
148+
149+ // extern TF_Buffer TF_GetBuffer (TF_Buffer *buffer);
150+ [ DllImport ( NativeBinding . TensorFlowLibrary ) ]
151+ static extern unsafe LLBuffer TF_GetBuffer ( LLBuffer * buffer ) ;
152+
153+ /// <summary>
154+ /// Returns a byte array representing the data wrapped by this buffer.
155+ /// </summary>
156+ /// <returns>The array.</returns>
157+ public byte [ ] ToArray ( )
158+ {
159+ if ( handle == IntPtr . Zero )
160+ return null ;
161+
162+ unsafe
163+ {
164+ var lb = ( LLBuffer * ) handle ;
165+
166+ var result = new byte [ ( int ) lb ->length ] ;
167+ Marshal . Copy ( lb ->data , result , 0 , ( int ) lb ->length ) ;
168+
169+ return result ;
170+ }
171+ }
172+ }
173+ }
0 commit comments