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