Line data Source code
1 : /* SPDX-License-Identifier: Apache-2.0 */
2 : /**
3 : * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved.
4 : *
5 : * @file nnstreamer-capi-util.c
6 : * @date 10 June 2019
7 : * @brief NNStreamer/Utilities C-API Wrapper.
8 : * @see https://github.com/nnstreamer/nnstreamer
9 : * @author MyungJoo Ham <myungjoo.ham@samsung.com>
10 : * @bug No known bugs except for NYI items
11 : */
12 :
13 : #include <string.h>
14 : #include <stdio.h>
15 : #include <stdarg.h>
16 : #include <glib.h>
17 : #include <nnstreamer_plugin_api_util.h>
18 : #include "nnstreamer.h"
19 : #include "nnstreamer-tizen-internal.h"
20 : #include "ml-api-internal.h"
21 :
22 : /**
23 : * @brief Enumeration for ml_info type.
24 : */
25 : typedef enum
26 : {
27 : ML_INFO_TYPE_UNKNOWN = 0,
28 : ML_INFO_TYPE_OPTION = 0xfeed0001,
29 : ML_INFO_TYPE_INFORMATION = 0xfeed0010,
30 : ML_INFO_TYPE_INFORMATION_LIST = 0xfeed0011,
31 :
32 : ML_INFO_TYPE_MAX = 0xfeedffff
33 : } ml_info_type_e;
34 :
35 : /**
36 : * @brief Data structure for value of ml_info.
37 : */
38 : typedef struct
39 : {
40 : void *value; /**< The data given by user. */
41 : ml_data_destroy_cb destroy; /**< The destroy func given by user. */
42 : } ml_info_value_s;
43 :
44 : /**
45 : * @brief Data structure for ml_info.
46 : */
47 : typedef struct
48 : {
49 : ml_info_type_e type; /**< The type of ml_info. */
50 : GHashTable *table; /**< hash table used by ml_info. */
51 : } ml_info_s;
52 :
53 : /**
54 : * @brief Data structure for ml_info_list.
55 : */
56 : typedef struct
57 : {
58 : ml_info_type_e type; /**< The type of ml_info. */
59 : GSList *info; /**< The list of ml_info. */
60 : } ml_info_list_s;
61 :
62 : /**
63 : * @brief Gets the version number of machine-learning API.
64 : */
65 : void
66 1 : ml_api_get_version (unsigned int *major, unsigned int *minor,
67 : unsigned int *micro)
68 : {
69 1 : if (major)
70 1 : *major = VERSION_MAJOR;
71 1 : if (minor)
72 1 : *minor = VERSION_MINOR;
73 1 : if (micro)
74 1 : *micro = VERSION_MICRO;
75 1 : }
76 :
77 : /**
78 : * @brief Convert the type from ml_tensor_type_e to tensor_type.
79 : * @note This code is based on the same order between NNS type and ML type.
80 : * The index should be the same in case of adding a new type.
81 : */
82 : static tensor_type
83 423 : convert_tensor_type_from (ml_tensor_type_e type)
84 : {
85 423 : if (type < ML_TENSOR_TYPE_INT32 || type >= ML_TENSOR_TYPE_UNKNOWN) {
86 0 : _ml_error_report
87 : ("Failed to convert the type. Input ml_tensor_type_e %d is invalid.",
88 : type);
89 0 : return _NNS_END;
90 : }
91 :
92 423 : return (tensor_type) type;
93 : }
94 :
95 : /**
96 : * @brief Convert the type from tensor_type to ml_tensor_type_e.
97 : * @note This code is based on the same order between NNS type and ML type.
98 : * The index should be the same in case of adding a new type.
99 : */
100 : static ml_tensor_type_e
101 640 : convert_ml_tensor_type_from (tensor_type type)
102 : {
103 640 : if (type < _NNS_INT32 || type >= _NNS_END) {
104 0 : _ml_error_report
105 : ("Failed to convert the type. Input tensor_type %d is invalid.", type);
106 0 : return ML_TENSOR_TYPE_UNKNOWN;
107 : }
108 :
109 640 : return (ml_tensor_type_e) type;
110 : }
111 :
112 : /**
113 : * @brief Gets the version string of machine-learning API.
114 : */
115 : char *
116 1 : ml_api_get_version_string (void)
117 : {
118 1 : return g_strdup_printf ("Machine Learning API %s", VERSION);
119 : }
120 :
121 : /**
122 : * @brief Internal function to create tensors-info handle.
123 : */
124 : static int
125 19294 : _ml_tensors_info_create_internal (ml_tensors_info_h * info, bool extended)
126 : {
127 : ml_tensors_info_s *tensors_info;
128 :
129 19294 : check_feature_state (ML_FEATURE);
130 :
131 19294 : if (!info)
132 2 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
133 : "The parameter, info, is NULL. Provide a valid pointer.");
134 :
135 19292 : *info = tensors_info = g_new0 (ml_tensors_info_s, 1);
136 19292 : if (tensors_info == NULL)
137 0 : _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
138 : "Failed to allocate the tensors info handle. Out of memory?");
139 :
140 19292 : g_mutex_init (&tensors_info->lock);
141 19292 : tensors_info->is_extended = extended;
142 :
143 : /* init tensors info struct */
144 19292 : return _ml_tensors_info_initialize (tensors_info);
145 : }
146 :
147 : /**
148 : * @brief Creates new tensors-info handle and copies tensors information.
149 : */
150 : int
151 6535 : _ml_tensors_info_create_from (const ml_tensors_info_h in,
152 : ml_tensors_info_h * out)
153 : {
154 : ml_tensors_info_s *_info;
155 : int status;
156 :
157 6535 : if (!in || !out)
158 0 : return ML_ERROR_INVALID_PARAMETER;
159 :
160 6535 : _info = (ml_tensors_info_s *) in;
161 :
162 6535 : if (_info->is_extended)
163 7 : status = ml_tensors_info_create_extended (out);
164 : else
165 6528 : status = ml_tensors_info_create (out);
166 :
167 6535 : if (status == ML_ERROR_NONE)
168 6535 : status = ml_tensors_info_clone (*out, in);
169 :
170 6535 : return status;
171 : }
172 :
173 : /**
174 : * @brief Allocates a tensors information handle with default value.
175 : */
176 : int
177 19259 : ml_tensors_info_create (ml_tensors_info_h * info)
178 : {
179 19259 : return _ml_tensors_info_create_internal (info, false);
180 : }
181 :
182 : /**
183 : * @brief Allocates an extended tensors information handle with default value.
184 : */
185 : int
186 35 : ml_tensors_info_create_extended (ml_tensors_info_h * info)
187 : {
188 35 : return _ml_tensors_info_create_internal (info, true);
189 : }
190 :
191 : /**
192 : * @brief Frees the given handle of a tensors information.
193 : */
194 : int
195 19266 : ml_tensors_info_destroy (ml_tensors_info_h info)
196 : {
197 : ml_tensors_info_s *tensors_info;
198 :
199 19266 : check_feature_state (ML_FEATURE);
200 :
201 19266 : tensors_info = (ml_tensors_info_s *) info;
202 :
203 19266 : if (!tensors_info)
204 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
205 : "The parameter, info, is NULL. Provide a valid pointer.");
206 :
207 19265 : G_LOCK_UNLESS_NOLOCK (*tensors_info);
208 19265 : _ml_tensors_info_free (tensors_info);
209 19265 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
210 :
211 19265 : g_mutex_clear (&tensors_info->lock);
212 19265 : g_free (tensors_info);
213 :
214 19265 : return ML_ERROR_NONE;
215 : }
216 :
217 : /**
218 : * @brief Validates the given tensors info is valid.
219 : */
220 : int
221 6367 : ml_tensors_info_validate (const ml_tensors_info_h info, bool *valid)
222 : {
223 : ml_tensors_info_s *tensors_info;
224 :
225 6367 : check_feature_state (ML_FEATURE);
226 :
227 6367 : if (!valid)
228 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
229 : "The data-return parameter, valid, is NULL. It should be a pointer pre-allocated by the caller.");
230 :
231 6366 : tensors_info = (ml_tensors_info_s *) info;
232 :
233 6366 : if (!tensors_info)
234 3 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
235 : "The input parameter, tensors_info, is NULL. It should be a valid ml_tensors_info_h, which is usually created by ml_tensors_info_create().");
236 :
237 6363 : G_LOCK_UNLESS_NOLOCK (*tensors_info);
238 6363 : *valid = gst_tensors_info_validate (&tensors_info->info);
239 6363 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
240 :
241 6363 : return ML_ERROR_NONE;
242 : }
243 :
244 : /**
245 : * @brief Compares the given tensors information.
246 : */
247 : int
248 68 : _ml_tensors_info_compare (const ml_tensors_info_h info1,
249 : const ml_tensors_info_h info2, bool *equal)
250 : {
251 : ml_tensors_info_s *i1, *i2;
252 :
253 68 : check_feature_state (ML_FEATURE);
254 :
255 68 : if (info1 == NULL)
256 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
257 : "The input parameter, info1, should be a valid ml_tensors_info_h handle, which is usually created by ml_tensors_info_create(). However, info1 is NULL.");
258 67 : if (info2 == NULL)
259 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
260 : "The input parameter, info2, should be a valid ml_tensors_info_h handle, which is usually created by ml_tensors_info_create(). However, info2 is NULL.");
261 66 : if (equal == NULL)
262 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
263 : "The output parameter, equal, should be a valid pointer allocated by the caller. However, equal is NULL.");
264 :
265 65 : i1 = (ml_tensors_info_s *) info1;
266 65 : G_LOCK_UNLESS_NOLOCK (*i1);
267 65 : i2 = (ml_tensors_info_s *) info2;
268 65 : G_LOCK_UNLESS_NOLOCK (*i2);
269 :
270 65 : *equal = gst_tensors_info_is_equal (&i1->info, &i2->info);
271 :
272 65 : G_UNLOCK_UNLESS_NOLOCK (*i2);
273 65 : G_UNLOCK_UNLESS_NOLOCK (*i1);
274 65 : return ML_ERROR_NONE;
275 : }
276 :
277 : /**
278 : * @brief Sets the number of tensors with given handle of tensors information.
279 : */
280 : int
281 137 : ml_tensors_info_set_count (ml_tensors_info_h info, unsigned int count)
282 : {
283 : ml_tensors_info_s *tensors_info;
284 :
285 137 : check_feature_state (ML_FEATURE);
286 :
287 137 : if (!info)
288 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
289 : "The parameter, info, is NULL. It should be a valid ml_tensors_info_h handle, which is usually created by ml_tensors_info_create().");
290 136 : if (count > ML_TENSOR_SIZE_LIMIT || count == 0)
291 2 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
292 : "The parameter, count, is the number of tensors, which should be between 1 and %d. The given count is %u.",
293 : ML_TENSOR_SIZE_LIMIT, count);
294 :
295 134 : tensors_info = (ml_tensors_info_s *) info;
296 :
297 : /* This is atomic. No need for locks */
298 134 : tensors_info->info.num_tensors = count;
299 :
300 134 : return ML_ERROR_NONE;
301 : }
302 :
303 : /**
304 : * @brief Gets the number of tensors with given handle of tensors information.
305 : */
306 : int
307 82 : ml_tensors_info_get_count (ml_tensors_info_h info, unsigned int *count)
308 : {
309 : ml_tensors_info_s *tensors_info;
310 :
311 82 : check_feature_state (ML_FEATURE);
312 :
313 82 : if (!info)
314 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
315 : "The parameter, info, is NULL. It should be a valid ml_tensors_info_h handle, which is usually created by ml_tensors_info_create().");
316 81 : if (!count)
317 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
318 : "The parameter, count, is NULL. It should be a valid unsigned int * pointer, allocated by the caller.");
319 :
320 80 : tensors_info = (ml_tensors_info_s *) info;
321 : /* This is atomic. No need for locks */
322 80 : *count = tensors_info->info.num_tensors;
323 :
324 80 : return ML_ERROR_NONE;
325 : }
326 :
327 : /**
328 : * @brief Sets the tensor name with given handle of tensors information.
329 : */
330 : int
331 10 : ml_tensors_info_set_tensor_name (ml_tensors_info_h info,
332 : unsigned int index, const char *name)
333 : {
334 : ml_tensors_info_s *tensors_info;
335 : GstTensorInfo *_info;
336 :
337 10 : check_feature_state (ML_FEATURE);
338 :
339 10 : if (!info)
340 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
341 : "The parameter, info, is NULL. It should be a valid ml_tensors_info_h handle, which is usually created by ml_tensors_info_create().");
342 :
343 9 : tensors_info = (ml_tensors_info_s *) info;
344 9 : G_LOCK_UNLESS_NOLOCK (*tensors_info);
345 :
346 9 : if (tensors_info->info.num_tensors <= index) {
347 1 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
348 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
349 : "The number of tensors in 'info' parameter is %u, which is not larger than the given 'index' %u. Thus, we cannot get %u'th tensor from 'info'. Please set the number of tensors of 'info' correctly or check the value of the given 'index'.",
350 : tensors_info->info.num_tensors, index, index);
351 : }
352 :
353 8 : _info = gst_tensors_info_get_nth_info (&tensors_info->info, index);
354 8 : if (!_info) {
355 0 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
356 0 : return ML_ERROR_INVALID_PARAMETER;
357 : }
358 :
359 8 : g_free (_info->name);
360 8 : _info->name = g_strdup (name);
361 :
362 8 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
363 8 : return ML_ERROR_NONE;
364 : }
365 :
366 : /**
367 : * @brief Gets the tensor name with given handle of tensors information.
368 : */
369 : int
370 18 : ml_tensors_info_get_tensor_name (ml_tensors_info_h info,
371 : unsigned int index, char **name)
372 : {
373 : ml_tensors_info_s *tensors_info;
374 : GstTensorInfo *_info;
375 :
376 18 : check_feature_state (ML_FEATURE);
377 :
378 18 : if (!info)
379 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
380 : "The parameter, info, is NULL. It should be a valid ml_tensors_info_h handle, which is usually created by ml_tensors_info_create().");
381 17 : if (!name)
382 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
383 : "The parameter, name, is NULL. It should be a valid char ** pointer, allocated by the caller. E.g., char *name; ml_tensors_info_get_tensor_name (info, index, &name);");
384 :
385 16 : tensors_info = (ml_tensors_info_s *) info;
386 16 : G_LOCK_UNLESS_NOLOCK (*tensors_info);
387 :
388 16 : if (tensors_info->info.num_tensors <= index) {
389 2 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
390 2 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
391 : "The number of tensors in 'info' parameter is %u, which is not larger than the given 'index' %u. Thus, we cannot get %u'th tensor from 'info'. Please set the number of tensors of 'info' correctly or check the value of the given 'index'.",
392 : tensors_info->info.num_tensors, index, index);
393 : }
394 :
395 14 : _info = gst_tensors_info_get_nth_info (&tensors_info->info, index);
396 14 : if (!_info) {
397 0 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
398 0 : return ML_ERROR_INVALID_PARAMETER;
399 : }
400 :
401 14 : *name = g_strdup (_info->name);
402 :
403 14 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
404 14 : return ML_ERROR_NONE;
405 : }
406 :
407 : /**
408 : * @brief Sets the tensor type with given handle of tensors information.
409 : */
410 : int
411 429 : ml_tensors_info_set_tensor_type (ml_tensors_info_h info,
412 : unsigned int index, const ml_tensor_type_e type)
413 : {
414 : ml_tensors_info_s *tensors_info;
415 : GstTensorInfo *_info;
416 :
417 429 : check_feature_state (ML_FEATURE);
418 :
419 429 : if (!info)
420 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
421 : "The parameter, info, is NULL. It should be a valid pointer of ml_tensors_info_h, which is usually created by ml_tensors_info_create().");
422 :
423 428 : if (type >= ML_TENSOR_TYPE_UNKNOWN || type < 0)
424 2 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
425 : "The parameter, type, ML_TENSOR_TYPE_UNKNOWN or out of bound. The value of type should be between 0 and ML_TENSOR_TYPE_UNKNOWN - 1. type = %d, ML_TENSOR_TYPE_UNKNOWN = %d.",
426 : type, ML_TENSOR_TYPE_UNKNOWN);
427 :
428 : #ifndef FLOAT16_SUPPORT
429 426 : if (type == ML_TENSOR_TYPE_FLOAT16)
430 1 : _ml_error_report_return (ML_ERROR_NOT_SUPPORTED,
431 : "Float16 (IEEE 754) is not supported by the machine (or the compiler or your build configuration). You cannot configure ml_tensors_info instance with Float16 type.");
432 : #endif
433 : /** @todo add BFLOAT16 when nnstreamer is ready for it. */
434 :
435 425 : tensors_info = (ml_tensors_info_s *) info;
436 425 : G_LOCK_UNLESS_NOLOCK (*tensors_info);
437 :
438 425 : if (tensors_info->info.num_tensors <= index) {
439 2 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
440 2 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
441 : "The number of tensors in 'info' parameter is %u, which is not larger than the given 'index' %u. Thus, we cannot get %u'th tensor from 'info'. Please set the number of tensors of 'info' correctly or check the value of the given 'index'.",
442 : tensors_info->info.num_tensors, index, index);
443 : }
444 :
445 423 : _info = gst_tensors_info_get_nth_info (&tensors_info->info, index);
446 423 : if (!_info) {
447 0 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
448 0 : return ML_ERROR_INVALID_PARAMETER;
449 : }
450 :
451 423 : _info->type = convert_tensor_type_from (type);
452 :
453 423 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
454 423 : return ML_ERROR_NONE;
455 : }
456 :
457 : /**
458 : * @brief Gets the tensor type with given handle of tensors information.
459 : */
460 : int
461 644 : ml_tensors_info_get_tensor_type (ml_tensors_info_h info,
462 : unsigned int index, ml_tensor_type_e * type)
463 : {
464 : ml_tensors_info_s *tensors_info;
465 : GstTensorInfo *_info;
466 :
467 644 : check_feature_state (ML_FEATURE);
468 :
469 644 : if (!info)
470 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
471 : "The parameter, info, is NULL. It should be a valid ml_tensors_info_h handle, which is usually created by ml_tensors_info_create().");
472 643 : if (!type)
473 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
474 : "The parameter, type, is NULL. It should be a valid pointer of ml_tensor_type_e *, allocated by the caller. E.g., ml_tensor_type_e t; ml_tensors_info_get_tensor_type (info, index, &t);");
475 :
476 642 : tensors_info = (ml_tensors_info_s *) info;
477 642 : G_LOCK_UNLESS_NOLOCK (*tensors_info);
478 :
479 642 : if (tensors_info->info.num_tensors <= index) {
480 2 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
481 2 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
482 : "The number of tensors in 'info' parameter is %u, which is not larger than the given 'index' %u. Thus, we cannot get %u'th tensor from 'info'. Please set the number of tensors of 'info' correctly or check the value of the given 'index'.",
483 : tensors_info->info.num_tensors, index, index);
484 : }
485 :
486 640 : _info = gst_tensors_info_get_nth_info (&tensors_info->info, index);
487 640 : if (!_info) {
488 0 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
489 0 : return ML_ERROR_INVALID_PARAMETER;
490 : }
491 :
492 640 : *type = convert_ml_tensor_type_from (_info->type);
493 :
494 640 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
495 640 : return ML_ERROR_NONE;
496 : }
497 :
498 : /**
499 : * @brief Sets the tensor dimension with given handle of tensors information.
500 : */
501 : int
502 422 : ml_tensors_info_set_tensor_dimension (ml_tensors_info_h info,
503 : unsigned int index, const ml_tensor_dimension dimension)
504 : {
505 : ml_tensors_info_s *tensors_info;
506 : GstTensorInfo *_info;
507 : guint i, rank, max_rank;
508 :
509 422 : check_feature_state (ML_FEATURE);
510 :
511 422 : if (!info)
512 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
513 : "The parameter, info, is NULL. It should be a valid pointer of ml_tensors_info_h, which is usually created by ml_tensors_info_create().");
514 :
515 421 : tensors_info = (ml_tensors_info_s *) info;
516 421 : G_LOCK_UNLESS_NOLOCK (*tensors_info);
517 :
518 421 : if (tensors_info->info.num_tensors <= index) {
519 2 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
520 2 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
521 : "The number of tensors in 'info' parameter is %u, which is not larger than the given 'index' %u. Thus, we cannot get %u'th tensor from 'info'. Please set the number of tensors of 'info' correctly or check the value of the given 'index'.",
522 : tensors_info->info.num_tensors, index, index);
523 : }
524 :
525 : /**
526 : * Validate dimension.
527 : * We cannot use util function to get the rank of tensor dimension here.
528 : * The old rank limit is 4, and testcases or app may set old dimension.
529 : */
530 838 : max_rank = tensors_info->is_extended ?
531 419 : ML_TENSOR_RANK_LIMIT : ML_TENSOR_RANK_LIMIT_PREV;
532 419 : rank = max_rank + 1;
533 2234 : for (i = 0; i < max_rank; i++) {
534 1819 : if (dimension[i] == 0) {
535 82 : if (rank > max_rank)
536 21 : rank = i;
537 : }
538 :
539 1819 : if (rank == 0 || (i > rank && dimension[i] > 0)) {
540 4 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
541 4 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
542 : "The parameter, dimension, is invalid. It should be a valid unsigned integer array.");
543 : }
544 : }
545 :
546 415 : _info = gst_tensors_info_get_nth_info (&tensors_info->info, index);
547 415 : if (!_info) {
548 0 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
549 0 : return ML_ERROR_INVALID_PARAMETER;
550 : }
551 :
552 2075 : for (i = 0; i < ML_TENSOR_RANK_LIMIT_PREV; i++) {
553 1660 : _info->dimension[i] = dimension[i];
554 : }
555 :
556 5395 : for (i = ML_TENSOR_RANK_LIMIT_PREV; i < ML_TENSOR_RANK_LIMIT; i++) {
557 4980 : _info->dimension[i] = (tensors_info->is_extended ? dimension[i] : 0);
558 : }
559 :
560 415 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
561 415 : return ML_ERROR_NONE;
562 : }
563 :
564 : /**
565 : * @brief Gets the tensor dimension with given handle of tensors information.
566 : */
567 : int
568 1119 : ml_tensors_info_get_tensor_dimension (ml_tensors_info_h info,
569 : unsigned int index, ml_tensor_dimension dimension)
570 : {
571 : ml_tensors_info_s *tensors_info;
572 : GstTensorInfo *_info;
573 1119 : guint i, valid_rank = ML_TENSOR_RANK_LIMIT;
574 :
575 1119 : check_feature_state (ML_FEATURE);
576 :
577 1119 : if (!info)
578 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
579 : "The parameter, info, is NULL. It should be a valid pointer of ml_tensors_info_h, which is usually created by ml_tensors_info_create().");
580 :
581 1118 : tensors_info = (ml_tensors_info_s *) info;
582 1118 : G_LOCK_UNLESS_NOLOCK (*tensors_info);
583 :
584 1118 : if (tensors_info->info.num_tensors <= index) {
585 2 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
586 2 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
587 : "The number of tensors in 'info' parameter is %u, which is not larger than the given 'index' %u. Thus, we cannot get %u'th tensor from 'info'. Please set the number of tensors of 'info' correctly or check the value of the given 'index'.",
588 : tensors_info->info.num_tensors, index, index);
589 : }
590 :
591 1116 : _info = gst_tensors_info_get_nth_info (&tensors_info->info, index);
592 1116 : if (!_info) {
593 0 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
594 0 : return ML_ERROR_INVALID_PARAMETER;
595 : }
596 :
597 1116 : if (!tensors_info->is_extended)
598 1108 : valid_rank = ML_TENSOR_RANK_LIMIT_PREV;
599 :
600 5676 : for (i = 0; i < valid_rank; i++) {
601 4560 : dimension[i] = _info->dimension[i];
602 : }
603 :
604 14412 : for (; i < ML_TENSOR_RANK_LIMIT; i++)
605 13296 : dimension[i] = 0;
606 :
607 1116 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
608 1116 : return ML_ERROR_NONE;
609 : }
610 :
611 : /**
612 : * @brief Gets the byte size of the given handle of tensors information.
613 : */
614 : int
615 25 : ml_tensors_info_get_tensor_size (ml_tensors_info_h info,
616 : int index, size_t *data_size)
617 : {
618 : ml_tensors_info_s *tensors_info;
619 :
620 25 : check_feature_state (ML_FEATURE);
621 :
622 25 : if (!info)
623 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
624 : "The parameter, info, is NULL. Provide a valid pointer.");
625 24 : if (!data_size)
626 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
627 : "The parameter, data_size, is NULL. It should be a valid size_t * pointer allocated by the caller. E.g., size_t d; ml_tensors_info_get_tensor_size (info, index, &d);");
628 :
629 23 : tensors_info = (ml_tensors_info_s *) info;
630 23 : G_LOCK_UNLESS_NOLOCK (*tensors_info);
631 :
632 : /* init 0 */
633 23 : *data_size = 0;
634 :
635 23 : if (index >= 0 && tensors_info->info.num_tensors <= index) {
636 2 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
637 2 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
638 : "The number of tensors in 'info' parameter is %u, which is not larger than the given 'index' %u. Thus, we cannot get %u'th tensor from 'info'. Please set the number of tensors of 'info' correctly or check the value of the given 'index'.",
639 : tensors_info->info.num_tensors, index, index);
640 : }
641 :
642 21 : *data_size = gst_tensors_info_get_size (&tensors_info->info, index);
643 :
644 21 : G_UNLOCK_UNLESS_NOLOCK (*tensors_info);
645 21 : return ML_ERROR_NONE;
646 : }
647 :
648 : /**
649 : * @brief Initializes the tensors information with default value.
650 : */
651 : int
652 19293 : _ml_tensors_info_initialize (ml_tensors_info_s * info)
653 : {
654 19293 : if (!info)
655 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
656 : "The parameter, info, is NULL. Provide a valid pointer.");
657 :
658 19292 : gst_tensors_info_init (&info->info);
659 :
660 19292 : return ML_ERROR_NONE;
661 : }
662 :
663 : /**
664 : * @brief Frees and initialize the data in tensors info.
665 : * @note This does not touch the lock. The caller should lock.
666 : */
667 : void
668 19305 : _ml_tensors_info_free (ml_tensors_info_s * info)
669 : {
670 19305 : if (!info)
671 0 : return;
672 :
673 19305 : gst_tensors_info_free (&info->info);
674 : }
675 :
676 : /**
677 : * @brief Frees the tensors data handle and its data.
678 : * @param[in] data The handle of tensors data.
679 : * @param[in] free_data The flag to free the buffers in handle.
680 : * @return @c 0 on success. Otherwise a negative error value.
681 : */
682 : int
683 12639 : _ml_tensors_data_destroy_internal (ml_tensors_data_h data, gboolean free_data)
684 : {
685 12639 : int status = ML_ERROR_NONE;
686 : ml_tensors_data_s *_data;
687 : guint i;
688 :
689 12639 : if (data == NULL)
690 19 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
691 : "The parameter, data, is NULL. It should be a valid ml_tensors_data_h handle, which is usually created by ml_tensors_data_create ().");
692 :
693 12620 : _data = (ml_tensors_data_s *) data;
694 12620 : G_LOCK_UNLESS_NOLOCK (*_data);
695 :
696 12620 : if (free_data) {
697 449 : if (_data->destroy) {
698 0 : status = _data->destroy (_data, _data->user_data);
699 0 : if (status != ML_ERROR_NONE) {
700 0 : G_UNLOCK_UNLESS_NOLOCK (*_data);
701 0 : _ml_error_report_return_continue (status,
702 : "Tried to destroy internal user_data of the given parameter, data, with its destroy callback; however, it has failed with %d.",
703 : status);
704 : }
705 : } else {
706 115393 : for (i = 0; i < ML_TENSOR_SIZE_LIMIT; i++) {
707 114944 : if (_data->tensors[i].data) {
708 673 : g_free (_data->tensors[i].data);
709 673 : _data->tensors[i].data = NULL;
710 : }
711 : }
712 : }
713 : }
714 :
715 12620 : if (_data->info)
716 12620 : ml_tensors_info_destroy (_data->info);
717 :
718 12620 : G_UNLOCK_UNLESS_NOLOCK (*_data);
719 12620 : g_mutex_clear (&_data->lock);
720 12620 : g_free (_data);
721 12620 : return status;
722 : }
723 :
724 : /**
725 : * @brief Frees the tensors data pointer.
726 : * @note This does not touch the lock
727 : */
728 : int
729 468 : ml_tensors_data_destroy (ml_tensors_data_h data)
730 : {
731 : int ret;
732 468 : check_feature_state (ML_FEATURE);
733 468 : ret = _ml_tensors_data_destroy_internal (data, TRUE);
734 468 : if (ret != ML_ERROR_NONE)
735 19 : _ml_error_report_return_continue (ret,
736 : "Call to _ml_tensors_data_destroy_internal failed with %d", ret);
737 449 : return ret;
738 : }
739 :
740 : /**
741 : * @brief Creates a tensor data frame without buffer with the given tensors information.
742 : * @note Memory for tensor data buffers is not allocated.
743 : */
744 : int
745 12643 : _ml_tensors_data_create_no_alloc (const ml_tensors_info_h info,
746 : ml_tensors_data_h * data)
747 : {
748 : ml_tensors_data_s *_data;
749 : ml_tensors_info_s *_info;
750 : guint i;
751 12643 : int status = ML_ERROR_NONE;
752 :
753 12643 : check_feature_state (ML_FEATURE);
754 :
755 12643 : if (data == NULL)
756 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
757 : "The parameter, data, is NULL. It should be a valid ml_tensors_info_h handle that may hold a space for ml_tensors_info_h. E.g., ml_tensors_data_h data; _ml_tensors_data_create_no_alloc (info, &data);.");
758 :
759 : /* init null */
760 12642 : *data = NULL;
761 :
762 12642 : _data = g_new0 (ml_tensors_data_s, 1);
763 12642 : if (!_data)
764 0 : _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
765 : "Failed to allocate memory for tensors data. Probably the system is out of memory.");
766 :
767 12642 : g_mutex_init (&_data->lock);
768 :
769 12642 : _info = (ml_tensors_info_s *) info;
770 12642 : if (_info != NULL) {
771 6526 : status = _ml_tensors_info_create_from (info, &_data->info);
772 6526 : if (status != ML_ERROR_NONE) {
773 0 : _ml_error_report_continue
774 : ("Failed to create internal information handle for tensors data.");
775 0 : goto error;
776 : }
777 :
778 6526 : G_LOCK_UNLESS_NOLOCK (*_info);
779 6526 : _data->num_tensors = _info->info.num_tensors;
780 13492 : for (i = 0; i < _data->num_tensors; i++) {
781 6966 : _data->tensors[i].size = gst_tensors_info_get_size (&_info->info, i);
782 6966 : _data->tensors[i].data = NULL;
783 : }
784 6526 : G_UNLOCK_UNLESS_NOLOCK (*_info);
785 : }
786 :
787 6116 : error:
788 12642 : if (status == ML_ERROR_NONE) {
789 12642 : *data = _data;
790 : } else {
791 0 : _ml_tensors_data_destroy_internal (_data, FALSE);
792 : }
793 :
794 12642 : return status;
795 : }
796 :
797 : /**
798 : * @brief Clones the given tensor data frame from the given tensors data. (more info in nnstreamer.h)
799 : * @note Memory ptr for data buffer is copied. No new memory for data buffer is allocated.
800 : */
801 : int
802 79 : _ml_tensors_data_clone_no_alloc (const ml_tensors_data_s * data_src,
803 : ml_tensors_data_h * data)
804 : {
805 : int status;
806 : ml_tensors_data_s *_data;
807 :
808 158 : check_feature_state (ML_FEATURE);
809 :
810 79 : if (data == NULL)
811 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
812 : "The parameter, data, is NULL. It should be a valid ml_tensors_data_h handle, which is usually created by ml_tensors_data_create ().");
813 79 : if (data_src == NULL)
814 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
815 : "The parameter, data_src, the source data to be cloned, is NULL. It should be a valid ml_tensors_data_s struct (internal representation of ml_tensors_data_h handle).");
816 :
817 79 : status = _ml_tensors_data_create_no_alloc (data_src->info,
818 : (ml_tensors_data_h *) & _data);
819 79 : if (status != ML_ERROR_NONE)
820 0 : _ml_error_report_return_continue (status,
821 : "The call to _ml_tensors_data_create_no_alloc has failed with %d.",
822 : status);
823 :
824 79 : G_LOCK_UNLESS_NOLOCK (*_data);
825 :
826 79 : _data->num_tensors = data_src->num_tensors;
827 79 : memcpy (_data->tensors, data_src->tensors,
828 79 : sizeof (GstTensorMemory) * data_src->num_tensors);
829 :
830 79 : *data = _data;
831 79 : G_UNLOCK_UNLESS_NOLOCK (*_data);
832 79 : return ML_ERROR_NONE;
833 : }
834 :
835 : /**
836 : * @brief Allocates zero-initialized memory of the given size for the tensor at the specified index
837 : * in the tensor data structure, and sets the size value for that tensor.
838 : */
839 : static int
840 6492 : _ml_tensor_data_alloc (ml_tensors_data_s * data, guint index, const size_t size)
841 : {
842 6492 : if (!data || index >= data->num_tensors || size <= 0)
843 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
844 : "Invalid parameter: data is invalid, or index is out of range.");
845 :
846 6492 : data->tensors[index].size = size;
847 6492 : data->tensors[index].data = g_malloc0 (size);
848 6492 : if (data->tensors[index].data == NULL)
849 0 : _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
850 : "Failed to allocate memory for tensor data.");
851 :
852 6492 : return ML_ERROR_NONE;
853 : }
854 :
855 : /**
856 : * @brief Copies the tensor data frame.
857 : */
858 : int
859 156 : ml_tensors_data_clone (const ml_tensors_data_h in, ml_tensors_data_h * out)
860 : {
861 : int status;
862 : unsigned int i;
863 156 : ml_tensors_data_s *_in, *_out = NULL;
864 :
865 156 : check_feature_state (ML_FEATURE);
866 :
867 156 : if (in == NULL)
868 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
869 : "The parameter, in, is NULL. It should be a valid ml_tensors_data_h handle, which is usually created by ml_tensors_data_create ().");
870 :
871 155 : if (out == NULL)
872 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
873 : "The parameter, out, is NULL. It should be a valid pointer to a space that can hold a ml_tensors_data_h handle. E.g., ml_tensors_data_h out; ml_tensors_data_clone (in, &out);.");
874 :
875 154 : _in = (ml_tensors_data_s *) in;
876 154 : G_LOCK_UNLESS_NOLOCK (*_in);
877 :
878 154 : status = ml_tensors_data_create (_in->info, out);
879 154 : if (status != ML_ERROR_NONE) {
880 0 : _ml_loge ("Failed to create new handle to copy tensor data.");
881 0 : goto error;
882 : }
883 :
884 154 : _out = (ml_tensors_data_s *) (*out);
885 :
886 464 : for (i = 0; i < _out->num_tensors; ++i) {
887 310 : if (!_out->tensors[i].data) {
888 : /**
889 : * If tensor format is static, memory is already allocated.
890 : * However, flexible tensor is not. To copy raw data, allocate new memory here.
891 : */
892 0 : status = _ml_tensor_data_alloc (_out, i, _in->tensors[i].size);
893 0 : if (status != ML_ERROR_NONE) {
894 0 : goto error;
895 : }
896 : }
897 :
898 310 : memcpy (_out->tensors[i].data, _in->tensors[i].data, _in->tensors[i].size);
899 : }
900 :
901 154 : error:
902 154 : if (status != ML_ERROR_NONE) {
903 : /* Failed to create new data handle. */
904 0 : _ml_tensors_data_destroy_internal (_out, TRUE);
905 0 : *out = NULL;
906 : }
907 :
908 154 : G_UNLOCK_UNLESS_NOLOCK (*_in);
909 154 : return status;
910 : }
911 :
912 : /**
913 : * @brief Gets the tensors information of given tensor data frame.
914 : */
915 : int
916 3 : ml_tensors_data_get_info (const ml_tensors_data_h data,
917 : ml_tensors_info_h * info)
918 : {
919 : int status;
920 : ml_tensors_data_s *_data;
921 :
922 3 : check_feature_state (ML_FEATURE);
923 :
924 3 : if (data == NULL) {
925 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
926 : "The parameter, data, is NULL. It should be a valid ml_tensors_data_h handle, which is usually created by ml_tensors_data_create ().");
927 : }
928 :
929 2 : if (info == NULL) {
930 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
931 : "The parameter, info, is NULL. It should be a valid pointer to a space that can hold a ml_tensors_info_h handle. E.g., ml_tensors_info_h info; ml_tensors_data_get_info (data, &info);.");
932 : }
933 :
934 1 : _data = (ml_tensors_data_s *) data;
935 1 : G_LOCK_UNLESS_NOLOCK (*_data);
936 :
937 1 : status = _ml_tensors_info_create_from (_data->info, info);
938 1 : if (status != ML_ERROR_NONE) {
939 0 : _ml_error_report_continue
940 : ("Failed to get the tensor information from data handle.");
941 : }
942 :
943 1 : G_UNLOCK_UNLESS_NOLOCK (*_data);
944 1 : return status;
945 : }
946 :
947 : /**
948 : * @brief Allocates a tensor data frame with the given tensors info. (more info in nnstreamer.h)
949 : */
950 : int
951 6273 : ml_tensors_data_create (const ml_tensors_info_h info, ml_tensors_data_h * data)
952 : {
953 6273 : int status = ML_ERROR_NONE;
954 6273 : ml_tensors_info_s *_info = NULL;
955 6273 : ml_tensors_data_s *_data = NULL;
956 : guint i;
957 : bool valid;
958 :
959 12546 : check_feature_state (ML_FEATURE);
960 :
961 6273 : if (info == NULL)
962 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
963 : "The parameter, info, is NULL. It should be a valid pointer of ml_tensors_info_h, which is usually created by ml_tensors_info_create().");
964 6272 : if (data == NULL)
965 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
966 : "The parameter, data, is NULL. It should be a valid space to hold a ml_tensors_data_h handle. E.g., ml_tensors_data_h data; ml_tensors_data_create (info, &data);.");
967 :
968 6271 : status = ml_tensors_info_validate (info, &valid);
969 6271 : if (status != ML_ERROR_NONE)
970 0 : _ml_error_report_return_continue (status,
971 : "ml_tensors_info_validate() has reported that the parameter, info, is not NULL, but its contents are not valid. The user must provide a valid tensor information with it.");
972 6271 : if (!valid)
973 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
974 : "The parameter, info, is not NULL, but its contents are not valid. The user must provide a valid tensor information with it. Probably, there is an entry that is not allocated or dimension/type information not available. The given info should have valid number of tensors, entries of every tensor along with its type and dimension info.");
975 :
976 : status =
977 6270 : _ml_tensors_data_create_no_alloc (info, (ml_tensors_data_h *) & _data);
978 :
979 6270 : if (status != ML_ERROR_NONE) {
980 0 : _ml_error_report_return_continue (status,
981 : "Failed to allocate tensor data based on the given info with the call to _ml_tensors_data_create_no_alloc (): %d. Check if it's out-of-memory.",
982 : status);
983 : }
984 :
985 6270 : _info = (ml_tensors_info_s *) info;
986 6270 : if (_info->info.format == _NNS_TENSOR_FORMAT_STATIC) {
987 12762 : for (i = 0; i < _data->num_tensors; i++) {
988 6492 : status = _ml_tensor_data_alloc (_data, i, _data->tensors[i].size);
989 6492 : if (status != ML_ERROR_NONE)
990 0 : goto error;
991 : }
992 : } else {
993 0 : _ml_logw
994 : ("[ml_tensors_data_create] format is not static, skipping tensor memory allocation. Use ml_tensors_data_set_tensor_data() to update data buffer.");
995 : }
996 :
997 6270 : error:
998 6270 : if (status == ML_ERROR_NONE) {
999 6270 : *data = _data;
1000 : } else {
1001 0 : _ml_tensors_data_destroy_internal (_data, TRUE);
1002 : }
1003 :
1004 6270 : return status;
1005 : }
1006 :
1007 : /**
1008 : * @brief Gets a tensor data of given handle.
1009 : */
1010 : int
1011 770 : ml_tensors_data_get_tensor_data (ml_tensors_data_h data, unsigned int index,
1012 : void **raw_data, size_t *data_size)
1013 : {
1014 : ml_tensors_data_s *_data;
1015 770 : int status = ML_ERROR_NONE;
1016 :
1017 770 : check_feature_state (ML_FEATURE);
1018 :
1019 770 : if (data == NULL)
1020 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1021 : "The parameter, data, is NULL. It should be a valid ml_tensors_data_h handle, which is usually created by ml_tensors_data_create ().");
1022 769 : if (raw_data == NULL)
1023 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1024 : "The parameter, raw_data, is NULL. It should be a valid, non-NULL, void ** pointer, which is supposed to point to the raw data of tensors[index] after the call.");
1025 768 : if (data_size == NULL)
1026 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1027 : "The parameter, data_size, is NULL. It should be a valid, non-NULL, size_t * pointer, which is supposed to point to the size of returning raw_data after the call.");
1028 :
1029 767 : _data = (ml_tensors_data_s *) data;
1030 767 : G_LOCK_UNLESS_NOLOCK (*_data);
1031 :
1032 767 : if (_data->num_tensors <= index) {
1033 2 : _ml_error_report
1034 : ("The parameter, index, is out of bound. The number of tensors of 'data' is %u while you requested %u'th tensor (index = %u).",
1035 : _data->num_tensors, index, index);
1036 2 : status = ML_ERROR_INVALID_PARAMETER;
1037 2 : goto report;
1038 : }
1039 :
1040 765 : *raw_data = _data->tensors[index].data;
1041 765 : *data_size = _data->tensors[index].size;
1042 :
1043 767 : report:
1044 767 : G_UNLOCK_UNLESS_NOLOCK (*_data);
1045 767 : return status;
1046 : }
1047 :
1048 : /**
1049 : * @brief Copies a tensor data to given handle.
1050 : */
1051 : int
1052 281 : ml_tensors_data_set_tensor_data (ml_tensors_data_h data, unsigned int index,
1053 : const void *raw_data, const size_t data_size)
1054 : {
1055 281 : ml_tensors_info_s *_info = NULL;
1056 : ml_tensors_data_s *_data;
1057 281 : int status = ML_ERROR_NONE;
1058 :
1059 281 : check_feature_state (ML_FEATURE);
1060 :
1061 281 : if (data == NULL)
1062 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1063 : "The parameter, data, is NULL. It should be a valid ml_tensors_data_h handle, which is usually created by ml_tensors_data_create ().");
1064 280 : if (raw_data == NULL)
1065 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1066 : "The parameter, raw_data, is NULL. It should be a valid, non-NULL, void * pointer, which is supposed to point to the raw data of tensors[index: %u].",
1067 : index);
1068 :
1069 279 : _data = (ml_tensors_data_s *) data;
1070 279 : G_LOCK_UNLESS_NOLOCK (*_data);
1071 :
1072 279 : if (_data->num_tensors <= index) {
1073 1 : _ml_error_report
1074 : ("The parameter, index, is out of bound. The number of tensors of 'data' is %u, while you've requested index of %u.",
1075 : _data->num_tensors, index);
1076 1 : status = ML_ERROR_INVALID_PARAMETER;
1077 1 : goto report;
1078 : }
1079 :
1080 : /**
1081 : * By default, the tensor format is _NNS_TENSOR_FORMAT_STATIC.
1082 : * In this case, memory allocation and the setting of _data->tensors[index].size
1083 : * are already handled in ml_tensors_data_create().
1084 : * So for the STATIC format, both the `size` and `data` pointer should already be valid here.
1085 : *
1086 : * For FLEXIBLE format, memory may not be allocated yet and will be handled here.
1087 : */
1088 278 : _info = (ml_tensors_info_s *) _data->info;
1089 278 : if (_info && _info->info.format != _NNS_TENSOR_FORMAT_STATIC) {
1090 0 : if (!_data->tensors[index].data ||
1091 0 : _data->tensors[index].size != data_size) {
1092 0 : _ml_logw
1093 : ("Memory allocation was not performed in ml_tensor_data_create() when tensor format is flexible.");
1094 :
1095 0 : g_free (_data->tensors[index].data);
1096 :
1097 0 : status = _ml_tensor_data_alloc (_data, index, data_size);
1098 0 : if (status != ML_ERROR_NONE) {
1099 0 : goto report;
1100 : }
1101 : }
1102 : }
1103 :
1104 278 : if (data_size <= 0 || _data->tensors[index].size < data_size) {
1105 2 : _ml_error_report
1106 : ("The parameter, data_size (%zu), is invalid. It should be larger than 0 and not larger than the required size of tensors[index: %u] (%zu).",
1107 : data_size, index, _data->tensors[index].size);
1108 2 : status = ML_ERROR_INVALID_PARAMETER;
1109 2 : goto report;
1110 : }
1111 :
1112 276 : if (_data->tensors[index].data != raw_data)
1113 273 : memcpy (_data->tensors[index].data, raw_data, data_size);
1114 :
1115 3 : report:
1116 279 : G_UNLOCK_UNLESS_NOLOCK (*_data);
1117 279 : return status;
1118 : }
1119 :
1120 : /**
1121 : * @brief Copies tensor meta info.
1122 : */
1123 : int
1124 6548 : ml_tensors_info_clone (ml_tensors_info_h dest, const ml_tensors_info_h src)
1125 : {
1126 : ml_tensors_info_s *dest_info, *src_info;
1127 6548 : int status = ML_ERROR_NONE;
1128 :
1129 6548 : check_feature_state (ML_FEATURE);
1130 :
1131 6548 : dest_info = (ml_tensors_info_s *) dest;
1132 6548 : src_info = (ml_tensors_info_s *) src;
1133 :
1134 6548 : if (!dest_info)
1135 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1136 : "The parameter, dest, is NULL. It should be an allocated handle (ml_tensors_info_h), usually allocated by ml_tensors_info_create ().");
1137 6547 : if (!src_info)
1138 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1139 : "The parameter, src, is NULL. It should be a handle (ml_tensors_info_h) with valid data.");
1140 :
1141 6546 : G_LOCK_UNLESS_NOLOCK (*dest_info);
1142 6546 : G_LOCK_UNLESS_NOLOCK (*src_info);
1143 :
1144 6546 : if (gst_tensors_info_validate (&src_info->info)) {
1145 6546 : dest_info->is_extended = src_info->is_extended;
1146 6546 : gst_tensors_info_copy (&dest_info->info, &src_info->info);
1147 : } else {
1148 0 : _ml_error_report
1149 : ("The parameter, src, is a ml_tensors_info_h handle without valid data. Every tensor-info of tensors-info should have a valid type and dimension information and the number of tensors should be between 1 and %d.",
1150 : ML_TENSOR_SIZE_LIMIT);
1151 0 : status = ML_ERROR_INVALID_PARAMETER;
1152 : }
1153 :
1154 6546 : G_UNLOCK_UNLESS_NOLOCK (*src_info);
1155 6546 : G_UNLOCK_UNLESS_NOLOCK (*dest_info);
1156 :
1157 6546 : return status;
1158 : }
1159 :
1160 : /**
1161 : * @brief Replaces string.
1162 : * This function deallocates the input source string.
1163 : * This is copied from nnstreamer/tensor_common.c by the nnstreamer maintainer.
1164 : * @param[in] source The input string. This will be freed when returning the replaced string.
1165 : * @param[in] what The string to search for.
1166 : * @param[in] to The string to be replaced.
1167 : * @param[in] delimiters The characters which specify the place to split the string. Set NULL to replace all matched string.
1168 : * @param[out] count The count of replaced. Set NULL if it is unnecessary.
1169 : * @return Newly allocated string. The returned string should be freed with g_free().
1170 : */
1171 : gchar *
1172 15 : _ml_replace_string (gchar * source, const gchar * what, const gchar * to,
1173 : const gchar * delimiters, guint * count)
1174 : {
1175 : GString *builder;
1176 : gchar *start, *pos, *result;
1177 15 : guint changed = 0;
1178 : gsize len;
1179 :
1180 15 : g_return_val_if_fail (source, NULL);
1181 15 : g_return_val_if_fail (what && to, source);
1182 :
1183 15 : len = strlen (what);
1184 15 : start = source;
1185 :
1186 15 : builder = g_string_new (NULL);
1187 57 : while ((pos = g_strstr_len (start, -1, what)) != NULL) {
1188 42 : gboolean skip = FALSE;
1189 :
1190 42 : if (delimiters) {
1191 : const gchar *s;
1192 : gchar *prev, *next;
1193 : gboolean prev_split, next_split;
1194 :
1195 22 : prev = next = NULL;
1196 22 : prev_split = next_split = FALSE;
1197 :
1198 22 : if (pos != source)
1199 18 : prev = pos - 1;
1200 22 : if (*(pos + len) != '\0')
1201 19 : next = pos + len;
1202 :
1203 46 : for (s = delimiters; *s != '\0'; ++s) {
1204 34 : if (!prev || *s == *prev)
1205 16 : prev_split = TRUE;
1206 34 : if (!next || *s == *next)
1207 15 : next_split = TRUE;
1208 34 : if (prev_split && next_split)
1209 10 : break;
1210 : }
1211 :
1212 22 : if (!prev_split || !next_split)
1213 12 : skip = TRUE;
1214 : }
1215 :
1216 42 : builder = g_string_append_len (builder, start, pos - start);
1217 :
1218 : /* replace string if found */
1219 42 : if (skip)
1220 24 : builder = g_string_append_len (builder, pos, len);
1221 : else
1222 30 : builder = g_string_append (builder, to);
1223 :
1224 42 : start = pos + len;
1225 42 : if (!skip)
1226 30 : changed++;
1227 : }
1228 :
1229 : /* append remains */
1230 15 : builder = g_string_append (builder, start);
1231 15 : result = g_string_free (builder, FALSE);
1232 :
1233 15 : if (count)
1234 9 : *count = changed;
1235 :
1236 15 : g_free (source);
1237 15 : return result;
1238 : }
1239 :
1240 : /**
1241 : * @brief Converts predefined entity.
1242 : */
1243 : gchar *
1244 343 : _ml_convert_predefined_entity (const gchar * str)
1245 : {
1246 343 : gchar *converted = g_strdup (str);
1247 :
1248 : #if defined(__ANDROID__)
1249 : {
1250 : extern const char *nnstreamer_native_get_data_path (void);
1251 :
1252 : const char *data_path = nnstreamer_native_get_data_path ();
1253 :
1254 : converted = _ml_replace_string (converted, "@APP_DATA_PATH@", data_path,
1255 : NULL, NULL);
1256 : }
1257 : #endif
1258 :
1259 343 : return converted;
1260 : }
1261 :
1262 : /**
1263 : * @brief error reporting infra
1264 : */
1265 : #define _ML_ERRORMSG_LENGTH (4096U)
1266 : static char errormsg[_ML_ERRORMSG_LENGTH] = { 0 }; /* one page limit */
1267 :
1268 : static int reported = 0;
1269 : G_LOCK_DEFINE_STATIC (errlock);
1270 :
1271 : /**
1272 : * @brief public API function of error reporting.
1273 : */
1274 : const char *
1275 0 : ml_error (void)
1276 : {
1277 0 : G_LOCK (errlock);
1278 0 : if (reported != 0) {
1279 0 : errormsg[0] = '\0';
1280 0 : reported = 0;
1281 : }
1282 0 : if (errormsg[0] == '\0') {
1283 0 : G_UNLOCK (errlock);
1284 0 : return NULL;
1285 : }
1286 :
1287 0 : reported = 1;
1288 :
1289 0 : G_UNLOCK (errlock);
1290 0 : return errormsg;
1291 : }
1292 :
1293 : /**
1294 : * @brief Internal interface to write messages for ml_error()
1295 : */
1296 : void
1297 940 : _ml_error_report_ (const char *fmt, ...)
1298 : {
1299 : int n;
1300 : va_list arg_ptr;
1301 940 : G_LOCK (errlock);
1302 :
1303 940 : va_start (arg_ptr, fmt);
1304 940 : n = vsnprintf (errormsg, _ML_ERRORMSG_LENGTH, fmt, arg_ptr);
1305 940 : va_end (arg_ptr);
1306 :
1307 940 : if (n > _ML_ERRORMSG_LENGTH) {
1308 0 : errormsg[_ML_ERRORMSG_LENGTH - 2] = '.';
1309 0 : errormsg[_ML_ERRORMSG_LENGTH - 3] = '.';
1310 0 : errormsg[_ML_ERRORMSG_LENGTH - 4] = '.';
1311 : }
1312 :
1313 940 : _ml_loge ("%s", errormsg);
1314 :
1315 940 : reported = 0;
1316 :
1317 940 : G_UNLOCK (errlock);
1318 940 : }
1319 :
1320 : /**
1321 : * @brief Internal interface to write messages for ml_error(), relaying previously reported errors.
1322 : */
1323 : void
1324 44 : _ml_error_report_continue_ (const char *fmt, ...)
1325 : {
1326 44 : size_t cursor = 0;
1327 : va_list arg_ptr;
1328 : char buf[_ML_ERRORMSG_LENGTH];
1329 44 : G_LOCK (errlock);
1330 :
1331 : /* Check if there is a message to relay */
1332 44 : if (reported == 0) {
1333 44 : cursor = strlen (errormsg);
1334 44 : if (cursor < (_ML_ERRORMSG_LENGTH - 1)) {
1335 44 : errormsg[cursor] = '\n';
1336 44 : errormsg[cursor + 1] = '\0';
1337 44 : cursor++;
1338 : }
1339 : } else {
1340 0 : errormsg[0] = '\0';
1341 : }
1342 :
1343 44 : va_start (arg_ptr, fmt);
1344 44 : vsnprintf (buf, _ML_ERRORMSG_LENGTH - 1, fmt, arg_ptr);
1345 44 : _ml_loge ("%s", buf);
1346 :
1347 44 : memcpy (errormsg + cursor, buf, _ML_ERRORMSG_LENGTH - strlen (errormsg) - 1);
1348 44 : if (strlen (errormsg) >= (_ML_ERRORMSG_LENGTH - 2)) {
1349 0 : errormsg[_ML_ERRORMSG_LENGTH - 2] = '.';
1350 0 : errormsg[_ML_ERRORMSG_LENGTH - 3] = '.';
1351 0 : errormsg[_ML_ERRORMSG_LENGTH - 4] = '.';
1352 : }
1353 :
1354 44 : va_end (arg_ptr);
1355 :
1356 44 : errormsg[_ML_ERRORMSG_LENGTH - 1] = '\0';
1357 44 : reported = 0;
1358 44 : G_UNLOCK (errlock);
1359 44 : }
1360 :
1361 : static const char *strerrors[] = {
1362 : [0] = "Not an error",
1363 : [EINVAL] =
1364 : "Invalid parameters are given to a function. Check parameter values. (EINVAL)",
1365 : };
1366 :
1367 : /**
1368 : * @brief public API function of error code descriptions
1369 : */
1370 : const char *
1371 0 : ml_strerror (int errnum)
1372 : {
1373 0 : int size = sizeof (strerrors) / sizeof (strerrors[0]);
1374 :
1375 0 : if (errnum < 0)
1376 0 : errnum = errnum * -1;
1377 :
1378 0 : if (errnum == 0 || errnum >= size)
1379 0 : return NULL;
1380 0 : return strerrors[errnum];
1381 : }
1382 :
1383 : /**
1384 : * @brief Internal function to check the handle is valid.
1385 : */
1386 : static bool
1387 1423 : _ml_info_is_valid (gpointer handle, ml_info_type_e expected)
1388 : {
1389 : ml_info_type_e current;
1390 :
1391 1423 : if (!handle)
1392 6 : return false;
1393 :
1394 : /* The first field should be an enum value of ml_info_type_e. */
1395 1417 : current = *((ml_info_type_e *) handle);
1396 1417 : if (current != expected)
1397 14 : return false;
1398 :
1399 1403 : switch (current) {
1400 1382 : case ML_INFO_TYPE_OPTION:
1401 : case ML_INFO_TYPE_INFORMATION:
1402 : {
1403 1382 : ml_info_s *_info = (ml_info_s *) handle;
1404 :
1405 1382 : if (!_info->table)
1406 0 : return false;
1407 :
1408 1382 : break;
1409 : }
1410 21 : case ML_INFO_TYPE_INFORMATION_LIST:
1411 21 : break;
1412 0 : default:
1413 : /* Unknown type */
1414 0 : return false;
1415 : }
1416 :
1417 1403 : return true;
1418 : }
1419 :
1420 : /**
1421 : * @brief Internal function for destroy value of option table
1422 : */
1423 : static void
1424 408 : _ml_info_value_free (gpointer data)
1425 : {
1426 : ml_info_value_s *_value;
1427 :
1428 408 : _value = (ml_info_value_s *) data;
1429 408 : if (_value) {
1430 408 : if (_value->destroy)
1431 345 : _value->destroy (_value->value);
1432 408 : g_free (_value);
1433 : }
1434 408 : }
1435 :
1436 : /**
1437 : * @brief Internal function for create ml_info
1438 : */
1439 : static ml_info_s *
1440 248 : _ml_info_create (ml_info_type_e type)
1441 : {
1442 : ml_info_s *info;
1443 :
1444 248 : info = g_new0 (ml_info_s, 1);
1445 248 : if (info == NULL) {
1446 0 : _ml_error_report
1447 : ("Failed to allocate memory for the ml_info. Out of memory?");
1448 0 : return NULL;
1449 : }
1450 :
1451 248 : info->type = type;
1452 248 : info->table =
1453 248 : g_hash_table_new_full (g_str_hash, g_str_equal, g_free,
1454 : _ml_info_value_free);
1455 248 : if (info->table == NULL) {
1456 0 : _ml_error_report
1457 : ("Failed to allocate memory for the table of ml_info. Out of memory?");
1458 0 : g_free (info);
1459 0 : return NULL;
1460 : }
1461 :
1462 248 : return info;
1463 : }
1464 :
1465 : /**
1466 : * @brief Internal function for destroy ml_info
1467 : */
1468 : static void
1469 244 : _ml_info_destroy (gpointer data)
1470 : {
1471 244 : ml_info_s *info = (ml_info_s *) data;
1472 :
1473 244 : if (!info)
1474 0 : return;
1475 :
1476 244 : info->type = ML_INFO_TYPE_UNKNOWN;
1477 :
1478 244 : if (info->table) {
1479 244 : g_hash_table_destroy (info->table);
1480 244 : info->table = NULL;
1481 : }
1482 :
1483 244 : g_free (info);
1484 244 : return;
1485 : }
1486 :
1487 : /**
1488 : * @brief Internal function for set value of given ml_info
1489 : */
1490 : static int
1491 413 : _ml_info_set_value (ml_info_s * info, const char *key, void *value,
1492 : ml_data_destroy_cb destroy)
1493 : {
1494 : ml_info_value_s *info_value;
1495 :
1496 413 : if (!STR_IS_VALID (key))
1497 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1498 : "The parameter, 'key' is invalid. It should be a valid string.");
1499 :
1500 412 : if (!info || !value)
1501 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1502 : "The parameter, 'info' or 'value' is NULL. It should be a valid ml_info and value.");
1503 :
1504 412 : info_value = g_new0 (ml_info_value_s, 1);
1505 412 : if (!info_value)
1506 0 : _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
1507 : "Failed to allocate memory for the info value. Out of memory?");
1508 :
1509 412 : info_value->value = value;
1510 412 : info_value->destroy = destroy;
1511 412 : g_hash_table_insert (info->table, g_strdup (key), (gpointer) info_value);
1512 :
1513 412 : return ML_ERROR_NONE;
1514 : }
1515 :
1516 : /**
1517 : * @brief Internal function for get value of given ml_info
1518 : */
1519 : static int
1520 725 : _ml_info_get_value (ml_info_s * info, const char *key, void **value)
1521 : {
1522 : ml_info_value_s *info_value;
1523 :
1524 725 : if (!info || !key || !value)
1525 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1526 : "The parameter, 'info', 'key' or 'value' is NULL. It should be a valid ml_info, key and value.");
1527 :
1528 725 : info_value = g_hash_table_lookup (info->table, key);
1529 725 : if (!info_value) {
1530 386 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1531 : "Failed to find a value of key '%s', invalid key string?", key);
1532 : }
1533 :
1534 339 : *value = info_value->value;
1535 :
1536 339 : return ML_ERROR_NONE;
1537 : }
1538 :
1539 : /**
1540 : * @brief Creates an option and returns the instance a handle.
1541 : */
1542 : int
1543 194 : ml_option_create (ml_option_h * option)
1544 : {
1545 194 : ml_info_s *_option = NULL;
1546 :
1547 194 : check_feature_state (ML_FEATURE);
1548 :
1549 194 : if (!option) {
1550 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1551 : "The parameter, 'option' is NULL. It should be a valid ml_option_h");
1552 : }
1553 :
1554 193 : _option = _ml_info_create (ML_INFO_TYPE_OPTION);
1555 193 : if (_option == NULL)
1556 0 : _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
1557 : "Failed to allocate memory for the option handle. Out of memory?");
1558 :
1559 193 : *option = _option;
1560 193 : return ML_ERROR_NONE;
1561 : }
1562 :
1563 : /**
1564 : * @brief Frees the given handle of a ml_option.
1565 : */
1566 : int
1567 191 : ml_option_destroy (ml_option_h option)
1568 : {
1569 191 : check_feature_state (ML_FEATURE);
1570 :
1571 191 : if (!option) {
1572 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1573 : "The parameter, 'option' is NULL. It should be a valid ml_option_h, which should be created by ml_option_create().");
1574 : }
1575 :
1576 190 : if (!_ml_info_is_valid (option, ML_INFO_TYPE_OPTION))
1577 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1578 : "The parameter, 'option' is not a ml-option handle.");
1579 :
1580 189 : _ml_info_destroy (option);
1581 :
1582 189 : return ML_ERROR_NONE;
1583 : }
1584 :
1585 : /**
1586 : * @brief Set key-value pair in given option handle. Note that if duplicated key is given, the value is updated with the new one.
1587 : * If some options are changed or there are newly added options, please modify below description.
1588 : * The list of valid key-values are:
1589 : *
1590 : * key (char *) || value (expected type (pointer))
1591 : * ---------------------------------------------------------
1592 : * "framework_name" || explicit name of framework (char *)
1593 : * ...
1594 : */
1595 : int
1596 320 : ml_option_set (ml_option_h option, const char *key, void *value,
1597 : ml_data_destroy_cb destroy)
1598 : {
1599 320 : check_feature_state (ML_FEATURE);
1600 :
1601 320 : if (!option) {
1602 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1603 : "The parameter, 'option' is NULL. It should be a valid ml_option_h, which should be created by ml_option_create().");
1604 : }
1605 :
1606 319 : if (!key) {
1607 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1608 : "The parameter, 'key' is NULL. It should be a valid const char*");
1609 : }
1610 :
1611 318 : if (!value) {
1612 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1613 : "The parameter, 'value' is NULL. It should be a valid void*");
1614 : }
1615 :
1616 317 : if (!_ml_info_is_valid (option, ML_INFO_TYPE_OPTION))
1617 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1618 : "The parameter, 'option' is not a ml-option handle.");
1619 :
1620 316 : return _ml_info_set_value ((ml_info_s *) option, key, value, destroy);
1621 : }
1622 :
1623 : /**
1624 : * @brief Gets a value of key in ml_option instance.
1625 : */
1626 : int
1627 662 : ml_option_get (ml_option_h option, const char *key, void **value)
1628 : {
1629 662 : check_feature_state (ML_FEATURE);
1630 :
1631 662 : if (!option) {
1632 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1633 : "The parameter, 'option' is NULL. It should be a valid ml_option_h, which should be created by ml_option_create().");
1634 : }
1635 :
1636 661 : if (!key) {
1637 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1638 : "The parameter, 'key' is NULL. It should be a valid const char*");
1639 : }
1640 :
1641 660 : if (!value) {
1642 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1643 : "The parameter, 'value' is NULL. It should be a valid void**");
1644 : }
1645 :
1646 659 : if (!_ml_info_is_valid (option, ML_INFO_TYPE_OPTION))
1647 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1648 : "The parameter, 'option' is not a ml-option handle.");
1649 :
1650 658 : return _ml_info_get_value ((ml_info_s *) option, key, value);
1651 : }
1652 :
1653 : /**
1654 : * @brief Creates an ml_information instance and returns the handle.
1655 : */
1656 : int
1657 55 : _ml_information_create (ml_information_h * info)
1658 : {
1659 55 : ml_info_s *_info = NULL;
1660 :
1661 55 : check_feature_state (ML_FEATURE);
1662 :
1663 55 : if (!info) {
1664 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1665 : "The parameter, 'info' is NULL. It should be a valid ml_information_h");
1666 : }
1667 :
1668 55 : _info = _ml_info_create (ML_INFO_TYPE_INFORMATION);
1669 55 : if (!_info)
1670 0 : _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
1671 : "Failed to allocate memory for the info handle. Out of memory?");
1672 :
1673 55 : *info = _info;
1674 55 : return ML_ERROR_NONE;
1675 : }
1676 :
1677 : /**
1678 : * @brief Set key-value pair in given information handle.
1679 : * @note If duplicated key is given, the value is updated with the new one.
1680 : */
1681 : int
1682 98 : _ml_information_set (ml_information_h information, const char *key, void *value,
1683 : ml_data_destroy_cb destroy)
1684 : {
1685 98 : check_feature_state (ML_FEATURE);
1686 :
1687 98 : if (!information) {
1688 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1689 : "The parameter, 'information' is NULL. It should be a valid ml_information_h, which should be created by ml_information_create().");
1690 : }
1691 :
1692 98 : if (!key) {
1693 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1694 : "The parameter, 'key' is NULL. It should be a valid const char*");
1695 : }
1696 :
1697 98 : if (!value) {
1698 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1699 : "The parameter, 'value' is NULL. It should be a valid void*");
1700 : }
1701 :
1702 98 : if (!_ml_info_is_valid (information, ML_INFO_TYPE_INFORMATION))
1703 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1704 : "The parameter, 'information' is not a ml-information handle.");
1705 :
1706 97 : return _ml_info_set_value ((ml_info_s *) information, key, value, destroy);
1707 : }
1708 :
1709 : /**
1710 : * @brief Frees the given handle of a ml_information.
1711 : */
1712 : int
1713 51 : ml_information_destroy (ml_information_h information)
1714 : {
1715 51 : check_feature_state (ML_FEATURE);
1716 :
1717 51 : if (!information) {
1718 0 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1719 : "The parameter, 'information' is NULL. It should be a valid ml_information_h, which should be created by ml_information_create().");
1720 : }
1721 :
1722 51 : if (!_ml_info_is_valid (information, ML_INFO_TYPE_INFORMATION))
1723 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1724 : "The parameter, 'information' is not a ml-information handle.");
1725 :
1726 50 : _ml_info_destroy (information);
1727 :
1728 50 : return ML_ERROR_NONE;
1729 : }
1730 :
1731 : /**
1732 : * @brief Gets the value corresponding to the given key in ml_information instance.
1733 : */
1734 : int
1735 71 : ml_information_get (ml_information_h information, const char *key, void **value)
1736 : {
1737 71 : check_feature_state (ML_FEATURE);
1738 :
1739 71 : if (!information) {
1740 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1741 : "The parameter, 'information' is NULL. It should be a valid ml_information_h, which should be created by ml_information_create().");
1742 : }
1743 :
1744 70 : if (!key) {
1745 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1746 : "The parameter, 'key' is NULL. It should be a valid const char*");
1747 : }
1748 :
1749 69 : if (!value) {
1750 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1751 : "The parameter, 'value' is NULL. It should be a valid void**");
1752 : }
1753 :
1754 68 : if (!_ml_info_is_valid (information, ML_INFO_TYPE_INFORMATION))
1755 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1756 : "The parameter, 'information' is not a ml-information handle.");
1757 :
1758 67 : return _ml_info_get_value ((ml_info_s *) information, key, value);
1759 : }
1760 :
1761 : /**
1762 : * @brief Creates an ml-information-list instance and returns the handle.
1763 : */
1764 : int
1765 5 : _ml_information_list_create (ml_information_list_h * list)
1766 : {
1767 : ml_info_list_s *_info_list;
1768 :
1769 5 : check_feature_state (ML_FEATURE);
1770 :
1771 5 : if (!list)
1772 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1773 : "The parameter, 'list' is NULL. It should be a valid ml_information_list_h.");
1774 :
1775 4 : _info_list = g_try_new0 (ml_info_list_s, 1);
1776 4 : if (!_info_list) {
1777 0 : _ml_error_report_return (ML_ERROR_OUT_OF_MEMORY,
1778 : "Failed to allocate memory for ml_information_list_h. Out of memory?");
1779 : }
1780 :
1781 4 : _info_list->type = ML_INFO_TYPE_INFORMATION_LIST;
1782 :
1783 4 : *list = _info_list;
1784 4 : return ML_ERROR_NONE;
1785 : }
1786 :
1787 : /**
1788 : * @brief Adds an ml-information into ml-information-list.
1789 : */
1790 : int
1791 7 : _ml_information_list_add (ml_information_list_h list, ml_information_h info)
1792 : {
1793 : ml_info_list_s *_info_list;
1794 :
1795 7 : check_feature_state (ML_FEATURE);
1796 :
1797 7 : if (!_ml_info_is_valid (list, ML_INFO_TYPE_INFORMATION_LIST)) {
1798 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1799 : "The parameter, 'list' is invalid. It should be a valid ml_information_list_h, which should be created by ml_information_list_create().");
1800 : }
1801 :
1802 6 : if (!_ml_info_is_valid (info, ML_INFO_TYPE_OPTION) &&
1803 6 : !_ml_info_is_valid (info, ML_INFO_TYPE_INFORMATION)) {
1804 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1805 : "The parameter, 'info' is invalid. It should be a valid ml_information_h, which should be created by ml_information_create().");
1806 : }
1807 :
1808 5 : _info_list = (ml_info_list_s *) list;
1809 5 : _info_list->info = g_slist_append (_info_list->info, info);
1810 :
1811 5 : return ML_ERROR_NONE;
1812 : }
1813 :
1814 : /**
1815 : * @brief Destroys the ml-information-list instance.
1816 : */
1817 : int
1818 6 : ml_information_list_destroy (ml_information_list_h list)
1819 : {
1820 : ml_info_list_s *_info_list;
1821 :
1822 6 : check_feature_state (ML_FEATURE);
1823 :
1824 6 : if (!_ml_info_is_valid (list, ML_INFO_TYPE_INFORMATION_LIST)) {
1825 2 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1826 : "The parameter, 'list' is invalid. It should be a valid ml_information_list_h, which should be created by ml_information_list_create().");
1827 : }
1828 :
1829 4 : _info_list = (ml_info_list_s *) list;
1830 4 : g_slist_free_full (_info_list->info, _ml_info_destroy);
1831 4 : g_free (_info_list);
1832 :
1833 4 : return ML_ERROR_NONE;
1834 : }
1835 :
1836 : /**
1837 : * @brief Gets the number of ml-information in ml-information-list instance.
1838 : */
1839 : int
1840 6 : ml_information_list_length (ml_information_list_h list, unsigned int *length)
1841 : {
1842 : ml_info_list_s *_info_list;
1843 :
1844 6 : check_feature_state (ML_FEATURE);
1845 :
1846 6 : if (!_ml_info_is_valid (list, ML_INFO_TYPE_INFORMATION_LIST)) {
1847 2 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1848 : "The parameter, 'list' is invalid. It should be a valid ml_information_list_h, which should be created by ml_information_list_create().");
1849 : }
1850 :
1851 4 : if (!length) {
1852 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1853 : "The parameter, 'length' is NULL. It should be a valid unsigned int*");
1854 : }
1855 :
1856 3 : _info_list = (ml_info_list_s *) list;
1857 3 : *length = g_slist_length (_info_list->info);
1858 :
1859 3 : return ML_ERROR_NONE;
1860 : }
1861 :
1862 : /**
1863 : * @brief Gets a ml-information in ml-information-list instance with given index.
1864 : */
1865 : int
1866 9 : ml_information_list_get (ml_information_list_h list, unsigned int index,
1867 : ml_information_h * information)
1868 : {
1869 : ml_info_list_s *_info_list;
1870 :
1871 9 : check_feature_state (ML_FEATURE);
1872 :
1873 9 : if (!_ml_info_is_valid (list, ML_INFO_TYPE_INFORMATION_LIST)) {
1874 2 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1875 : "The parameter, 'list' is NULL. It should be a valid ml_information_list_h, which should be created by ml_information_list_create().");
1876 : }
1877 :
1878 7 : if (!information) {
1879 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1880 : "The parameter, 'information' is NULL. It should be a valid ml_information_h*");
1881 : }
1882 :
1883 6 : _info_list = (ml_info_list_s *) list;
1884 6 : *information = g_slist_nth_data (_info_list->info, index);
1885 :
1886 6 : if (*information == NULL) {
1887 1 : _ml_error_report_return (ML_ERROR_INVALID_PARAMETER,
1888 : "The parameter, 'index' is invalid. It should be less than the length of ml_information_list_h.");
1889 : }
1890 :
1891 5 : return ML_ERROR_NONE;
1892 : }
|