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