[MachineLearning.Inference][Non-ACR] Fix the potential bug (#2547)
[platform/core/csapi/tizenfx.git] / src / Tizen.MachineLearning.Inference / Tizen.MachineLearning.Inference / TensorsData.cs
1 /*
2 * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 using System;
18 using System.Collections;
19
20 namespace Tizen.MachineLearning.Inference
21 {
22     /// <summary>
23     /// The TensorsData class sets and gets the buffer data for each Tensor.
24     /// </summary>
25     /// <since_tizen> 6 </since_tizen>
26     public class TensorsData : IDisposable
27     {
28         private IntPtr _handle = IntPtr.Zero;
29         private bool _disposed = false;
30         private TensorsInfo _tensorsInfo = null;
31         private ArrayList _dataList = null;
32
33         /// <summary>
34         /// Creates a TensorsData instance with handle which is given by TensorsInfo.
35         /// </summary>
36         /// <param name="handle">The handle of tensors data.</param>
37         /// <param name="info">The handle of tensors info.</param>
38         /// <param name="isFetch">The boolean value for fetching the data (Default: false)</param>
39         /// <param name="hasOwnership">The boolean value for automatic disposal (Default: true)</param>
40         /// <since_tizen> 6 </since_tizen>
41         private TensorsData(IntPtr handle, TensorsInfo info, bool isFetch = false, bool hasOwnership = true)
42         {
43             NNStreamer.CheckNNStreamerSupport();
44             NNStreamerError ret = NNStreamerError.None;
45
46             /* Set internal object */
47             _handle = handle;
48             /* Because developers can change the TensorsInfo object, it should be stored as a deep-copied instance. */
49             _tensorsInfo = info.Clone();
50
51             /* Set count */
52             int count = 0;
53             ret = Interop.Util.GetTensorsCount(_handle, out count);
54             NNStreamer.CheckException(ret, "unable to get the count of TensorsData");
55
56             _dataList = new ArrayList(count);
57
58             if (isFetch)
59             {
60                 for (int i = 0; i < count; ++i)
61                 {
62                     IntPtr raw_data;
63                     byte[] bufData = null;
64                     int size;
65
66                     ret = Interop.Util.GetTensorData(_handle, i, out raw_data, out size);
67                     NNStreamer.CheckException(ret, "unable to get the buffer of TensorsData: " + i.ToString());
68
69                     bufData = Interop.Util.IntPtrToByteArray(raw_data, size);
70                     _dataList.Add(bufData);
71                 }
72             }
73             else
74             {
75                 for (int i = 0; i < count; ++i)
76                 {
77                     int size = info.GetTensorSize(i);
78                     byte[] bufData = new byte[size];
79
80                     _dataList.Add(bufData);
81                 }
82             }
83
84             /* If it created as DataReceivedEventArgs, do not dispose. */
85             _disposed = !hasOwnership;
86         }
87
88         /// <summary>
89         /// Destructor of the TensorsData instance
90         /// </summary>
91         /// <since_tizen> 6 </since_tizen>
92         ~TensorsData()
93         {
94             Dispose(false);
95         }
96
97         /// <summary>
98         /// Gets the number of Tensor in TensorsData class
99         /// </summary>
100         /// <feature>http://tizen.org/feature/machine_learning.inference</feature>
101         /// <exception cref="NotSupportedException">Thrown when the feature is not supported.</exception>
102         /// <since_tizen> 6 </since_tizen>
103         public int Count
104         {
105             get {
106                 NNStreamer.CheckNNStreamerSupport();
107
108                 return _dataList.Count;
109             }
110         }
111
112         /// <summary>
113         /// Gets the tensors information.
114         /// </summary>
115         /// <returns>The TensorsInfo instance</returns>
116         /// <feature>http://tizen.org/feature/machine_learning.inference</feature>
117         /// <exception cref="NotSupportedException">Thrown when the feature is not supported.</exception>
118         /// <since_tizen> 8 </since_tizen>
119         public TensorsInfo TensorsInfo
120         {
121             get {
122                 NNStreamer.CheckNNStreamerSupport();
123
124                 return _tensorsInfo;
125             }
126         }
127
128         /// <summary>
129         /// Allocates a new TensorsData instance with the given tensors information.
130         /// </summary>
131         /// <param name="info">TensorsInfo object which has Tensor information</param>
132         /// <returns>The TensorsInfo instance</returns>
133         /// <exception cref="ArgumentException">Thrown when the method failed due to an invalid parameter.</exception>
134         /// <exception cref="NotSupportedException">Thrown when the feature is not supported.</exception>
135         /// <since_tizen> 8 </since_tizen>
136         public static TensorsData Allocate(TensorsInfo info)
137         {
138             NNStreamer.CheckNNStreamerSupport();
139
140             if (info == null)
141                 throw NNStreamerExceptionFactory.CreateException(NNStreamerError.InvalidParameter, "TensorsInfo is null");
142
143             TensorsData retData = info.GetTensorsData();
144             return retData;
145         }
146
147         /// <summary>
148         /// Sets a tensor data to given index.
149         /// </summary>
150         /// <param name="index">The index of the tensor.</param>
151         /// <param name="buffer">Raw tensor data to be set.</param>
152         /// <feature>http://tizen.org/feature/machine_learning.inference</feature>
153         /// <exception cref="NotSupportedException">Thrown when the feature is not supported.</exception>
154         /// <exception cref="ArgumentException">Thrown when the data is not valid.</exception>
155         /// <since_tizen> 6 </since_tizen>
156         public void SetTensorData(int index, byte[] buffer)
157         {
158             NNStreamer.CheckNNStreamerSupport();
159
160             CheckIndex(index);
161             CheckDataBuffer(index, buffer);
162
163             _dataList[index] = buffer;
164         }
165
166         /// <summary>
167         /// Gets a tensor data to given index.
168         /// </summary>
169         /// <param name="index">The index of the tensor.</param>
170         /// <returns>Raw tensor data</returns>
171         /// <feature>http://tizen.org/feature/machine_learning.inference</feature>
172         /// <exception cref="ArgumentException">Thrown when the method failed due to an invalid parameter.</exception>
173         /// <exception cref="NotSupportedException">Thrown when the feature is not supported.</exception>
174         /// <since_tizen> 6 </since_tizen>
175         public byte[] GetTensorData(int index)
176         {
177             NNStreamer.CheckNNStreamerSupport();
178
179             CheckIndex(index);
180
181             return (byte[])_dataList[index];
182         }
183
184         /// <summary>
185         /// Releases any unmanaged resources used by this object.
186         /// </summary>
187         /// <since_tizen> 6 </since_tizen>
188         public void Dispose()
189         {
190             Dispose(true);
191             GC.SuppressFinalize(this);
192         }
193
194         /// <summary>
195         /// Releases any unmanaged resources used by this object. Can also dispose any other disposable objects.
196         /// </summary>
197         /// <param name="disposing">If true, disposes any disposable objects. If false, does not dispose disposable objects.</param>
198         protected virtual void Dispose(bool disposing)
199         {
200             if (_disposed)
201                 return;
202
203             if (disposing)
204             {
205                 // release managed object
206                 _tensorsInfo.Dispose();
207                 _tensorsInfo = null;
208             }
209
210             // release unmanaged objects
211             if (_handle != IntPtr.Zero)
212             {
213                 NNStreamerError ret = Interop.Util.DestroyTensorsData(_handle);
214                 if (ret != NNStreamerError.None)
215                 {
216                     Log.Error(NNStreamer.TAG, "failed to destroy TensorsData object");
217                 }
218                 _handle = IntPtr.Zero;
219             }
220             _disposed = true;
221         }
222
223         internal IntPtr GetHandle()
224         {
225             return _handle;
226         }
227
228         internal void PrepareInvoke()
229         {
230             NNStreamerError ret = NNStreamerError.None;
231             int count = _dataList.Count;
232
233             for (int i = 0; i < count; ++i)
234             {
235                 byte[] data = (byte[])_dataList[i];
236                 ret = Interop.Util.SetTensorData(_handle, i, data, data.Length);
237                 NNStreamer.CheckException(ret, "unable to set the buffer of TensorsData: " + i.ToString());
238             }
239         }
240
241         internal static TensorsData CreateFromNativeHandle(IntPtr dataHandle, IntPtr infoHandle, bool isFetch = false, bool hasOwnership = true)
242         {
243             TensorsInfo info = null;
244
245             if (infoHandle != IntPtr.Zero)
246             {
247                 info = TensorsInfo.ConvertTensorsInfoFromHandle(infoHandle);
248             }
249
250             return new TensorsData(dataHandle, info, isFetch, hasOwnership);
251         }
252
253         private void CheckIndex(int index)
254         {
255             if (index < 0 || index >= _dataList.Count)
256             {
257                 string msg = "Invalid index [" + index + "] of the tensors";
258                 throw NNStreamerExceptionFactory.CreateException(NNStreamerError.InvalidParameter, msg);
259             }
260         }
261
262         private void CheckDataBuffer(int index, byte[] data)
263         {
264             if (data == null)
265             {
266                 string msg = "data is not valid";
267                 throw NNStreamerExceptionFactory.CreateException(NNStreamerError.InvalidParameter, msg);
268             }
269
270             if (index >= Tensor.SizeLimit)
271             {
272                 string msg = "Max size of the tensors is " + Tensor.SizeLimit;
273                 throw NNStreamerExceptionFactory.CreateException(NNStreamerError.QuotaExceeded, msg);
274             }
275
276             if (_tensorsInfo != null)
277             {
278                 if (index >= _tensorsInfo.Count)
279                 {
280                     string msg = "Current information has " + _tensorsInfo.Count + " tensors";
281                     throw NNStreamerExceptionFactory.CreateException(NNStreamerError.QuotaExceeded, msg);
282                 }
283
284                 int size = _tensorsInfo.GetTensorSize(index);
285                 if (data.Length != size)
286                 {
287                     string msg = "Invalid buffer size, required size is " + size.ToString();
288                     throw NNStreamerExceptionFactory.CreateException(NNStreamerError.InvalidParameter, msg);
289                 }
290             }
291         }
292     }
293 }